5 static void promote_tensor(void);
6 static int compatible(U
*, U
*);
8 //-----------------------------------------------------------------------------
10 // Called from the "eval" module to evaluate tensor elements.
12 // p1 points to the tensor operand.
14 //-----------------------------------------------------------------------------
22 //---------------------------------------------------------------------
24 // create a new tensor for the result
26 //---------------------------------------------------------------------
28 nelem
= p1
->u
.tensor
->nelem
;
30 ndim
= p1
->u
.tensor
->ndim
;
32 p2
= alloc_tensor(nelem
);
34 p2
->u
.tensor
->ndim
= ndim
;
36 for (i
= 0; i
< ndim
; i
++)
37 p2
->u
.tensor
->dim
[i
] = p1
->u
.tensor
->dim
[i
];
39 //---------------------------------------------------------------------
43 //---------------------------------------------------------------------
45 a
= p1
->u
.tensor
->elem
;
46 b
= p2
->u
.tensor
->elem
;
48 for (i
= 0; i
< nelem
; i
++) {
54 //---------------------------------------------------------------------
58 //---------------------------------------------------------------------
65 //-----------------------------------------------------------------------------
69 // Input: Operands on stack
71 // Output: Result on stack
73 //-----------------------------------------------------------------------------
76 tensor_plus_tensor(void)
86 // are the dimension lists equal?
88 ndim
= p1
->u
.tensor
->ndim
;
90 if (ndim
!= p2
->u
.tensor
->ndim
) {
96 for (i
= 0; i
< ndim
; i
++)
97 if (p1
->u
.tensor
->dim
[i
] != p2
->u
.tensor
->dim
[i
]) {
103 // create a new tensor for the result
105 nelem
= p1
->u
.tensor
->nelem
;
107 p3
= alloc_tensor(nelem
);
109 p3
->u
.tensor
->ndim
= ndim
;
111 for (i
= 0; i
< ndim
; i
++)
112 p3
->u
.tensor
->dim
[i
] = p1
->u
.tensor
->dim
[i
];
116 a
= p1
->u
.tensor
->elem
;
117 b
= p2
->u
.tensor
->elem
;
118 c
= p3
->u
.tensor
->elem
;
120 for (i
= 0; i
< nelem
; i
++) {
134 //-----------------------------------------------------------------------------
136 // careful not to reorder factors
138 //-----------------------------------------------------------------------------
141 tensor_times_scalar(void)
151 ndim
= p1
->u
.tensor
->ndim
;
152 nelem
= p1
->u
.tensor
->nelem
;
154 p3
= alloc_tensor(nelem
);
156 p3
->u
.tensor
->ndim
= ndim
;
158 for (i
= 0; i
< ndim
; i
++)
159 p3
->u
.tensor
->dim
[i
] = p1
->u
.tensor
->dim
[i
];
161 a
= p1
->u
.tensor
->elem
;
162 b
= p3
->u
.tensor
->elem
;
164 for (i
= 0; i
< nelem
; i
++) {
176 scalar_times_tensor(void)
186 ndim
= p2
->u
.tensor
->ndim
;
187 nelem
= p2
->u
.tensor
->nelem
;
189 p3
= alloc_tensor(nelem
);
191 p3
->u
.tensor
->ndim
= ndim
;
193 for (i
= 0; i
< ndim
; i
++)
194 p3
->u
.tensor
->dim
[i
] = p2
->u
.tensor
->dim
[i
];
196 a
= p2
->u
.tensor
->elem
;
197 b
= p3
->u
.tensor
->elem
;
199 for (i
= 0; i
< nelem
; i
++) {
212 is_square_matrix(U
*p
)
214 if (istensor(p
) && p
->u
.tensor
->ndim
== 2 && p
->u
.tensor
->dim
[0] == p
->u
.tensor
->dim
[1])
220 //-----------------------------------------------------------------------------
222 // gradient of tensor
224 //-----------------------------------------------------------------------------
227 d_tensor_tensor(void)
229 int i
, j
, ndim
, nelem
;
232 ndim
= p1
->u
.tensor
->ndim
;
233 nelem
= p1
->u
.tensor
->nelem
;
235 if (ndim
+ 1 >= MAXDIM
)
238 p3
= alloc_tensor(nelem
* p2
->u
.tensor
->nelem
);
240 p3
->u
.tensor
->ndim
= ndim
+ 1;
242 for (i
= 0; i
< ndim
; i
++)
243 p3
->u
.tensor
->dim
[i
] = p1
->u
.tensor
->dim
[i
];
245 p3
->u
.tensor
->dim
[ndim
] = p2
->u
.tensor
->dim
[0];
247 a
= p1
->u
.tensor
->elem
;
248 b
= p2
->u
.tensor
->elem
;
249 c
= p3
->u
.tensor
->elem
;
251 for (i
= 0; i
< nelem
; i
++) {
252 for (j
= 0; j
< p2
->u
.tensor
->nelem
; j
++) {
256 c
[i
* p2
->u
.tensor
->nelem
+ j
] = pop();
266 push_symbol(DERIVATIVE
);
272 //-----------------------------------------------------------------------------
274 // gradient of scalar
276 //-----------------------------------------------------------------------------
279 d_scalar_tensor(void)
284 p3
= alloc_tensor(p2
->u
.tensor
->nelem
);
286 p3
->u
.tensor
->ndim
= 1;
288 p3
->u
.tensor
->dim
[0] = p2
->u
.tensor
->dim
[0];
290 a
= p2
->u
.tensor
->elem
;
291 b
= p3
->u
.tensor
->elem
;
293 for (i
= 0; i
< p2
->u
.tensor
->nelem
; i
++) {
303 //-----------------------------------------------------------------------------
305 // Derivative of tensor
307 //-----------------------------------------------------------------------------
310 d_tensor_scalar(void)
315 p3
= alloc_tensor(p1
->u
.tensor
->nelem
);
317 p3
->u
.tensor
->ndim
= p1
->u
.tensor
->ndim
;
319 for (i
= 0; i
< p1
->u
.tensor
->ndim
; i
++)
320 p3
->u
.tensor
->dim
[i
] = p1
->u
.tensor
->dim
[i
];
322 a
= p1
->u
.tensor
->elem
;
323 b
= p3
->u
.tensor
->elem
;
325 for (i
= 0; i
< p1
->u
.tensor
->nelem
; i
++) {
336 compare_tensors(U
*p1
, U
*p2
)
340 if (p1
->u
.tensor
->ndim
< p2
->u
.tensor
->ndim
)
343 if (p1
->u
.tensor
->ndim
> p2
->u
.tensor
->ndim
)
346 for (i
= 0; i
< p1
->u
.tensor
->ndim
; i
++) {
347 if (p1
->u
.tensor
->dim
[i
] < p2
->u
.tensor
->dim
[i
])
349 if (p1
->u
.tensor
->dim
[i
] > p2
->u
.tensor
->dim
[i
])
353 for (i
= 0; i
< p1
->u
.tensor
->nelem
; i
++) {
354 if (equal(p1
->u
.tensor
->elem
[i
], p2
->u
.tensor
->elem
[i
]))
356 if (lessp(p1
->u
.tensor
->elem
[i
], p2
->u
.tensor
->elem
[i
]))
365 //-----------------------------------------------------------------------------
367 // Raise a tensor to a power
373 // Output: Result on stack
375 //-----------------------------------------------------------------------------
382 // first and last dims must be equal
384 k
= p1
->u
.tensor
->ndim
- 1;
386 if (p1
->u
.tensor
->dim
[0] != p1
->u
.tensor
->dim
[k
]) {
398 if (n
== (int) 0x80000000) {
407 if (p1
->u
.tensor
->ndim
!= 2)
408 stop("power(tensor,0) with tensor rank not equal to 2");
409 n
= p1
->u
.tensor
->dim
[0];
410 p1
= alloc_tensor(n
* n
);
411 p1
->u
.tensor
->ndim
= 2;
412 p1
->u
.tensor
->dim
[0] = n
;
413 p1
->u
.tensor
->dim
[1] = n
;
414 for (i
= 0; i
< n
; i
++)
415 p1
->u
.tensor
->elem
[n
* i
+ i
] = one
;
429 for (i
= 1; i
< n
; i
++) {
432 if (iszero(stack
[tos
- 1]))
446 p2
= alloc_tensor(p1
->u
.tensor
->nelem
);
448 p2
->u
.tensor
->ndim
= p1
->u
.tensor
->ndim
;
450 for (i
= 0; i
< p1
->u
.tensor
->ndim
; i
++)
451 p2
->u
.tensor
->dim
[i
] = p1
->u
.tensor
->dim
[i
];
453 for (i
= 0; i
< p1
->u
.tensor
->nelem
; i
++)
454 p2
->u
.tensor
->elem
[i
] = p1
->u
.tensor
->elem
[i
];
461 // Tensors with elements that are also tensors get promoted to a higher rank.
466 int i
, j
, k
, nelem
, ndim
;
478 p2
= p1
->u
.tensor
->elem
[0];
480 for (i
= 1; i
< p1
->u
.tensor
->nelem
; i
++)
481 if (!compatible(p2
, p1
->u
.tensor
->elem
[i
]))
482 stop("Cannot promote tensor due to inconsistent tensor components.");
490 ndim
= p1
->u
.tensor
->ndim
+ p2
->u
.tensor
->ndim
;
493 stop("tensor rank > 24");
495 nelem
= p1
->u
.tensor
->nelem
* p2
->u
.tensor
->nelem
;
497 p3
= alloc_tensor(nelem
);
499 p3
->u
.tensor
->ndim
= ndim
;
501 for (i
= 0; i
< p1
->u
.tensor
->ndim
; i
++)
502 p3
->u
.tensor
->dim
[i
] = p1
->u
.tensor
->dim
[i
];
504 for (j
= 0; j
< p2
->u
.tensor
->ndim
; j
++)
505 p3
->u
.tensor
->dim
[i
+ j
] = p2
->u
.tensor
->dim
[j
];
509 for (i
= 0; i
< p1
->u
.tensor
->nelem
; i
++) {
510 p2
= p1
->u
.tensor
->elem
[i
];
511 for (j
= 0; j
< p2
->u
.tensor
->nelem
; j
++)
512 p3
->u
.tensor
->elem
[k
++] = p2
->u
.tensor
->elem
[j
];
521 compatible(U
*p
, U
*q
)
525 if (!istensor(p
) && !istensor(q
))
528 if (!istensor(p
) || !istensor(q
))
531 if (p
->u
.tensor
->ndim
!= q
->u
.tensor
->ndim
)
534 for (i
= 0; i
< p
->u
.tensor
->ndim
; i
++)
535 if (p
->u
.tensor
->dim
[i
] != q
->u
.tensor
->dim
[i
])
560 "((1,2,3),(4,5,6),(7,8,9))",
562 // check tensor promotion
580 test(__FILE__
, s
, sizeof s
/ sizeof (char *));