-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy patheval_tensor.c
127 lines (88 loc) · 2.06 KB
/
eval_tensor.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
void
eval_tensor(struct atom *p1)
{
int i;
p1 = copy_tensor(p1);
for (i = 0; i < p1->u.tensor->nelem; i++) {
push(p1->u.tensor->elem[i]);
evalf();
p1->u.tensor->elem[i] = pop();
}
push(p1);
promote_tensor();
}
// tensors with elements that are also tensors get promoted to a higher rank
void
promote_tensor(void)
{
int i, j, k, ndim1, ndim2, nelem1, nelem2;
struct atom *p1, *p2, *p3;
p1 = pop();
if (!istensor(p1)) {
push(p1);
return;
}
ndim1 = p1->u.tensor->ndim;
nelem1 = p1->u.tensor->nelem;
// check
p2 = p1->u.tensor->elem[0];
for (i = 1; i < nelem1; i++) {
p3 = p1->u.tensor->elem[i];
if (!compatible_dimensions(p2, p3))
stopf("tensor dimensions");
}
if (!istensor(p2)) {
push(p1);
return; // all elements are scalars
}
ndim2 = p2->u.tensor->ndim;
nelem2 = p2->u.tensor->nelem;
if (ndim1 + ndim2 > MAXDIM)
stopf("rank exceeds max");
// alloc
p3 = alloc_tensor(nelem1 * nelem2);
// merge dimensions
k = 0;
for (i = 0; i < ndim1; i++)
p3->u.tensor->dim[k++] = p1->u.tensor->dim[i];
for (i = 0; i < ndim2; i++)
p3->u.tensor->dim[k++] = p2->u.tensor->dim[i];
p3->u.tensor->ndim = ndim1 + ndim2;
// merge elements
k = 0;
for (i = 0; i < nelem1; i++) {
p2 = p1->u.tensor->elem[i];
for (j = 0; j < nelem2; j++)
p3->u.tensor->elem[k++] = p2->u.tensor->elem[j];
}
push(p3);
}
int
compatible_dimensions(struct atom *p, struct atom *q)
{
int i, n;
if (!istensor(p) && !istensor(q))
return 1; // both p and q are scalars
if (!istensor(p) || !istensor(q))
return 0; // scalar and tensor
n = p->u.tensor->ndim;
if (n != q->u.tensor->ndim)
return 0;
for (i = 0; i < n; i++)
if (p->u.tensor->dim[i] != q->u.tensor->dim[i])
return 0;
return 1;
}
struct atom *
copy_tensor(struct atom *p1)
{
int i;
struct atom *p2;
p2 = alloc_tensor(p1->u.tensor->nelem);
p2->u.tensor->ndim = p1->u.tensor->ndim;
for (i = 0; i < p1->u.tensor->ndim; i++)
p2->u.tensor->dim[i] = p1->u.tensor->dim[i];
for (i = 0; i < p1->u.tensor->nelem; i++)
p2->u.tensor->elem[i] = p1->u.tensor->elem[i];
return p2;
}