En Mathematica, que crear listas ligadas sencillas de este modo:"listas enlazadas" Mathematica y desempeño
toLinkedList[x_List] := Fold[pair[#2, #1] &, pair[], Reverse[x]];
fromLinkedList[ll_pair] := List @@ Flatten[ll];
emptyQ[pair[]] := True;
emptyQ[_pair] := False;
Usando el símbolo pair
de las cons cells tiene la ventaja de Flatten
trabajar con seguridad incluso si las listas contienen Mathematica- estilo List
s, y le permite definir notación personalizada usando MakeExpression
/MakeBoxes
, que hace que todo sea mucho más agradable. Para evitar tener que perder el tiempo con $IterationLimit
, escribí funciones para trabajar con estas listas usando While
bucles o NestWhile
en lugar de usar recursión. Naturalmente, yo quería ver qué enfoque sería más rápido, así que escribí dos candidatos para que pudiera ver 'em luchar:
nestLength[ll_pair] :=
With[{step = {#[[1, -1]], #[[-1]] + 1} &},
[email protected][step, {ll, 0}, ! [email protected]@# &]];
whileLength[ll_pair] :=
Module[{result = 0, current = ll},
While[! [email protected],
current = current[[2]];
++result];
result];
Los resultados fueron muy extraña. Probé las funciones en listas vinculadas de longitud 10000, y whileLength
fue generalmente un 50% más rápido, aproximadamente 0.035 segundos a nestLength
de 0.055 segundos. Sin embargo, de vez en cuando whileLength
tomaría aproximadamente ~ 4 segundos. Pensé que podría haber algún comportamiento de almacenamiento en caché, así que comencé a generar listas nuevas y aleatorias para verificar, y whileLength
no necesariamente sería lento en la primera ejecución con una nueva lista; podría tomar docenas de veces ver la desaceleración, pero luego no volvería a ocurrir (al menos no para las 200 carreras que estaba probando con cada lista).
¿Qué podría estar pasando?
Como referencia, la función que he usado para las pruebas es la siguiente:
getTimes[f_, n_] :=
With[{ll = [email protected][100, 10000]},
Table[Timing[[email protected]], {n}][[All, 1]]]
EDIT: me he olvidado de mencionar la versión anterior; Tengo estos resultados con Mathematica 8.
editar el segundo: Cuando leí Daniel Lichtblau's answer, me di cuenta de que mis tiempos de carreras "típicos" omiten una de las principales 0. Se ha fijado.
EDITAR el tercero: Creo que Leonid Shifrin es correcto asociar el problema con Module
; Puedo obtener el mismo tipo de comportamiento de la versión basada en NestWhile
reemplazando el With
con un Module
:
nestModuleLength[ll_pair] :=
Module[{step = {#[[1, -1]], #[[-1]] + 1} &},
[email protected][step, {ll, 0}, ! [email protected]@# &]];
In[15]:= Select[getTimes[nestModuleLength, 100], # > 3 &]
Out[15]= {3.797}
Developer'PackedArrayQ puede ser relevante –
@Yaroslav Bulatov: No puedo ver por qué matrices envasados serían relevantes, ya que nada se debe embalar, excepto la inicial '' list' generada por randominteger ', que se convierte inmediatamente en una expresión de árbol. – Pillsy
¿Estás usando la versión 7 u 8? En cualquier caso, por lo que vale, creo que has descubierto algo de un error o al menos un punto débil en el comportamiento de evaluación. –