2023-02-24 19:10:32 +01:00
|
|
|
#include "tensor.h"
|
2023-05-07 16:58:49 +02:00
|
|
|
#include "tensoriterator.h"
|
2023-04-11 20:39:14 +02:00
|
|
|
|
2023-02-24 19:10:32 +01:00
|
|
|
tensor tensor_new(void)
|
|
|
|
|
{
|
|
|
|
|
return calloc(1, sizeof(struct _tensor));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tensor_destroy(tensor t)
|
|
|
|
|
{
|
|
|
|
|
if (!tensor_is_empty(t)) {
|
|
|
|
|
free(t->size);
|
|
|
|
|
free(t->elements);
|
2023-03-13 15:45:30 +01:00
|
|
|
free(t->index_offsets);
|
2023-02-24 19:10:32 +01:00
|
|
|
}
|
2023-03-13 15:45:30 +01:00
|
|
|
free(t);
|
2023-02-24 19:10:32 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t tensor_is_empty(const tensor t)
|
2023-03-12 20:29:55 +01:00
|
|
|
{
|
2023-02-24 19:10:32 +01:00
|
|
|
return t->elements == NULL || t->size == NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t tensor_is_equal(const tensor t1, const tensor t2)
|
2023-03-12 20:29:55 +01:00
|
|
|
{
|
2023-03-13 15:45:30 +01:00
|
|
|
assert(!tensor_is_empty(t1));
|
|
|
|
|
assert(!tensor_is_empty(t2));
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint32_t i;
|
2023-05-07 13:31:04 +02:00
|
|
|
if (t1->rank != t2->rank) return 0;
|
|
|
|
|
for (i = 0; i < t1->rank; i++) {
|
2023-03-12 20:29:55 +01:00
|
|
|
if (t1->size[i] != t2->size[i]) return 0;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < t1->num_elem; i++) {
|
2023-04-11 17:51:01 +02:00
|
|
|
if (DTYPE_NE(t1->elements[i], t2->elements[i])) return 0;
|
2023-03-12 20:29:55 +01:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t _tensor_check_size(const uint32_t *size, uint8_t rank)
|
2023-02-24 19:10:32 +01:00
|
|
|
{
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t i;
|
|
|
|
|
if(rank < 0) return 0;
|
|
|
|
|
for(i = 0; i < rank; i++) {
|
2023-02-24 19:10:32 +01:00
|
|
|
if(size[i] < 1) return 0;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t _tensor_set_size(tensor t, const uint32_t *size, uint8_t rank)
|
2023-02-24 19:10:32 +01:00
|
|
|
{
|
2023-03-13 15:45:30 +01:00
|
|
|
/* Sets the size of a Tensor. During this process all data in the tensor t is lost. */
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint32_t *temp_size;
|
|
|
|
|
uint32_t *temp_index_offset;
|
|
|
|
|
dtype *temp_elements;
|
|
|
|
|
uint8_t i, j;
|
|
|
|
|
uint32_t num_elem = 1;
|
2023-03-13 15:45:30 +01:00
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
if(!_tensor_check_size(size, rank)) return 0;
|
2023-02-24 19:10:32 +01:00
|
|
|
|
2023-03-13 15:45:30 +01:00
|
|
|
/* Try allocating memory for the size/ index_offset array of the tensor */
|
2023-05-07 14:38:41 +02:00
|
|
|
for(i = 0; i < rank; i++) {
|
2023-02-24 19:10:32 +01:00
|
|
|
num_elem *= size[i];
|
|
|
|
|
}
|
2023-05-07 14:38:41 +02:00
|
|
|
temp_size = malloc(rank * sizeof(uint32_t));
|
|
|
|
|
temp_index_offset = malloc(rank * sizeof(uint32_t));
|
|
|
|
|
temp_elements = malloc(num_elem * sizeof(dtype));
|
|
|
|
|
if((temp_size == NULL && rank != 0) || (temp_index_offset == NULL && rank != 0) || temp_elements == NULL) {
|
|
|
|
|
free(temp_size);
|
|
|
|
|
free(temp_index_offset);
|
2023-02-24 19:10:32 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-13 15:45:30 +01:00
|
|
|
/* Freeing old memory. */
|
|
|
|
|
free(t->size);
|
|
|
|
|
free(t->index_offsets);
|
|
|
|
|
free(t->elements);
|
|
|
|
|
|
2023-02-24 19:10:32 +01:00
|
|
|
/* Setting the size array */
|
2023-05-07 14:38:41 +02:00
|
|
|
t->size = temp_size;
|
|
|
|
|
if(rank != 0) memcpy(t->size, size, rank * sizeof(uint32_t));
|
|
|
|
|
t->rank = rank;
|
2023-03-13 15:45:30 +01:00
|
|
|
/* Setting the index_offset array */
|
2023-05-07 14:38:41 +02:00
|
|
|
t->index_offsets = temp_index_offset;
|
2023-05-07 13:31:04 +02:00
|
|
|
for(i = 0; i < t->rank; i++) {
|
2023-03-13 15:45:30 +01:00
|
|
|
t->index_offsets[i] = 1;
|
2023-05-07 13:31:04 +02:00
|
|
|
for(j = i + 1; j < t->rank; j++) {
|
2023-03-13 15:45:30 +01:00
|
|
|
t->index_offsets[i] *= t->size[j];
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-24 19:10:32 +01:00
|
|
|
/* Setting the elements pointer and memory usage */
|
2023-05-07 14:38:41 +02:00
|
|
|
t->elements = temp_elements;
|
2023-02-24 19:10:32 +01:00
|
|
|
t->num_elem = num_elem;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t tensor_set(tensor t, const uint32_t *index, dtype val)
|
2023-02-24 19:10:32 +01:00
|
|
|
{
|
2023-03-13 15:45:30 +01:00
|
|
|
assert(!tensor_is_empty(t));
|
2023-03-12 21:29:10 +01:00
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t i;
|
|
|
|
|
uint32_t offset = 0;
|
2023-03-12 21:29:10 +01:00
|
|
|
|
2023-05-07 13:31:04 +02:00
|
|
|
if(t->rank == 0) {
|
2023-03-09 18:24:17 +01:00
|
|
|
t->elements[0] = val;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-02-24 19:10:32 +01:00
|
|
|
|
2023-05-07 13:31:04 +02:00
|
|
|
for(i = 0; i < t->rank; i++) {
|
2023-02-24 20:16:28 +01:00
|
|
|
if(t->size[i] <= index[i]) return 0;
|
2023-03-13 15:45:30 +01:00
|
|
|
offset += t->index_offsets[i] * index[i];
|
2023-02-24 19:10:32 +01:00
|
|
|
}
|
2023-03-12 21:29:10 +01:00
|
|
|
|
2023-02-24 19:10:32 +01:00
|
|
|
t->elements[offset] = val;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
dtype tensor_get(const tensor t, const uint32_t *index, uint8_t *success)
|
2023-02-24 19:10:32 +01:00
|
|
|
{
|
2023-03-13 15:45:30 +01:00
|
|
|
assert(!tensor_is_empty(t));
|
2023-03-12 21:29:10 +01:00
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t i;
|
|
|
|
|
uint32_t offset = 0;
|
2023-03-12 21:29:10 +01:00
|
|
|
|
2023-05-07 13:31:04 +02:00
|
|
|
if(t->rank == 0) return t->elements[0];
|
2023-02-24 19:10:32 +01:00
|
|
|
|
2023-05-07 13:31:04 +02:00
|
|
|
for(i = 0; i < t->rank; i++) {
|
2023-02-24 19:10:32 +01:00
|
|
|
if(t->size[i] <= index[i]) {
|
|
|
|
|
if(success != NULL) *success = 0;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-03-13 15:45:30 +01:00
|
|
|
offset += t->index_offsets[i] * index[i];
|
2023-02-24 19:10:32 +01:00
|
|
|
}
|
2023-02-24 20:16:28 +01:00
|
|
|
|
2023-02-24 19:10:32 +01:00
|
|
|
if(success != NULL) *success = 1;
|
|
|
|
|
return t->elements[offset];
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t tensor_init_one(tensor t, uint8_t rank, const uint32_t *size)
|
2023-02-24 19:10:32 +01:00
|
|
|
{
|
2023-05-07 14:38:41 +02:00
|
|
|
uint32_t i;
|
2023-02-24 19:10:32 +01:00
|
|
|
|
2023-05-07 13:31:04 +02:00
|
|
|
if(!_tensor_set_size(t, size, rank)) return 0;
|
2023-02-24 19:10:32 +01:00
|
|
|
for(i = 0; i < t->num_elem; i++) {
|
2023-04-11 17:51:01 +02:00
|
|
|
t->elements[i] = DTYPE_ONE;
|
2023-02-24 19:10:32 +01:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t tensor_init_zero(tensor t, uint8_t rank, const uint32_t *size)
|
2023-02-24 19:10:32 +01:00
|
|
|
{
|
2023-05-07 14:38:41 +02:00
|
|
|
uint32_t i;
|
2023-02-24 19:10:32 +01:00
|
|
|
|
2023-05-07 13:31:04 +02:00
|
|
|
if(!_tensor_set_size(t, size, rank)) return 0;
|
2023-02-24 19:10:32 +01:00
|
|
|
for(i = 0; i < t->num_elem; i++) {
|
2023-04-11 17:51:01 +02:00
|
|
|
t->elements[i] = DTYPE_ZERO;
|
2023-02-24 19:10:32 +01:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t tensor_init_rand(tensor t, uint8_t rank, const uint32_t *size, dtype max)
|
2023-02-24 19:10:32 +01:00
|
|
|
{
|
2023-05-07 14:38:41 +02:00
|
|
|
uint32_t i;
|
|
|
|
|
static long last_seed;
|
2023-02-27 14:45:21 +01:00
|
|
|
last_seed += time(NULL) * 200 + rand();
|
|
|
|
|
srand(last_seed);
|
2023-02-24 19:10:32 +01:00
|
|
|
|
2023-05-07 13:31:04 +02:00
|
|
|
if(!_tensor_set_size(t, size, rank)) return 0;
|
2023-02-24 19:10:32 +01:00
|
|
|
for(i = 0; i < t->num_elem; i++) {
|
2023-04-11 17:51:01 +02:00
|
|
|
t->elements[i] = DTYPE_RAND(max);
|
2023-02-24 19:10:32 +01:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t tensor_cpy(tensor t1, const tensor t2)
|
2023-03-18 20:52:26 +01:00
|
|
|
{
|
|
|
|
|
assert(!tensor_is_empty(t2));
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint32_t i;
|
2023-05-07 13:31:04 +02:00
|
|
|
if(!_tensor_set_size(t1, t2->size, t2->rank)) return 0;
|
2023-03-18 20:52:26 +01:00
|
|
|
for(i = 0; i < t2->num_elem; i++) {
|
|
|
|
|
t1->elements[i] = t2->elements[i];
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tensor_add_scalar(tensor t, dtype n)
|
|
|
|
|
{
|
|
|
|
|
assert(!tensor_is_empty(t));
|
|
|
|
|
|
2023-05-07 16:58:49 +02:00
|
|
|
tensoriter_scalar iter = tensoriter_scalar_create(t);
|
|
|
|
|
tensoriter_scalar_map_add(iter, n);
|
|
|
|
|
tensoriter_scalar_destroy(iter);
|
2023-03-18 20:52:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tensor_sub_scalar(tensor t, dtype n)
|
|
|
|
|
{
|
|
|
|
|
assert(!tensor_is_empty(t));
|
|
|
|
|
|
2023-05-07 16:58:49 +02:00
|
|
|
tensoriter_scalar iter = tensoriter_scalar_create(t);
|
|
|
|
|
tensoriter_scalar_map_sub(iter, n);
|
|
|
|
|
tensoriter_scalar_destroy(iter);
|
2023-03-18 20:52:26 +01:00
|
|
|
}
|
|
|
|
|
|
2023-04-11 20:39:14 +02:00
|
|
|
void tensor_mul_scalar(tensor t, dtype n)
|
2023-03-18 20:52:26 +01:00
|
|
|
{
|
|
|
|
|
assert(!tensor_is_empty(t));
|
|
|
|
|
|
2023-05-07 16:58:49 +02:00
|
|
|
tensoriter_scalar iter = tensoriter_scalar_create(t);
|
|
|
|
|
tensoriter_scalar_map_mul(iter, n);
|
|
|
|
|
tensoriter_scalar_destroy(iter);
|
2023-03-18 20:52:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tensor_div_scalar(tensor t, dtype n)
|
|
|
|
|
{
|
|
|
|
|
assert(!tensor_is_empty(t));
|
|
|
|
|
|
2023-05-07 16:58:49 +02:00
|
|
|
tensoriter_scalar iter = tensoriter_scalar_create(t);
|
|
|
|
|
tensoriter_scalar_map_div(iter, n);
|
|
|
|
|
tensoriter_scalar_destroy(iter);
|
2023-03-18 20:52:26 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t tensor_add_inplace(tensor t1, const tensor t2)
|
2023-02-24 19:10:32 +01:00
|
|
|
{
|
2023-03-13 15:45:30 +01:00
|
|
|
assert(!tensor_is_empty(t1));
|
|
|
|
|
assert(!tensor_is_empty(t2));
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint32_t i;
|
2023-05-07 13:31:04 +02:00
|
|
|
if(t1->rank != t2->rank) return 0;
|
|
|
|
|
for(i = 0; i < t1->rank; i++) {
|
2023-02-27 14:45:21 +01:00
|
|
|
if(t1->size[i] != t2->size[i]) return 0;
|
|
|
|
|
}
|
|
|
|
|
for(i = 0; i < t1->num_elem; i++) {
|
2023-04-11 17:51:01 +02:00
|
|
|
t1->elements[i] = DTYPE_ADD(t1->elements[i], t2->elements[i]);
|
2023-03-18 20:56:40 +01:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint8_t tensor_sub_inplace(tensor t1, const tensor t2)
|
2023-03-18 20:56:40 +01:00
|
|
|
{
|
|
|
|
|
assert(!tensor_is_empty(t1));
|
|
|
|
|
assert(!tensor_is_empty(t2));
|
|
|
|
|
|
2023-05-07 14:38:41 +02:00
|
|
|
uint32_t i;
|
2023-05-07 13:31:04 +02:00
|
|
|
if(t1->rank != t2->rank) return 0;
|
|
|
|
|
for(i = 0; i < t1->rank; i++) {
|
2023-03-18 20:56:40 +01:00
|
|
|
if(t1->size[i] != t2->size[i]) return 0;
|
|
|
|
|
}
|
|
|
|
|
for(i = 0; i < t1->num_elem; i++) {
|
2023-04-11 17:51:01 +02:00
|
|
|
t1->elements[i] = DTYPE_SUB(t1->elements[i], t2->elements[i]);
|
2023-02-27 14:45:21 +01:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-02-24 19:10:32 +01:00
|
|
|
|
2023-04-11 20:55:16 +02:00
|
|
|
tensor tensor_add(const tensor t1, const tensor t2)
|
|
|
|
|
{
|
|
|
|
|
assert(!tensor_is_empty(t1));
|
|
|
|
|
assert(!tensor_is_empty(t2));
|
|
|
|
|
|
|
|
|
|
tensor t3 = tensor_new();
|
|
|
|
|
if(t3 == NULL) return NULL;
|
|
|
|
|
if (!tensor_cpy(t3, t1)) return NULL;
|
|
|
|
|
if (!tensor_add_inplace(t3, t2)) return NULL;
|
|
|
|
|
return t3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tensor tensor_sub(const tensor t1, const tensor t2)
|
|
|
|
|
{
|
|
|
|
|
assert(!tensor_is_empty(t1));
|
|
|
|
|
assert(!tensor_is_empty(t2));
|
|
|
|
|
|
|
|
|
|
tensor t3 = tensor_new();
|
|
|
|
|
if(t3 == NULL) return NULL;
|
|
|
|
|
if (!tensor_cpy(t3, t1)) return NULL;
|
|
|
|
|
if (!tensor_sub_inplace(t3, t2)) return NULL;
|
|
|
|
|
return t3;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-24 19:17:31 +01:00
|
|
|
void tensor_print(const tensor t)
|
2023-02-24 19:10:32 +01:00
|
|
|
{
|
2023-05-07 14:38:41 +02:00
|
|
|
uint32_t i, j;
|
|
|
|
|
uint32_t *indx;
|
2023-02-24 19:10:32 +01:00
|
|
|
|
|
|
|
|
if(tensor_is_empty(t)){
|
|
|
|
|
printf("<empty tensor>\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-07 13:31:04 +02:00
|
|
|
printf("Tensor of rank %i and size (", t->rank);
|
|
|
|
|
for(i = 0; i < t->rank - 1; i++) {
|
2023-02-24 19:10:32 +01:00
|
|
|
printf("%i, ", t->size[i]);
|
|
|
|
|
}
|
2023-05-07 13:31:04 +02:00
|
|
|
if(t->rank == 0) printf("): ");
|
|
|
|
|
else printf("%i): ", t->size[t->rank - 1]);
|
2023-02-24 19:10:32 +01:00
|
|
|
|
|
|
|
|
|
2023-05-07 13:31:04 +02:00
|
|
|
if(t->rank == 0) {
|
2023-03-09 18:24:17 +01:00
|
|
|
/* scalar */
|
2023-04-11 17:51:01 +02:00
|
|
|
DTYPE_PRINT(t->elements[0]);
|
2023-02-24 19:10:32 +01:00
|
|
|
putchar('\n');
|
2023-05-07 13:31:04 +02:00
|
|
|
} else if (t->rank == 1) {
|
2023-03-09 18:24:17 +01:00
|
|
|
/* column vector */
|
2023-02-24 19:10:32 +01:00
|
|
|
if(t->size[0] == 1) {
|
|
|
|
|
putchar('(');
|
2023-04-11 17:51:01 +02:00
|
|
|
DTYPE_PRINT(t->elements[0]);
|
2023-02-24 19:10:32 +01:00
|
|
|
printf(")\n");
|
|
|
|
|
} else {
|
|
|
|
|
printf("\n/");
|
2023-04-11 17:51:01 +02:00
|
|
|
DTYPE_PRINT(t->elements[0]);
|
2023-02-24 19:10:32 +01:00
|
|
|
printf("\\\n");
|
|
|
|
|
for(i = 1; i < t->size[0] - 1; i++) {
|
|
|
|
|
putchar('|');
|
2023-04-11 17:51:01 +02:00
|
|
|
DTYPE_PRINT(t->elements[i]);
|
2023-02-24 19:10:32 +01:00
|
|
|
printf("|\n");
|
|
|
|
|
}
|
|
|
|
|
printf("\\");
|
2023-04-11 17:51:01 +02:00
|
|
|
DTYPE_PRINT(t->elements[t->size[0] - 1]);
|
2023-02-24 19:10:32 +01:00
|
|
|
printf("/\n");
|
|
|
|
|
}
|
2023-05-07 13:31:04 +02:00
|
|
|
} else if (t->rank == 2) {
|
2023-03-09 18:24:17 +01:00
|
|
|
/* matix */
|
2023-02-24 19:10:32 +01:00
|
|
|
indx = malloc(sizeof(int) * 2);
|
|
|
|
|
if(t->size[0] == 1) {
|
|
|
|
|
putchar('(');
|
2023-02-24 20:16:28 +01:00
|
|
|
indx[0] = 0;
|
2023-02-24 19:10:32 +01:00
|
|
|
for(i = 0; i < t->size[1]; i++) {
|
2023-02-24 20:16:28 +01:00
|
|
|
indx[1] = i;
|
2023-04-11 17:51:01 +02:00
|
|
|
DTYPE_PRINT(tensor_get(t, indx, NULL));
|
2023-02-24 19:10:32 +01:00
|
|
|
}
|
|
|
|
|
printf(")\n");
|
|
|
|
|
} else {
|
|
|
|
|
printf("\n/");
|
2023-02-24 20:16:28 +01:00
|
|
|
indx[0] = 0;
|
2023-02-24 19:10:32 +01:00
|
|
|
for(i = 0; i < t->size[1]; i++) {
|
2023-02-24 20:16:28 +01:00
|
|
|
indx[1] = i;
|
2023-04-11 17:51:01 +02:00
|
|
|
DTYPE_PRINT(tensor_get(t, indx, NULL));
|
2023-02-24 19:10:32 +01:00
|
|
|
}
|
|
|
|
|
printf("\\\n");
|
|
|
|
|
for(i = 1; i < t->size[0] - 1; i++) {
|
|
|
|
|
putchar('|');
|
2023-02-24 20:16:28 +01:00
|
|
|
indx[0] = i;
|
2023-02-24 19:10:32 +01:00
|
|
|
for(j = 0; j < t->size[1]; j++) {
|
2023-02-24 20:16:28 +01:00
|
|
|
indx[1] = j;
|
2023-04-11 17:51:01 +02:00
|
|
|
DTYPE_PRINT(tensor_get(t, indx, NULL));
|
2023-02-24 19:10:32 +01:00
|
|
|
}
|
|
|
|
|
printf("|\n");
|
|
|
|
|
}
|
|
|
|
|
printf("\\");
|
2023-02-24 20:16:28 +01:00
|
|
|
indx[0] = t->size[0] - 1;
|
2023-02-24 19:10:32 +01:00
|
|
|
for(i = 0; i < t->size[1]; i++) {
|
2023-02-24 20:16:28 +01:00
|
|
|
indx[1] = i;
|
2023-04-11 17:51:01 +02:00
|
|
|
DTYPE_PRINT(tensor_get(t, indx, NULL));
|
2023-02-24 19:10:32 +01:00
|
|
|
}
|
|
|
|
|
printf("/\n");
|
|
|
|
|
}
|
|
|
|
|
free(indx);
|
|
|
|
|
} else {
|
2023-04-11 17:51:01 +02:00
|
|
|
putchar('[');
|
|
|
|
|
for(i = 0; i < t->num_elem; i++) {
|
|
|
|
|
DTYPE_PRINT(t->elements[i]);
|
|
|
|
|
}
|
|
|
|
|
putchar(']');
|
|
|
|
|
putchar('\n');
|
2023-02-24 19:10:32 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|