Function Repository Resource:

Einstoff

Source Notebook

Manipulate multidimensional arrays with a einsum-descendant tensor-axis notation

Contributed by: Gravifer

ResourceFunction["Einstoff"][operator]

returns the curried Einstoff interface selected by operator, such as ArrayReshape,ArrayReduce,Dot or Map.

Details

The returned function keeps the call signature and behavior of the corresponding operator in the Gravifer/Einstoff paclet.
ResourceFunction["Einstoff"] is an operator selector. ResourceFunction["Einstoff"][operator] returns the curried interface for that operation; the returned function accepts a shape description, a list of tensors, an optional list of axis-size bindings, and options.
Built-in symbols accepted as the operator argument include ArrayReshape, ArrayReduce, Operate, Map, Dot, Inner, Join and Split. String selectors accepted in the same argument are "Massage", "ArrayContract" and "einsum". ResourceFunction["Einstoff"]["Massage"] selects the permissive structural engine; ResourceFunction["Einstoff"][ArrayReshape] and ResourceFunction["Einstoff"]["ArrayContract"] impose narrower capability checks.
A description is normally a RuleDelayed expression {inputShape1, inputShape2, } {outputShape1, outputShape2, }. Each shape is a list of dimension terms, and tensors is a list whose arity agrees with the input shapes.
On the complete left-hand side, a_ binds and infers the logical axis a. Repeated occurrences of a_ denote the same logical axis and must have equal size. A bare a on the left remains an ambient expression; a bare a on the right references the completed left-hand-side binding.
String axes such as "channels" are hygienically scoped names that are independent of symbol values. Anonymous blanks infer unnamed axes, while BlankSequence and BlankNullSequence describe one-or-more and zero-or-more axis sequences.
CircleTimes composes logical axes into one physical dimension. CirclePlus denotes a structural direct sum used by ResourceFunction["Einstoff"][Join], ResourceFunction["Einstoff"][Split], and the permissive ResourceFunction["Einstoff"]["Massage"]. Positive integers denote literal sizes, and 1 or an empty shape represents a unit axis where applicable.
Targeted axes identify blocks consumed by reduction, contraction or mapped operations. String axes may be targeted with Slot, Highlighted or Framed; symbol axes use Highlighted or Framed. Targeting is occurrence metadata and does not change logical axis identity.
Annotation[axis,n] and Labeled[n,axis] declare an inline positive-integer size on either side of a description. They compose in either nesting order with valid targeting wrappers. A sized blank both infers its size and checks equality with n.
Explicit bindings are supplied as a list of rules, for example {"channels"3}. Symbol and string spellings for one logical name may not be mixed, and inference-only blank spellings are not valid out-of-band binding keys.
For the operator selectors ArrayReshape, "Massage", "ArrayContract", ArrayReduce, Dot, Inner and "einsum", the option "Targeting" accepts True, False or Automatic to control whether operated axes are inferred, checked against explicit targets, or required explicitly. TraceActionHold or TraceActionDefer returns the lowered Wolfram expression instead of executing it normally.
ResourceFunction["Einstoff"][ArrayReduce] accepts either a Wolfram reducer or a case-insensitive recipe name: sum, total, add, mean, average, max, min, prod, product, times, var, variance, std, stddev, count_nonzero, countnonzero, any, all, logsumexp or lse. Variance and standard deviation use population normalization, and any/all test whether elements are nonzero.
ResourceFunction["Einstoff"][Operate] accepts a Wolfram function or a case-insensitive shape-preserving recipe name: id, identity, flip, reverse, sort, softmax, log_softmax or logsoftmax. Parameterized operations can be supplied directly as functions, for example RotateLeft[#,k]&.
This resource delegates through PacletSymbol to the published Gravifer/Einstoff paclet, which requires Wolfram Language 15.0 or later. Parsing, validation, planning and execution remain versioned in that paclet rather than being copied into this Resource Function.
For now, the Gravifer/Einstoff paclet requires Wolfram Language 15.0 or later; PacletSymbol cannot resolve this resource on an older system.
Use RuleDelayed for descriptions. Rule may evaluate its right-hand side before ResourceFunction["Einstoff"] captures the description and is supported only on a best-effort basis.
Bare symbols on the left-hand side are ambient expressions, not references to another blank of the same spelling. Use a_ to bind an inferred axis and use bare a on the right-hand side to reference that completed binding.
String axes are hygienic and immune to ambient symbol values. Keep explicit bindings in a list, for example {"channels"3}.
ResourceFunction["Einstoff"] is inspired by einops and einx, but uses Wolfram Language rules instead of parsing raw strings.

Examples

Basic Examples (3) 

Permute the axes of a rank-three array:

In[1]:=
x = ArrayReshape[Range[24], {2, 3, 4}]; 
ResourceFunction["Einstoff"][
  ArrayReshape][{{a_, b_, c_}} :> {{c, a, b}}, {x}]
Out[1]=

Merge adjacent axes into one product axis:

In[2]:=
ResourceFunction["Einstoff"][
  ArrayReshape][{{a_, b_}} :> {{a\[CircleTimes]b}}, {ArrayReshape[
   Range[6], {2, 3}]}]
Out[2]=

Contract a shared axis of two tensors using Dot:

In[3]:=
ResourceFunction["Einstoff"][
  Dot][{{a_, b_}, {b_, c_}} :> {{a, c}}, {ArrayReshape[
   Range[6], {2, 3}], ArrayReshape[Range[12], {3, 4}]}]
Out[3]=

Scope (9) 

Select the ArrayReduce operator, here reducing a targeted axis:

In[4]:=
ResourceFunction["Einstoff"][ArrayReduce][
  Total][{{a_, #b}} :> {{a}}, {ArrayReshape[Range[6], {2, 3}]}]
Out[4]=

Split a product axis using an explicit hygienic string-axis binding:

In[5]:=
ResourceFunction["Einstoff"][
  ArrayReshape][{{"rows"\[CircleTimes]b_}} :> {{"rows", b}}, {Range[
   6]}, {"rows" -> 2}]
Out[5]=

Broadcast an output-only axis whose size is declared inline:

In[6]:=
ResourceFunction["Einstoff"][
  "Massage"][{{a_}} :> {{a, Annotation[c, 3]}}, {Range[4]}]
Out[6]=

Use string axes when names must be independent of ambient symbol values:

In[7]:=
ResourceFunction["Einstoff"][
  ArrayReshape][{{"row", "col"}} :> {{"col", "row"}}, {ArrayReshape[
   Range[6], {2, 3}]}]
Out[7]=

Apply a shape-preserving function to each targeted block:

In[8]:=
ResourceFunction["Einstoff"][Operate][Reverse][{{a_, 
\!\(\*FrameBox[\!\(b_\),
DefaultBaseStyle->"HighlightedInput",
FrameStyle->None,
StripOnInput->False]\)}} :> {{a, 
\!\(\*FrameBox[\!\(b\),
DefaultBaseStyle->"HighlightedInput",
FrameStyle->None,
StripOnInput->False]\)}}, {ArrayReshape[Range[6], {2, 3}]}]
Out[8]=

Use Map when the operation may change the shape of each targeted block:

In[9]:=
ResourceFunction["Einstoff"][Map][
  Total][{{a_, #b}} :> {{a}}, {ArrayReshape[Range[6], {2, 3}]}]
Out[9]=

Choose custom multiplication and addition functions with Inner; this example uses tropical arithmetic:

In[10]:=
ResourceFunction["Einstoff"][Inner][Plus, Min][{{a_}, {b_}} :> {{a, b}}, {Range[2], Range[3]}]
Out[10]=

Contract two equal axes within one tensor while preserving the remaining axes:

In[11]:=
ResourceFunction["Einstoff"][
  "ArrayContract"][{{a_, b_, a_, d_}} :> {{b, d}}, {ArrayReshape[
   Range[16], {2, 2, 2, 2}]}]
Out[11]=

Join tensors along a structural direct-sum axis:

In[12]:=
ResourceFunction["Einstoff"][
  Join][{{m_, a_}, {m_, b_}} :> {{m, a\[CirclePlus]b}}, {ArrayReshape[
   Range[6], {2, 3}], ArrayReshape[Range[8], {2, 4}]}]
Out[12]=

Split a direct-sum axis into multiple output tensors:

In[13]:=
ResourceFunction["Einstoff"][
  Split][{{b_, "q"\[CirclePlus]k_}} :> {{b, "q"}, {b, k}}, {ArrayReshape[Range[20], {2, 10}]}, {"q" -> 3}]
Out[13]=

Generalizations & Extensions (4) 

Named recipes provide common operations without defining a separate function:

In[14]:=
ResourceFunction["Einstoff"][ArrayReduce][
  "max"][{{a_, b_}} :> {{a}}, {ArrayReshape[Range[12], {3, 4}]}]
Out[14]=

Use the einsum (Einstein summation) dispatcher when an operator is implied by the repeated-axis structure:

In[15]:=
ResourceFunction["Einstoff"][
  "einsum"][{{a_, b_}, {b_, c_}} :> {{a, c}}, {ArrayReshape[
   Range[6], {2, 3}], ArrayReshape[Range[12], {3, 4}]}]
Out[15]=

Repeat one binder to require equal dimensions and contract a matrix trace:

In[16]:=
ResourceFunction["Einstoff"][
  "einsum"][{{a_, a_}} :> {{}}, {ArrayReshape[Range[9], {3, 3}]}]
Out[16]=

Capture a run of leading axes and project that sequence onto the output:

In[17]:=
ResourceFunction["Einstoff"][ArrayReduce][Total][{{a__, 
\!\(\*FrameBox[\!\(b_\),
DefaultBaseStyle->"HighlightedInput",
FrameStyle->None,
StripOnInput->False]\)}} :> {{a ..}}, {ArrayReshape[
   Range[24], {2, 3, 4}]}]
Out[17]=

Use a named shape-preserving block operation:

In[18]:=
ResourceFunction["Einstoff"][Operate][
  "softmax"][{{a_, #b}} :> {{a, #b}}, {{{0, Log[3]}}}]
Out[18]=

Options (2) 

Require contracted axes to be targeted explicitly:

In[19]:=
ResourceFunction["Einstoff"][
  Dot][{{a_, #b}, {#b, c_}} :> {{a, c}}, {ArrayReshape[
   Range[6], {2, 3}], ArrayReshape[Range[12], {3, 4}]}, {}, "Targeting" -> True]
Out[19]=

Use TraceAction to inspect the lowered Wolfram expression without executing it:

In[20]:=
ResourceFunction["Einstoff"][
  ArrayReshape][{{a_, b_}} :> {{b, a}}, {ArrayReshape[
   Range[6], {2, 3}]}, {}, TraceAction -> Hold]
Out[20]=

Applications (4) 

Pool over every non-batch axis:

In[21]:=
ResourceFunction["Einstoff"][ArrayReduce][
  Mean][{{batch_, height_, width_}} :> {{batch}}, {ArrayReshape[
   Range[24], {2, 3, 4}]}]
Out[21]=

Express batched matrix multiplication; inspect the resulting batch, row and column dimensions:

In[22]:=
Dimensions[
 ResourceFunction["Einstoff"][
   Dot][{{n_, a_, b_}, {n_, b_, c_}} :> {{n, a, c}}, {ArrayReshape[
    Range[24], {2, 3, 4}], ArrayReshape[Range[40], {2, 4, 5}]}]]
Out[22]=

Assemble four blocks into one direct-sum array:

In[23]:=
ResourceFunction["Einstoff"][
  "Massage"][{{a_, b_}, {a_, c_}, {d_, b_}, {d_, c_}} :> {{a\[CirclePlus]d, b\[CirclePlus]c}}, {{{0, 1}}, {{10, 11,
     12}}, {{20, 21}, {22, 23}}, {{30, 31, 32}, {33, 34, 35}}}]
Out[23]=

Perform a space-to-depth-style rearrangement using explicitly sized block axes:

In[24]:=
Dimensions[
 ResourceFunction["Einstoff"][
   ArrayReshape][{{batch_, height_\[CircleTimes]"hBlock", width_\[CircleTimes]"wBlock"}} :> {{batch, height, width, "hBlock"\[CircleTimes]"wBlock"}}, {ArrayReshape[
    Range[48], {2, 4, 6}]}, {"hBlock" -> 2, "wBlock" -> 3}]]
Out[24]=

Properties & Relations (6) 

To a large extent, Einstoff just offers an altered interface to built-in functions.

Dropping an axis with Einstoff[ArrayReduce][Total] agrees with mapping Total over the retained rows:

In[25]:=
With[{x = ArrayReshape[Range[12], {3, 4}]}, ResourceFunction["Einstoff"][ArrayReduce][
    Total][{{a_, b_}} :> {{a}}, {x}] === Total /@ x]
Out[25]=

Einstoff[ArrayReshape] descriptions lower to combinations of ArrayReshape, Transpose and unit-axis handling.

A pure axis permutation agrees with Transpose:

In[26]:=
With[{x = ArrayReshape[Range[24], {2, 3, 4}]}, ResourceFunction["Einstoff"][
    ArrayReshape][{{a_, b_, c_}} :> {{c, a, b}}, {x}] === Transpose[x, {2, 3, 1}]]
Out[26]=

Einstoff[Dot] is the Times-and-Plus specialization of Einstoff[Inner] and agrees with native matrix multiplication:

In[27]:=
With[{x = ArrayReshape[Range[6], {2, 3}], y = ArrayReshape[Range[12], {3, 4}]}, ResourceFunction["Einstoff"][
    Dot][{{a_, b_}, {b_, c_}} :> {{a, c}}, {x, y}] === ResourceFunction["Einstoff"][Inner][Times, Plus][{{a_, b_}, {b_, c_}} :> {{a, c}}, {x, y}] === x . y]
Out[27]=

A within-tensor contraction agrees with TensorContract:

In[28]:=
With[{x = ArrayReshape[Range[16], {2, 2, 2, 2}]}, ResourceFunction["Einstoff"][
    "ArrayContract"][{{a_, b_, a_, d_}} :> {{b, d}}, {x}] === TensorContract[x, {{1, 3}}]]
Out[28]=

Einstoff[Join] and Einstoff[Split] interpret CirclePlus as a structural direct sum, while CircleTimes composes multiple logical axes into one physical dimension.

A structural direct-sum join agrees with Join along the corresponding array dimension:

In[29]:=
With[{x = ArrayReshape[Range[6], {2, 3}], y = ArrayReshape[Range[8], {2, 4}]}, ResourceFunction["Einstoff"][
    Join][{{m_, a_}, {m_, b_}} :> {{m, a\[CirclePlus]b}}, {x, y}] === Join[x, y, 2]]
Out[29]=

A structural direct-sum split agrees with taking the corresponding column ranges:

In[30]:=
With[{x = ArrayReshape[Range[20], {2, 10}]}, ResourceFunction["Einstoff"][
    Split][{{m_, "q"\[CirclePlus]k_}} :> {{m, "q"}, {m, k}}, {x}, {"q" -> 3}] === {Take[x, All, {1, 3}], Take[x, All, {4, 10}]}]
Out[30]=

Neat Examples (1) 

Create a banner saying "Einstoff":

In[31]:=
ims = MapIndexed[ImageMultiply[{#1,
      Lighter[ColorData["DefaultChartColors"]@First@#2, .7]}]
    &, Rasterize[#, RasterSize -> 56] & /@ Characters@"Einstoff"];
ResourceFunction["Einstoff"][
   ArrayReshape][{{batch_, height_, width_, color_}} :> {{height, batch\[CircleTimes]width, color}}, {ImageData /@ ims}] // Image
Out[14]=

Publisher

Gravifer

Version History

  • 1.0.0 – 24 August 2026

Source Metadata

Related Resources

Author Notes

This resource is intentionally a thin discoverability facade. Tensor-axis parsing, validation, planning, and execution are implemented and versioned only in the Gravifer/Einstoff paclet.

License Information