Fusion — np.evaluate vs unfused chains (and NumPy context)
np.evaluate runs a whole expression tree in one NDIter pass (no intermediates). Fixed-expression gate plus an operand-layout sweep of the flagship a*b+c (C/F/T/strided/bcast — does the fused single-pass win survive non-contiguous operands?), not a dtype/layout matrix — so reported as-is.
NumSharp — fused np.evaluate vs unfused np.* chains (4M elements, best-of-9; (Nx) = unfused ÷ fused, >1 = fusion faster):
correctness cross-checks ok
4M float64, best of 9:
a*b+c fused 3.53 ms unfused 6.08 ms (1.72x)
(a-b)/(a+b) fused 3.16 ms unfused 12.32 ms (3.90x)
sum(a*b) fused 2.30 ms unfused 4.33 ms (1.88x)
sum(af*bf) fused 1.43 ms unfused 1.57 ms (1.10x) [f32]
a*b+c out= fused 3.56 ms [1-pass fused-into-out]
i4*2+f8 fused 2.78 ms unfused 4.04 ms (1.45x)
a*b+c across operand layouts (2-D 2000x2000, all 3 operands same layout):
[C ] fused 3.43 ms unfused 6.05 ms (1.77x)
[F ] fused 3.52 ms unfused 6.18 ms (1.75x)
[T ] fused 3.50 ms unfused 6.27 ms (1.79x)
[strided] fused 3.31 ms unfused 4.72 ms (1.43x)
[bcast ] fused 1.06 ms unfused 3.75 ms (3.53x)
NumPy — absolutes on the same box (context for the unfused column):
numpy 2.4.2, 4M float64, best of 9:
a*b+c 12.35 ms
(a-b)/(a+b) 18.75 ms
sum(a*b) 8.60 ms
sum(af*bf) 4.14 ms [f32]
a*b+c out= 4.68 ms [two-pass with out=]
i4*2+f8 9.67 ms
a*b+c across operand layouts (2-D 2000x2000, unfused):
[C ] 12.52 ms
[F ] 12.54 ms
[T ] 12.51 ms
[strided] 7.91 ms
[bcast ] 11.95 ms