TransWikia.com

Alternative to Inner which allows level specification

Mathematica Asked by arutar on February 11, 2021

Is it possible to restrict Inner to a certain level? According to the documentation, the expected behaviour for Inner is to compute the generalized inner products of tensors at as high a level as possible.

As a simple example, if

f[{a_},{b_}]:={a b}
g[{a_},{b_}]:={a+b}

then for the calls

Inner[f, {{{a}, {b}}, {{c}, {d}}}, {{{x}}, {{y}}}, g]
Inner[f, {{{a}}}, {{{b}}}, g]

the first throws an error (the dimensions do not line up) and the second returns {{{f[a,b]}}}.

However, I want to restrict Inner to, say, level 2, so that

level2Inner[f, {{{a}, {b}}, {{c}, {d}}}, {{{x}}, {{y}}}, g] === {{a x + b y}, {c x + d y}}
level2Inner[f, {{{a}}}, {{{b}}}, g] === {{a b}}

I only really care about the level 2 behaviour, but it would be nice to know if more general behaviour is possible. Is there an elegant or standard way to do this?

Edit: One special case I am concerned with is the following. Define the function

f[nestedList1_,nestedList2_]:=Flatten /@ Tuples[{nestedList1, nestedList2}]

which just computes all possible concatenations of lists from the collection nestedList1 with lists from the collection nestedList2. Then given two matrices M1 and M2, where the entries of these matrices are lists of lists, I want something like

level2Inner[f, M1, M2, Join]

One can think of the operation f as computing all possible combinations, except the level2Inner restricts such combinations only to "valid pairs", i.e. where the indices in M1 and M2 line up appropriately.

For example, if you have a directed graph on n vertices, and M is the matrix n by n matrix with entry i,j consisting of a given list of paths (where each path is a list of edges) in G connecting vertex i with vertex j, then the i,j entry of level2Inner[f,M,M,Join] is a list of all possible (valid) paths from vertex i to vertex j which are concatenations of two paths originally specified in the matrix M.

3 Answers

I believe you want

MapThread[f, {M1, M2}, 2]

where you could also take (just to mention the useful Outer function)

f[M1ij_, M2ij_] := Flatten[Outer[Join, M1ij, M2ij, 1], 1]

for your all-concatenations-of-lists-in-lists function!

Answered by thorimur on February 11, 2021

Maybe like this.

Flatten/@Inner[Times, {{{a}, {b}}, {{c}, {d}}}, {{{x}}, {{y}}}, Plus, 2]
level2Inner[f_, list1_?ListQ, list2_?ListQ, g_] := 
  Flatten /@ Inner[f, list1, list2, g, 2];
level2Inner[Times, {{{a}, {b}}, {{c}, {d}}}, {{{x}}, {{y}}}, Plus]
level2Inner[Times, {{{a}}}, {{{b}}}, Plus]

{{a x + b y}, {c x + d y}}

{{a b}}

Answered by cvgmt on February 11, 2021

Why don't you strip appropriate List heads first? Like this

f[a_, b_] := a*b;
g[a__] := Plus[a];
level2Inner = Inner[#1, #2[[All, All, 1]], #3[[All, All, 1]], #4] &;
level2Inner[f, {{{a}, {b}}, {{c}, {d}}}, {{{x}}, {{y}}}, g](*=> {{a x+b y},{c x+d y}}*)
level2Inner[f, {{{a}}}, {{{b}}}, g](*=> {{a b}}*)

Note that for your second example to work g should be defined for arbitrary number of arguments.

EDIT: If you don't want to change the definitions of f and g, and also as a generalization for generic level, you can use

LevelInner[f_, m1_, m2_, g_, lvl_] := 
 Module[{f1, g1, id}, 
  Inner[f1, Map[id, m1, {lvl}], Map[id, m2, {lvl}], g1] /. 
    id -> Identity /. f1 -> f/. g1 -> g}];
LevelInner[f, {{{a}, {b}}, {{c}, {d}}}, {{{x}}, {{y}}}, g, 2](*=> {{g[f[{a}, {x}], f[{b}, {y}]]}, {g[f[{c}, {x}], f[{d}, {y}]]}}*)

Answered by Roma Lee on February 11, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP