Function Repository Resource:

General contraction of levels of the outer product of arrays

Contributed by: Jose Martin-Garcia
 ResourceFunction["ArrayContractThread"][f,{a1,a2,…,an},{{l1,l2,…,ln}}] contracts level l1 of array a1, level l2 of array a2,… in Outer[f,a1,…,an], using head Plus. ResourceFunction["ArrayContractThread"][f,arrays,{ctr1,ctr2,…}] performs several contractions. ResourceFunction["ArrayContractThread"][f,arrays,ctrs,g] performs contractions ctrs using head g. ResourceFunction["ArrayContractThread"][f,{a1,…,an},ctrs,g,{d1,…,dn}] performs contractions assuming that only the first di levels of array ai are array levels.

## Details and Options

Each contraction ctrk in the contraction list must be a list of non-negative integers {lk1,,lkn}. A positive lki indicates the level of array ai to be contracted during contraction ctrk . A zero lki indicates that array ai does not participate in contraction ctrk.
For each contraction ctrk, all levels lki must have the same dimension. That is, Dimensions[ai][[lki]] must coincide for all i for each k.
Each array ai in ResourceFunction["ArrayContractThread"][f,{a1,,an},] must be rectangular up to the deepest level involved in the contractions.
The effective depth di in ResourceFunction["ArrayContractThread"][f,{a1,,an},ctrs,g,{d1,,dn}] can be used to indicate that array ai should be treated as if it had only di levels. Therefore di must be an integer between 0 and the depth of ai, and all contraction levels lki must be between 0 and di. Following the precedent of Outer, by default di is chosen to be the depth of the array ai.
ResourceFunction["ArrayContractThread"] cannot contract levels of the same array. Use the resource function ArrayContract for that.

## Examples

### Basic Examples (2)

Take two arrays:

 In[1]:=
 Out[1]=
 In[2]:=
 Out[2]=

Contract the first levels of the arrays:

 In[3]:=
 Out[3]=

Contract level 2 of the first array and level 1 of the second:

 In[4]:=
 Out[4]=

Take three arrays:

 In[5]:=
 Out[5]=
 In[6]:=
 Out[6]=
 In[7]:=
 Out[7]=

Perform two simultaneous contractions:

 In[8]:=
 Out[8]=

Use head g for the same contractions:

 In[9]:=
 Out[9]=

### Scope (6)

Use arrays of any depth and dimension:

 In[10]:=
 In[11]:=
 Out[11]=

Perform any number of contractions simultaneously:

 In[12]:=
 In[13]:=
 Out[13]=
 In[14]:=
 Out[14]=
 In[15]:=
 Out[15]=

 In[16]:=
 In[17]:=
 Out[17]=

Specify the effective levels of the arrays:

 In[18]:=
 In[19]:=
 Out[19]=
 In[20]:=
 Out[20]=
 In[21]:=
 Out[21]=
 In[22]:=
 Out[22]=

Arrays do not need to be rectangular beyond the contraction levels:

 In[23]:=
 Out[23]=
 In[24]:=
 Out[24]=

Effective depths can be zero, and then the whole array is treated as a scalar:

 In[25]:=
 In[26]:=
 Out[26]=

### Properties and Relations (8)

Inner is a particular case of ArrayContractThread:

 In[27]:=
 In[28]:=
 Out[28]=
 In[29]:=
 Out[29]=
 In[30]:=
 Out[30]=
 In[31]:=
 Out[31]=

Dot is a particular case of ArrayContractThread:

 In[32]:=
 In[33]:=
 Out[33]=
 In[34]:=
 Out[34]=

Outer is a particular case of ArrayContractThread:

 In[35]:=
 In[36]:=
 Out[36]=
 In[37]:=
 Out[37]=
 In[38]:=
 Out[38]=

ArrayContractThread can handle scalar factors, but Outer cannot:

 In[39]:=
 Out[39]=
 In[40]:=
 Out[40]=

 In[41]:=
 In[42]:=
 Out[42]=
 In[43]:=
 Out[43]=

 In[44]:=
 In[45]:=
 Out[45]=

TensorContract of a TensorProduct expression is a particular case of ArrayContractThread if each contraction involves at most one level of each array:

 In[46]:=
 In[47]:=
 Out[47]=

The special case ArrayContractThread[f,{expr},{{n}},List,n] is equivalent to Map[f,expr,{n}]:

 In[48]:=
 In[49]:=
 Out[49]=
 In[50]:=
 Out[50]=
 In[51]:=
 Out[51]=

The special case ArrayContractThread[Identity,{expr},{{n}},g,n] is equivalent to Apply[g,expr,{n-1}]:

 In[52]:=
 In[53]:=
 Out[53]=
 In[54]:=
 Out[54]=
 In[55]:=
 Out[55]=

### Possible Issues (2)

ArrayContractThread effectively normalizes sparse and structured arrays in input:

 In[56]:=
 Out[56]=

Compare to the equivalent computation with Outer:

 In[57]:=
 Out[57]=
 In[58]:=
 Out[58]=

## Publisher

Jose Martin-Garcia

## Version History

• 1.0.0 – 05 August 2020

## Author Notes

• This function is rather slow, and normalizes everything. It is essentially a prototype to explore the generality of the possible concept.

• This function could still be generalized as follows: 1) the fourth argument could take a list of heads, one per contraction (this will be implemented in 12.2)—right now all contractions in the third argument use the same head in the fourth argument; and 2) like Tr, it should be possible to contract to the lowest dimension, instead of requiring coinciding dimensions.