Awhile back, I'd asked for a similar thing, a tensor _inner_ product. Raul Miller responded. I have the whole (or its majority) saved in my snippets file.
NB. Viktor Grigorov mentioned a need for a tensor product.
NB. I have been trying to think of a good simple expression, but there's special cases.
NB. Still, I figured maybe someone might make use of this:
tip=:{{assert.1=#,m
select.m=.{.,m
case.0 do.*/
NB. case.1 do.+/ .*
NB. case.2 do.+/@(,/)@(*"2 _)
NB. case. _ do.+/@,@(*"_)
case.do.+/@(,/^:(m-1))@(*"(m,_))end.}}
NB. Example use:
(i.2 3) 1 tip i.3 4
20 23 26 29
56 68 80 92
(i.2 3) +/ .* i.3 4
20 23 26 29
56 68 80 92
(i.2 3 5) 2 tip i.3 5 7
7105 7210 7315 7420 7525 7630 7735
18130 18460 18790 19120 19450 19780 20110
NB. Basically, the m argument to tip (tensor inner product) is the number
NB. of pairs of dimensions in the argument arrays which should be summed
NB. in the tensor product.
NB. You can use _ if you want all dimensions to be paired.
NB. The commented out lines in the definition could be removed or instated
NB. (with the NB. toggled out) and that should make no difference in the
NB. result, other than a slightly different intermediate representation of
NB. the inner product.
NB. As you can see in my above quicky examples, the m argument to tip is
NB. the number of (inner) dimensions which must match between the two
NB. array arguments. These dimensions vanish from the shape of the result.
NB. I should add that the definition of tip which I supplied assumes
NB. you're running the current j903 beta.
NB. Here's a definition which works on earlier released versions of J:
tip=:1 :0
assert. 1=#,m
select. m=. {.,m
case. 0 do. */
NB. case. 1 do. +/ .*
NB. case. 2 do.
NB. +/@(,/)@(*"2 _)
NB. case. _ do.
NB. +/@,@(*"_)
case. do.
+/@(,/^:(m-1))@(*"(m,_))
end.
)
NB. I should add that if you need the matched dimensions of the right
NB. argument to be reversed, you could replace " in the definition with a
NB. conjunction which reverses the order of those dimensions in that
NB. argument. For example, you could replace " with irank:
irank=:2 :0
urank=. {:3$&.|.n
yrank=. #$y
transpose=. |.(-urank){.i.yrank
x u"n transpose|:y
)
NB. (This leaves some edge cases unhandled -- negative n and degenerate y
NB. -- but support for those cases could be added if this were truly
NB. useful.)
$ (i.2 3 5 7) +irank 2 i.2 3 7 5
2 3 5 7
NB. But, like you said, it all depends on the definitions. And, it seemed
NB. to me that working with the natural behavior of " was good.
NB. (And you can always transpose manually, outside of the inner product
NB. definition.)
NB. Oops, I goofed.
NB. it's x that needs its trailing dimensions reversed, not y.
NB. And, because of how this works, x should have all of its dimensions
NB. reversed. So irank is not actually needed.
NB. So, here's an implementation that works like you had suggested:
tip=:1 :0
assert. 1=#,m
select. m=. {.,m
case. 0 do. */
NB. case. 1 do. +/ .*
NB. case. 2 do.
NB. +/@(,/)@(*"2 _)
NB. case. _ do.
NB. +/@,@(*"_)
case. do.
+/@(,/^:(m-1))@((* |:)~"(m,_))
end.
)
$(i.2 3 7 5) 2 tip i.5 7 11 13
2 3 11 13
NB. mm...
NB. I guess when working with tensors, 0 tip 1 would be the identity operation.
NB. For example:
(i.3 3 3)-:0 tip&1 i.3 3 3
1
NB. But it's also possible to find identity tensors for other tip operations.
(i.3 3 3) -:(i.3 3 3)1 tip =i.3
1
(i.3 3 3) -:1 tip&(=i.3) i.3 3 3 NB. alternate phrasing
1
NB. I have not thought about this enough to write an elegant id tensor
NB. generator, but it's easy enough to brute force:
genid=:4 :0
r=.0*raw=.i.(2*x)#y
p=: p:i.(1+x)#y
for_n.,raw do.
sel=.raw=n
try=. p x tip sel
if. try-:p**try do.
r=.r+sel
end.
end.
r
)
(i.3 3 3)-: (i.3 3 3) 2 tip 2 genid 3
1
(i.3 3 3)-: (i.3 3 3) 3 tip 3 genid 3
1
May 9, 2024, 21:04 by
and...@foxmail.com:
> To unsubscribe from this group and stop receiving emails from it, send an email to
forum+un...@jsoftware.com.
>