Estou resolvendo o sistema de reação-difusão de Turing com o seguinte código C ++. É muito lento: para a textura de 128x128 pixels, o número aceitável de iterações é 200 - o que resulta em 2,5 segundos de atraso. Preciso de 400 iterações para obter uma imagem interessante - mas 5 segundos de espera são demais. Além disso, o tamanho da textura deve ser de 512x512 - mas isso resulta em um grande tempo de espera. Os dispositivos são iPad, iPod.
Existe alguma chance de fazer isso mais rápido? O método de Euler converge lentamente (wikipedia) - ter um método mais rápido permitiria eliminar o número de iterações?
Edição: Como Thomas Klimpel apontou, as linhas: "if (m_An [i] [j] <0.0) {...}", "if (m_Bn [i] [j] <0.0) {...}" estão atrasando a convergência: após a remoção, uma imagem significativa aparece após 75 iterações . Eu comentei as linhas no código abaixo.
void TuringSystem::solve( int iterations, double CA, double CB ) {
m_iterations = iterations;
m_CA = CA;
m_CB = CB;
solveProcess();
}
void set_torus( int & x_plus1, int & x_minus1, int x, int size ) {
// Wrap "edges"
x_plus1 = x+1;
x_minus1 = x-1;
if( x == size - 1 ) { x_plus1 = 0; }
if( x == 0 ) { x_minus1 = size - 1; }
}
void TuringSystem::solveProcess() {
int n, i, j, i_add1, i_sub1, j_add1, j_sub1;
double DiA, ReA, DiB, ReB;
// uses Euler's method to solve the diff eqns
for( n=0; n < m_iterations; ++n ) {
for( i=0; i < m_height; ++i ) {
set_torus(i_add1, i_sub1, i, m_height);
for( j=0; j < m_width; ++j ) {
set_torus(j_add1, j_sub1, j, m_width);
// Component A
DiA = m_CA * ( m_Ao[i_add1][j] - 2.0 * m_Ao[i][j] + m_Ao[i_sub1][j] + m_Ao[i][j_add1] - 2.0 * m_Ao[i][j] + m_Ao[i][j_sub1] );
ReA = m_Ao[i][j] * m_Bo[i][j] - m_Ao[i][j] - 12.0;
m_An[i][j] = m_Ao[i][j] + 0.01 * (ReA + DiA);
// if( m_An[i][j] < 0.0 ) { m_An[i][j] = 0.0; }
// Component B
DiB = m_CB * ( m_Bo[i_add1][j] - 2.0 * m_Bo[i][j] + m_Bo[i_sub1][j] + m_Bo[i][j_add1] - 2.0 * m_Bo[i][j] + m_Bo[i][j_sub1] );
ReB = 16.0 - m_Ao[i][j] * m_Bo[i][j];
m_Bn[i][j] = m_Bo[i][j] + 0.01 * (ReB + DiB);
// if( m_Bn[i][j] < 0.0 ) { m_Bn[i][j]=0.0; }
}
}
// Swap Ao for An, Bo for Bn
swapBuffers();
}
}
Respostas:
Você parece estar limitado pela estabilidade, o que é esperado, já que a difusão é rígida à medida que você refina a grade. Bons métodos para sistemas rígidos são pelo menos parcialmente implícitos. Isso exigirá algum esforço, mas você pode implementar um algoritmo multigrid simples (ou usar uma biblioteca) para resolver esse sistema com um custo inferior a dez "unidades de trabalho" (essencialmente o custo de uma de suas etapas de tempo). Quando você refina a grade, o número de iterações não aumenta.
fonte
Do ponto de vista prático: o processador A5 não é tão poderoso, então você pode esperar algumas iterações de HW ou, se o seu ipod / ipad for conectado à Internet, resolver seu problema remotamente ou na nuvem.
fonte
Euler converge lentamente em relação a outros métodos, no entanto, acho que não é isso que você está interessado. Se você está apenas procurando imagens "interessantes", aumente o tamanho do seu passo de tempo e faça menos iterações. O problema, como Jed aponta, é que o método euler explícito apresenta problemas de estabilidade com grandes etapas de tempo em relação ao tamanho da grade. quanto menor for sua grade (ou seja, quanto maior a resolução da sua imagem), menor será o tempo necessário para explicá-la.
Por exemplo, usando o euler implícito em vez do explícito, você não obtém nenhuma ordem de convergência, mas a solução terá estabilidade incondicional, permitindo etapas de tempo muito maiores. Os métodos implícitos são mais complicados de implementar e exigem mais computação por etapa de tempo, mas você deve ver ganhos muito além disso executando menos etapas no total.
fonte