Am 12.03.14 21:48, schrieb Alexandre Ferrieux:
> OK, this aspect of your implementation had escaped me before. I
> thought you were still keeping an array of Tcl_Obj*. Now I see you
> are selecting one numeric type (doubles) and storing them directly as
> scalars ('expanded' as we would say in Eiffel). This is indeed *much*
> more efficient than what I thought, no comparison
>
> But in this case, I don't see a compelling reason for optimized
> bridges to the List type, since any mapping would incur the re-boxing
> (or conversion and un-boxing) of the individual values, with the
> overhead you've just highlighted.
Yes, this is true. Shimmering will occur sooner or later, as the user
wants to pull out the results from the computation, but all the
intermediate computations will be done in the most efficient
representation (contiguous array).
Of course, going via the string representation is still much more
expensive than via the list converter; the below code shimmers a vector
of 10000 elements between NumArray and list:
(vectcl) 49 % set x {}; for {set i 0} {$i<10000} {incr i} {
lappend x [expr rand()]
}
(vectcl) 50 % time {numarray .*= x 1.0; llength $x } 1000
1663.129394 microseconds per iteration
without the patch:
(vectcl) 50 % time {numarray .*= x 1.0; llength $x } 1000
24022.946292 microseconds per iteration
Therefore it's roughly 15 times faster with the list code. For matrices,
the NumArray->list converter creates slices for the rows of a matrix,
i.e. it shimmers to a list of NumArrays, which point to the original
buffer. The use case would be a
foreach row $matrix
invocation. Going via the string rep necessarily converts every value to
a string.
The question remains: is it possible to incorporate the small patch,
which replaces in tclListObj.c the direct invocations of SetListFromAny
with Tcl_ConvertToType? The extension still needs to do some "illegal"
stuff to inject the list converter, but at least it works.
> Also, note that selecting one scalar type biases the package towards
> one kind of computation (floating point based), precluding its us
> with e.g. bignums. But maybe this does not really matter given the
> target fields.
Yes and no. The current status is that it is working with doubles, but
I'm now adding support for integers and complex numbers. Integers are
needed to perform index arithmetics, and complex numbers will be used
for some standard linalg stuff, that should be provided by the basic
package (eigenvalues, FFT). There will be type metainformation similar
to Tcl_Obj->typePtr, but only once for the whole array of numbers. That
is consensus among all the numerical packages I've seen so far.
The overall idea is to have the EIAS data types expanded to
vector/matrix/tensor arithmetics. This can't distinguish between float
and double, but it can between an integer 1, a double 1.0 and a complex
1.0+0.0i, similar to expr, and therefore an integer vector {1 2}, a real
vector {1.0 2.0} and a complex vector {1.0+0.0i 2.0+0.0i}. From the
script perspective there should be no difference between expr and loops
on the list-of-lists representation and vexpr; except that the latter is
much faster and allows slicing, reductions etc. with a Matlab like syntax.
Christian
=== here comes the trivial patch ===
--- tclListObj.c.orig 2014-03-04 20:14:03.000000000 +0100
+++ tclListObj.c 2014-03-04 20:14:06.000000000 +0100
@@ -470,7 +470,7 @@
*objvPtr = NULL;
return TCL_OK;
}
- result = SetListFromAny(interp, listPtr);
+ result = Tcl_ConvertToType(interp, listPtr, &tclListType);
if (result != TCL_OK) {
return result;
}
@@ -579,7 +579,7 @@
Tcl_SetListObj(listPtr, 1, &objPtr);
return TCL_OK;
}
- result = SetListFromAny(interp, listPtr);
+ result = Tcl_ConvertToType(interp, listPtr, &tclListType);
if (result != TCL_OK) {
return result;
}
@@ -743,7 +743,7 @@
*objPtrPtr = NULL;
return TCL_OK;
}
- result = SetListFromAny(interp, listPtr);
+ result = Tcl_ConvertToType(interp, listPtr, &tclListType);
if (result != TCL_OK) {
return result;
}
@@ -796,7 +796,7 @@
*intPtr = 0;
return TCL_OK;
}
- result = SetListFromAny(interp, listPtr);
+ result = Tcl_ConvertToType(interp, listPtr, &tclListType);
if (result != TCL_OK) {
return result;
}
@@ -869,7 +869,7 @@
}
Tcl_SetListObj(listPtr, objc, NULL);
} else {
- int result = SetListFromAny(interp, listPtr);
+ int result = Tcl_ConvertToType(interp, listPtr, &tclListType);
if (result != TCL_OK) {
return result;
@@ -1627,7 +1627,7 @@
}
return TCL_ERROR;
}
- result = SetListFromAny(interp, listPtr);
+ result = Tcl_ConvertToType(interp, listPtr, &tclListType);
if (result != TCL_OK) {
return result;
}
=============================================================