199 lines
3.6 KiB
C++
199 lines
3.6 KiB
C++
// Do the inner product of tensors.
|
|
|
|
#include "stdafx.h"
|
|
#include "defs.h"
|
|
|
|
static void inner_f(void);
|
|
|
|
void
|
|
eval_inner(void)
|
|
{
|
|
p1 = cdr(p1);
|
|
push(car(p1));
|
|
eval();
|
|
p1 = cdr(p1);
|
|
while (iscons(p1)) {
|
|
push(car(p1));
|
|
eval();
|
|
inner();
|
|
p1 = cdr(p1);
|
|
}
|
|
}
|
|
|
|
void
|
|
inner(void)
|
|
{
|
|
save();
|
|
p2 = pop();
|
|
p1 = pop();
|
|
if (istensor(p1) && istensor(p2))
|
|
inner_f();
|
|
else {
|
|
push(p1);
|
|
push(p2);
|
|
if (istensor(p1))
|
|
tensor_times_scalar();
|
|
else if (istensor(p2))
|
|
scalar_times_tensor();
|
|
else
|
|
multiply();
|
|
}
|
|
restore();
|
|
}
|
|
|
|
// inner product of tensors p1 and p2
|
|
|
|
static void
|
|
inner_f(void)
|
|
{
|
|
int ak, bk, i, j, k, n, ndim;
|
|
U **a, **b, **c;
|
|
|
|
n = p1->u.tensor->dim[p1->u.tensor->ndim - 1];
|
|
|
|
if (n != p2->u.tensor->dim[0])
|
|
stop("inner: tensor dimension check");
|
|
|
|
ndim = p1->u.tensor->ndim + p2->u.tensor->ndim - 2;
|
|
|
|
if (ndim > MAXDIM)
|
|
stop("inner: rank of result exceeds maximum");
|
|
|
|
a = p1->u.tensor->elem;
|
|
b = p2->u.tensor->elem;
|
|
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// ak is the number of rows in tensor A
|
|
//
|
|
// bk is the number of columns in tensor B
|
|
//
|
|
// Example:
|
|
//
|
|
// A[3][3][4] B[4][4][3]
|
|
//
|
|
// 3 3 ak = 3 * 3 = 9
|
|
//
|
|
// 4 3 bk = 4 * 3 = 12
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
ak = 1;
|
|
for (i = 0; i < p1->u.tensor->ndim - 1; i++)
|
|
ak *= p1->u.tensor->dim[i];
|
|
|
|
bk = 1;
|
|
for (i = 1; i < p2->u.tensor->ndim; i++)
|
|
bk *= p2->u.tensor->dim[i];
|
|
|
|
p3 = alloc_tensor(ak * bk);
|
|
|
|
c = p3->u.tensor->elem;
|
|
|
|
// new method copied from ginac
|
|
#if 1
|
|
for (i = 0; i < ak; i++) {
|
|
for (j = 0; j < n; j++) {
|
|
if (iszero(a[i * n + j]))
|
|
continue;
|
|
for (k = 0; k < bk; k++) {
|
|
push(a[i * n + j]);
|
|
push(b[j * bk + k]);
|
|
multiply();
|
|
push(c[i * bk + k]);
|
|
add();
|
|
c[i * bk + k] = pop();
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
for (i = 0; i < ak; i++) {
|
|
for (j = 0; j < bk; j++) {
|
|
push(zero);
|
|
for (k = 0; k < n; k++) {
|
|
push(a[i * n + k]);
|
|
push(b[k * bk + j]);
|
|
multiply();
|
|
add();
|
|
}
|
|
c[i * bk + j] = pop();
|
|
}
|
|
}
|
|
#endif
|
|
//---------------------------------------------------------------------
|
|
//
|
|
// Note on understanding "k * bk + j"
|
|
//
|
|
// k * bk because each element of a column is bk locations apart
|
|
//
|
|
// + j because the beginnings of all columns are in the first bk
|
|
// locations
|
|
//
|
|
// Example: n = 2, bk = 6
|
|
//
|
|
// b111 <- 1st element of 1st column
|
|
// b112 <- 1st element of 2nd column
|
|
// b113 <- 1st element of 3rd column
|
|
// b121 <- 1st element of 4th column
|
|
// b122 <- 1st element of 5th column
|
|
// b123 <- 1st element of 6th column
|
|
//
|
|
// b211 <- 2nd element of 1st column
|
|
// b212 <- 2nd element of 2nd column
|
|
// b213 <- 2nd element of 3rd column
|
|
// b221 <- 2nd element of 4th column
|
|
// b222 <- 2nd element of 5th column
|
|
// b223 <- 2nd element of 6th column
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
if (ndim == 0)
|
|
push(p3->u.tensor->elem[0]);
|
|
else {
|
|
p3->u.tensor->ndim = ndim;
|
|
for (i = 0; i < p1->u.tensor->ndim - 1; i++)
|
|
p3->u.tensor->dim[i] = p1->u.tensor->dim[i];
|
|
j = i;
|
|
for (i = 0; i < p2->u.tensor->ndim - 1; i++)
|
|
p3->u.tensor->dim[j + i] = p2->u.tensor->dim[i + 1];
|
|
push(p3);
|
|
}
|
|
}
|
|
|
|
#if SELFTEST
|
|
|
|
static char *s[] = {
|
|
|
|
"inner(a,b)",
|
|
"a*b",
|
|
|
|
"inner(a,(b1,b2))",
|
|
"(a*b1,a*b2)",
|
|
|
|
"inner((a1,a2),b)",
|
|
"(a1*b,a2*b)",
|
|
|
|
"inner(((a11,a12),(a21,a22)),(x1,x2))",
|
|
"(a11*x1+a12*x2,a21*x1+a22*x2)",
|
|
|
|
"inner((1,2),(3,4))",
|
|
"11",
|
|
|
|
"inner(inner((1,2),((3,4),(5,6))),(7,8))",
|
|
"219",
|
|
|
|
"inner((1,2),inner(((3,4),(5,6)),(7,8)))",
|
|
"219",
|
|
|
|
"inner((1,2),((3,4),(5,6)),(7,8))",
|
|
"219",
|
|
};
|
|
|
|
void
|
|
test_inner(void)
|
|
{
|
|
test(__FILE__, s, sizeof s / sizeof (char *));
|
|
}
|
|
|
|
#endif
|