[R-br] Criação de função fortran em pacote (base)

Benilton Carvalho beniltoncarvalho em gmail.com
Terça Fevereiro 28 12:46:18 BRT 2012


Pegue uma xicara de Nescau ou um bule de cha' de paciencia (pq o email
ficou longo) e so' passe para a linha seguinte apenas depois de ter
compreendido a linha atual.

Tente o seguinte:

f = function(i){
   message("Calculo com i=", i)
   2^i
}

E execute-a no R:

> f(1)
Calculo com i=1
[1] 2
> f(2)
Calculo com i=2
[1] 4
> f(3)
Calculo com i=3
[1] 8

Entao, retornando `as definicoes de logica de programacao la' do
comeco do curso, a funcao f() e' um conjunto de 2 instrucoes. A
primeira instrucao eh escrever na tela a mensagem "Calculo com
i=<valor>". A segunda instrucao e' determinar 2^i.

Tudo certo ate' aqui?

Agora, para economizar um pouco o seu tempo, vc nao precisa digitar
f(1), f(2),f(3). Voce pode usar lapply() para automatizar um pouco.

resultado0 <- lapply(1:3, f)

que vai retornar o seguinte:

> resultado0 <- lapply(1:3, f)
Calculo com i=1
Calculo com i=2
Calculo com i=3


Pausa para pensar no que aconteceu: o lapply(), de modo bem
simplificado, criou internamente um loop indo de 1 ate' 3 e chamou a
funcao f() para esses argumentos... A traducao do lapply() nesse caso
eh:

resultado1 = vector('list', 3)
for (i in 1:3)
   resultado1[[i]] = f(i)
resultado1

Para confirmar que eu nao estou enganado, teste:

identical(resultado0, resultado1)

Ou seja, em cada passo, as duas instrucoes contidas na sua funcao f()
foram executadas. Alem disso, o resultado da **ultima** instrucao eh o
resultado que eh guardado pelo sistema.

Agora, com o multicore::mclapply(), o que acontece eh o seguinte:

library(multicore)
resultado2 = mclapply(1:3, f, mc.cores=2)

"Traduzindo" o que o mclapply faz eh o seguinte:

1) Conte quantos elementos foram passados no primeiro argumento do
mclapply()... Foram passados 1, 2, 3 ; portanto, 3 elementos;
2) Veja se foi especificado o numero de nucleos a serem usados (nesse caso 2);
3) Abra 2 novas sessoes (invisiveis para o usuario) do R (por isso que
mc.cores=2) e copie a definicao da funcao f() dentro de cada nova
sessao (note: copia a funcao *INTEIRA* nao apenas a primeira ou
segunda linha);
4) Divida 3 tarefas (executar f(1), f(2) e f(3) ) entre as 2 sessoes
disponiveis;
4.1) No meu caso, a sessao 1 ficou encarregada de executar f(1) e
f(2); ao passo que a sessao 2, ficou por executar f(3)
5) Coloque as sessoes para executar suas tarefas. Nesse momento:
5.1) Sessao 1: calcula f(1)
5.2) Sessao 2: calcula f(2)
5.3) Sessao 1: nota que ainda tem que calcular f(2), entao vai fazer isso;
5.4) Sessao 2: grita "first!" e fica esperando a sessao 1 acabar;
5.5) Sessao 1: termina;
5.6) Sessao 1 e Sessao 2: avisam para o processo central do R (que eh
o q vc tem na tela) que estao prontos pra mandar os resultados
(lembre-se, o resultado eh apenas o resultado da 2a instrucao) de
volta;
5.7) Processo Central do R: colecta os resultados das Sessoes e guarda
em resultado2

Confirme que os resultados sao identicos:

identical(resultado1, resultado2)

**OBS IMPORTANTE**: Volte no passo 5 acima... Observe que cada Sessao
tem o conhecimento inteiro da definicao da funcao f()... As sessoes
nao abrem a funcao nem desmembram seu conteudo para execucao. Cada
sessao executa a funcao f() inteira, do inicio ao fim. Portanto, cada
sessao executa, independentemente das outras sessoes, a linha
message() e tambem a linha 2^i que defini originalmente na funcao f().

Pronto, dito isso a *sua* funcao f(), vc define como:

function(i){
    g1 <- mvrnorm(n=1, mat.cokri[[1]][1:2601],m1)
    g2 <- mvrnorm(n=1, mat.cokri[[1]][1:2601],m2)
    g3 <- mvrnorm(n=1, mat.cokri[[1]][2602:5202],m3)
    g4 <- mvrnorm(n=1, mat.cokri[[1]][2602:5202],m4)
}

cada linha g1/.../g4 eh apenas uma instrucao dentro da funcao
inteira... E cada nucleo executara' a funcao completa (note que
retornarah apenas o resultado g4, por um possivel erro seu na
definicao da funcao).

Assim, ao chamar:

mclapply(1:1, SUAFUNCAO, mc.cores=4)

vc esta' dizendo para o R que quer calcular o valor de:

SUAFUNCAO(1) ## pois 1:1 eh igual a 1

Apesar de vc ter reservado 4 nucleos, apenas 1 sera usado, pq vc so'
tem 1 funcao a ser calculada... (note que eu falei *funcao* nao
*instrucao*). Esse 1 nucleo, calculara TODAS as instrucoes g1/.../g4
usando internamente i=1.

Se vc chamar:

mclapply(1:2, SUAFUNCAO, mc.cores=4)

vc esta' dizendo ao R que vc quer determinar:

SUAFUNCAO(1)
SUAFUNCAO(2)

Apesar de ter reservado 4 nucleos, ele soh precisa de 2 nucleos para
calcular... Dai' SUAFUNCAO() sera' executada em cada nucleo, usando 2
sessoes... cada sessao usara' respectiva- e internamente i=1 e i=2.
Novamente, TODAS as instrucoes serao executadas por um dado nucleo.

Se vc chamar:

mclapply(1:4, SUAFUNCAO, mc.cores=4)

vc esta' dizendo ao R que vc quer:

SUAFUNCAO(1)
SUAFUNCAO(2)
SUAFUNCAO(3)
SUAFUNCAO(4)

E como vc alocou 4 nucleos, entao todos os 4 serao usados... A mesma
estoria acima se aplica (cada nucleo executara todas as instrucoes
dentro de SUAFUNCAO, usando internamente os valores 1, 2, 3 e 4 para a
variavel i).

Pronto... terminado...

O problema maior: a sua funcao nao usa a variavel "i" internamente...
Isso quer dizer que:

SUAFUNCAO(1) e SUAFUNCAO(2) tem o mesmo valor (que eh o valor de g4).

Desse jeito, o que quer q vc faca apenas repetira a mesma tarefa
outras tantas vezes.

Para ter g1/g2/g3/g4 executadas em paralelo, vc deve idealmente
re-escrever a funcao de acordo com o que eu descrevi na minha primeira
resposta desse ciclo de mensagens. Apenas para fins ilustrativos,
mostro abaixo uma possivel solucao que deve te dar o resultado
esperado (nao posso garantir, afinal nao tenho um exemplo
reproduzivel, nao e'?):

pars = list(list(n=1, mu=mat.cokri[[1]][1:2601], Sigma=m1),
                list(n=1, mu=mat.cokri[[1]][1:2601], Sigma=m2),
                list(n=1, mu=mat.cokri[[1]][2602:5202], Sigma=m3),
                list(n=1, mu=mat.cokri[[1]][2602:5202], Sigma=m4))
f = function(thePar)
   do.call(mvrnorm, thePar)
mclapply(pars, f,mc.cores=4)

(mas, volto a repetir: faca o exercicio de implementar o que sugeri
desde o comeco)

benilton


Mais detalhes sobre a lista de discussão R-br