5

primer problemaDos problemas de eficiencia extraños en Mathematica

he cronometrado el tiempo que toma para calcular las siguientes declaraciones (donde V [X] es una llamada a una función que requiere mucho tiempo):

Alice  = Table[V[i],{i,1,300},{1000}]; 
Bob  = Table[Table[V[i],{i,1,300}],{1000}]^tr; 
Chris_pre = Table[V[i],{i,1,300}]; 
Chris  = Table[Chris_pre,{1000}]^tr; 

de Alice , Bob y Chris son matrices idénticas calculadas de 3 maneras ligeramente diferentes. Encuentro que Chris se computa 1000 veces más rápido que Alice y Bob.

No es sorprendente que Alice se calcule 1000 veces más lento porque, ingenuamente, la función V debe llamarse 1000 veces más que cuando se calcula Chris. Pero es muy sorprendente que Bob sea tan lento, ya que se calcula idénticamente a Chris, excepto que Chris almacena el paso intermedio Chris_pre.

¿Por qué Bob evalúa tan lentamente?


SEGUNDO PROBLEMA

Supongamos que quiero para compilar una función en Mathematica de la forma

f(x)=x+y 

donde "y" es una constante fija en tiempo de compilación (pero que no preferir reemplazar directamente en el código con su numérico porque quiero poder cambiarlo fácilmente). Si y de valor real es y = 7,3, y definir

f1=Compile[{x},x+y] 
f2=Compile[{x},x+7.3] 

entonces f1 corre 50% más lento que f2. ¿Cómo hago que Mathematica reemplace "y" con "7.3" cuando se compila f1, de modo que f1 se ejecuta tan rápido como f2?


EDIT:

encontré una solución fea para el segundo problema:

f1=ReleaseHold[Hold[Compile[{x},x+z]]/.{z->y}] 

Tiene que haber una mejor manera ...

Respuesta

5

Probablemente debería haber publicado estos como preguntas separadas, ¡pero sin preocupaciones!

Problema uno

El problema con Alice es por supuesto lo que usted espera. El problema con Bob es que el Table interno se evalúa una vez por iteración del Table externo. Esto es claramente visible con Trace:

Trace[Table[Table[i, {i, 1, 3}], {3}]] 

{ 
Table[Table[i,{i,1,2}],{2}], 
{Table[i,{i,1,2}],{i,1},{i,2},{1,2}},{Table[i,{i,1,2}],{i,1},{i,2},{1,2}}, 
{{1,2},{1,2}} 
} 

saltos de línea se añaden para dar énfasis, y sí, la salida del Rastro en la tabla es un poco raro, pero puede verlo. Claramente, Mathematica podría optimizar esto mejor, sabiendo que la tabla externa no tiene iterador, pero por cualquier razón, no tiene eso en cuenta. Sólo Chris hace lo que quiere, aunque se puede modificar Bob:

Transpose[Table[Evaluate[Table[V[i],{i,1,300}]],{1000}]] 

Esto parece que en realidad supera a Chris por un factor de dos o así, ya que no tiene que almacenar el resultado intermedio.

Problema dos

Hay una solución más simple con Evaluar, aunque espero que no funcionará con todas las funciones posibles para ser compilado (es decir, los que realmente deben celebrarse):

f1 = Compile[{x}, Evaluate[x + y]]; 

Usted también podría utilizar un With:

With[{y=7.3}, 
    f1 = Compile[{x}, x + y]; 
] 

O si Y se define en otro lugar, utilizar un temporal:

y = 7.3; 
With[{z = y}, 
    f1 = Compile[{x}, x + z]; 
] 

No soy un experto en los mecanismos de evaluación y evaluación de Mathematica, por lo que podría haber una manera mucho mejor, pero espero que uno de ellos lo haga por usted.

+0

¡Guau, muchas gracias! Esto es exactamente lo que estaba buscando. (Y me aseguraré de publicar problemas como este por separado en el futuro.) –

+0

Usar 'With' es probablemente la forma más segura de abordar el problema dos, ya que hace una verdadera sustitución léxica antes de cualquier evaluación de su cuerpo. –

+0

@Michael Pilat: De acuerdo. Sugerí la evaluación en el espíritu de un enfoque rápido y sucio si ya has definido 'y', pero la variable adicional temporal es definitivamente más segura. – Cascabel

1

Primer problema ¿Ha comprobado el resultado del cálculo de Chris_pre? Descubrirá que no es una matriz grande en absoluto, ya que está tratando de almacenar un resultado intermedio en un patrón, en lugar de una Variable. Prueba ChrisPre, en cambio. Entonces todos los tiempos son comparables.

Segundo problema Compile tiene una serie de restricciones complicadas para su uso. Un problema es que no puede referirse a variables globales. El constructo "Con" que ya fue sugerido es el camino sugerido para esto. Si desea obtener más información sobre Compilar, echa un vistazo a los trucos de Ted Érsek: http://www.verbeia.com/mathematica/tips/Tricks.html

+0

Vaya. En mi código actual, utilicé Chris1, que es un nombre de variable aceptable. Olvidé al escribir esto que los guiones bajos no se pueden usar para las variables en Mathematica. Muchas gracias por el enlace. Esto se ve como algo bueno. –

2

Su primer problema ya se ha explicado, pero quiero señalar que ConstantArray se introdujo en Mathematica 6 para abordar esta cuestión. Antes de ese momento, se usó Table[expr, {50}] para expresiones fijas y variables.

Desde la introducción de ConstantArray hay una clara separación entre la iteración con reevaluación y la simple duplicación de una expresión. Se puede ver el comportamiento utilizando la siguiente:

ConstantArray[Table[Pause[1]; i, {i, 5}], {50}] ~Monitor~ i 

Se tarda cinco segundos en lazo Table debido Pause[1], pero después de que se haya completado bucle no se vuelve a evaluar y las 50 copias se imprimen inmediatamente.

Cuestiones relacionadas