Files
ctensor/tensor.c

361 lines
8.5 KiB
C
Raw Normal View History

#include "tensor.h"
tensor tensor_new(void)
{
2023-09-03 09:45:20 +02:00
/* Creates a new tensor struct and returns it.
*
* @return A tensor (pointer to memory for a _tensor struct), if an error
* occurs NULL is returned
2023-09-03 09:45:20 +02:00
*/
return calloc(1, sizeof(struct _tensor));
}
void tensor_destroy(tensor t)
{
2023-09-03 09:45:20 +02:00
/* Destroys a tensor struct by free its memory.
*
* @param t The tensor that should be deleted
*/
if (!tensor_is_empty(t)) {
free(t->size);
free(t->elements);
free(t->stride);
}
free(t);
}
2023-05-08 17:06:49 +02:00
bool tensor_is_empty(const tensor t)
2023-03-12 20:29:55 +01:00
{
2023-09-03 09:45:20 +02:00
/* Checks whether a tensor is empty.
*
* @param t The tensor to check
*
* @return true when the tensor is empty, false otherwise
*/
return t->elements == NULL || t->size == NULL;
}
2023-05-08 17:06:49 +02:00
bool tensor_is_equal(const tensor t1, const tensor t2)
2023-03-12 20:29:55 +01:00
{
2023-09-03 09:45:20 +02:00
/* Checks whether two tensor are equal.
*
* @param t1 The first tensor
* @param t2 The seconds tensor
*
* @return true when the two tensors are equal, false otherwise
*/
assert(!tensor_is_empty(t1));
assert(!tensor_is_empty(t2));
2023-05-08 17:06:49 +02:00
if (t1->rank != t2->rank) return false;
if (!tarray_uint32_equals(t1->size, t2->size, t1->rank)) return false;
return tarray_equals(t1->elements, t2->elements, t1->num_elem);
2023-03-12 20:29:55 +01:00
}
2023-09-03 09:45:20 +02:00
bool _tensor_check_size(const uint32_t *size, uint8_t rank)
{
2023-09-03 09:45:20 +02:00
/* Checks whether a size array is valid.
*
* @param size A size array
* @param rank The length of the size array
*
* @return true when the size is valid, false otherwise
*/
2023-05-07 14:38:41 +02:00
uint8_t i;
2023-09-03 09:45:20 +02:00
if(rank < 0) return false;
2023-05-07 14:38:41 +02:00
for(i = 0; i < rank; i++) {
2023-09-03 09:45:20 +02:00
if(size[i] < 1) return false;
}
2023-09-03 09:45:20 +02:00
return true;
}
2023-09-03 09:45:20 +02:00
bool _tensor_set_size(tensor t, const uint32_t *size, uint8_t rank)
{
2023-09-03 09:45:20 +02:00
/* Sets the size of a Tensor. During this process all data in the tensor t
* is lost.
*
* @param t The tensor that should be changed
* @param size The final size of the tensor t
* @param rank The length of size
*
* @return true if the process was successful, false when an error occured
*/
2023-05-07 14:38:41 +02:00
uint32_t *temp_size;
uint32_t *temp_stride;
2023-05-07 14:38:41 +02:00
dtype *temp_elements;
uint8_t i;
2023-05-07 14:38:41 +02:00
uint32_t num_elem = 1;
2023-09-03 09:45:20 +02:00
if(!_tensor_check_size(size, rank)) return false;
/* Try allocating memory for the size/ stride array of the tensor */
2023-05-07 14:38:41 +02:00
for(i = 0; i < rank; i++) {
num_elem *= size[i];
}
2023-05-07 14:38:41 +02:00
temp_size = malloc(rank * sizeof(uint32_t));
temp_stride = malloc(rank * sizeof(uint32_t));
2023-05-07 14:38:41 +02:00
temp_elements = malloc(num_elem * sizeof(dtype));
if((temp_size == NULL && rank != 0) || (temp_stride == NULL && rank != 0) || temp_elements == NULL) {
2023-05-07 14:38:41 +02:00
free(temp_size);
free(temp_stride);
2023-09-03 09:45:20 +02:00
return false;
}
/* Freeing old memory. */
free(t->size);
free(t->stride);
free(t->elements);
/* 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;
/* Setting the stride array */
t->stride = temp_stride;
t->stride[0] = 1;
for(i = 1; i < t->rank; i++) {
t->stride[i] = t->stride[i - 1] * t->size[i - 1];
}
/* Setting the elements pointer and memory usage */
2023-05-07 14:38:41 +02:00
t->elements = temp_elements;
t->num_elem = num_elem;
2023-09-03 09:45:20 +02:00
return true;
}
2023-09-03 09:45:20 +02:00
bool tensor_set(tensor t, const uint32_t *index, dtype val)
{
2023-09-03 09:45:20 +02:00
/* Set the value at a index of a tensor.
*
* @param t The tensor to change
* @param index The index of the value that should change, the length of
* this array is defined by the rank of t
* @param val The updated value
*
* @return true if the change was successful, false otherwise
*/
assert(!tensor_is_empty(t));
2023-05-07 14:38:41 +02:00
uint8_t i;
uint32_t offset = 0;
2023-05-07 13:31:04 +02:00
if(t->rank == 0) {
2023-03-09 18:24:17 +01:00
t->elements[0] = val;
2023-09-03 09:45:20 +02:00
return true;
2023-03-09 18:24:17 +01:00
}
2023-05-07 13:31:04 +02:00
for(i = 0; i < t->rank; i++) {
2023-09-03 09:45:20 +02:00
if(t->size[i] <= index[i]) return false;
offset += t->stride[i] * index[i];
}
t->elements[offset] = val;
2023-09-03 09:45:20 +02:00
return true;
}
2023-09-03 09:45:20 +02:00
dtype tensor_get(const tensor t, const uint32_t *index, bool *success)
{
2023-09-03 09:45:20 +02:00
/* Gets a value at a index from a tensor.
*
* @param t The tensor from which to get the value from
* @param index The index of the value to get, the length of this array is
* defined by the rank of t
* @param success Is set according to the exit status of the function, if it
* is NULL it is ignored
*
* @return The retrieved value, DTYPE_NULL in case of an error
*/
assert(!tensor_is_empty(t));
2023-05-07 14:38:41 +02:00
uint8_t i;
uint32_t offset = 0;
2023-05-07 13:31:04 +02:00
if(t->rank == 0) return t->elements[0];
2023-05-07 13:31:04 +02:00
for(i = 0; i < t->rank; i++) {
if(t->size[i] <= index[i]) {
2023-09-03 09:45:20 +02:00
if(success != NULL) *success = false;
return DTYPE_ZERO;
}
offset += t->stride[i] * index[i];
}
2023-02-24 20:16:28 +01:00
2023-09-03 09:45:20 +02:00
if(success != NULL) *success = true;
return t->elements[offset];
}
2023-09-03 09:45:20 +02:00
bool tensor_init_one(tensor t, const uint32_t *size, uint8_t rank)
{
2023-09-03 09:45:20 +02:00
/* Inits (sets the size) and filles a tensor with ones.
*
* @param t The tensor to fill
* @param size The final size of the tensor t
* @param rank The length of size array
*
* @return true when successful, false otherwise
*/
2023-05-07 14:38:41 +02:00
uint32_t i;
2023-09-03 09:45:20 +02:00
if(!_tensor_set_size(t, size, rank)) return false;
for(i = 0; i < t->num_elem; i++) {
t->elements[i] = DTYPE_ONE;
}
2023-09-03 09:45:20 +02:00
return true;
}
2023-09-03 09:45:20 +02:00
bool tensor_init_zero(tensor t, const uint32_t *size, uint8_t rank)
{
2023-09-03 09:45:20 +02:00
/* Inits (sets the size) and filles a tensor with zeros.
*
* @param t The tensor to fill
* @param size The final size of the tensor t
* @param rank The length of size array
*
* @return true when successful, false otherwise
*/
2023-05-07 14:38:41 +02:00
uint32_t i;
2023-09-03 09:45:20 +02:00
if(!_tensor_set_size(t, size, rank)) return false;
for(i = 0; i < t->num_elem; i++) {
t->elements[i] = DTYPE_ZERO;
}
2023-09-03 09:45:20 +02:00
return true;
}
2023-09-03 09:45:20 +02:00
bool tensor_init_rand(tensor t, const uint32_t *size, uint8_t rank, dtype max)
{
2023-09-03 09:45:20 +02:00
/* Inits (sets the size) and filles a tensor with random values below or
* equal to the max value.
*
* @param t The tensor to fill
* @param size The final size of the tensor t
* @param rank The length of size array
* @param max The maximal value filled in
*
* @return true when successful, false otherwise
*/
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-09-03 09:45:20 +02:00
if(!_tensor_set_size(t, size, rank)) return false;
for(i = 0; i < t->num_elem; i++) {
t->elements[i] = DTYPE_RAND(max);
}
2023-09-03 09:45:20 +02:00
return true;
}
2023-09-03 09:45:20 +02:00
bool tensor_cpy(tensor t1, const tensor t2)
2023-03-18 20:52:26 +01:00
{
2023-09-03 09:45:20 +02:00
/* Copies the contents of t2 into t1.
*
* @param t1 The tensor in which to copy the values
* @param t2 The tensor from which to copy the values
*
* @return true when successful, false otherwise
*/
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-09-03 09:45:20 +02:00
if(!_tensor_set_size(t1, t2->size, t2->rank)) return false;
2023-03-18 20:52:26 +01:00
for(i = 0; i < t2->num_elem; i++) {
t1->elements[i] = t2->elements[i];
}
2023-09-03 09:45:20 +02:00
return true;
2023-03-18 20:52:26 +01:00
}
void tensor_print(const tensor t)
{
2023-09-03 09:45:20 +02:00
/* Prints a tensor to stdout.
*
* @param t The tensor to print
*/
2023-05-07 14:38:41 +02:00
uint32_t i, j;
2023-09-03 09:45:20 +02:00
uint32_t *index;
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++) {
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-05-07 13:31:04 +02:00
if(t->rank == 0) {
2023-03-09 18:24:17 +01:00
/* scalar */
DTYPE_PRINT(t->elements[0]);
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 */
if(t->size[0] == 1) {
putchar('(');
DTYPE_PRINT(t->elements[0]);
printf(")\n");
} else {
printf("\n/");
DTYPE_PRINT(t->elements[0]);
printf("\\\n");
for(i = 1; i < t->size[0] - 1; i++) {
putchar('|');
DTYPE_PRINT(t->elements[i]);
printf("|\n");
}
printf("\\");
DTYPE_PRINT(t->elements[t->size[0] - 1]);
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-09-03 09:45:20 +02:00
index = malloc(sizeof(int) * 2);
if(t->size[0] == 1) {
putchar('(');
2023-09-03 09:45:20 +02:00
index[0] = 0;
for(i = 0; i < t->size[1]; i++) {
2023-09-03 09:45:20 +02:00
index[1] = i;
DTYPE_PRINT(tensor_get(t, index, NULL));
}
printf(")\n");
} else {
printf("\n/");
2023-09-03 09:45:20 +02:00
index[0] = 0;
for(i = 0; i < t->size[1]; i++) {
2023-09-03 09:45:20 +02:00
index[1] = i;
DTYPE_PRINT(tensor_get(t, index, NULL));
}
printf("\\\n");
for(i = 1; i < t->size[0] - 1; i++) {
putchar('|');
2023-09-03 09:45:20 +02:00
index[0] = i;
for(j = 0; j < t->size[1]; j++) {
2023-09-03 09:45:20 +02:00
index[1] = j;
DTYPE_PRINT(tensor_get(t, index, NULL));
}
printf("|\n");
}
printf("\\");
2023-09-03 09:45:20 +02:00
index[0] = t->size[0] - 1;
for(i = 0; i < t->size[1]; i++) {
2023-09-03 09:45:20 +02:00
index[1] = i;
DTYPE_PRINT(tensor_get(t, index, NULL));
}
printf("/\n");
}
2023-09-03 09:45:20 +02:00
free(index);
} else {
putchar('[');
for(i = 0; i < t->num_elem; i++) {
DTYPE_PRINT(t->elements[i]);
}
putchar(']');
putchar('\n');
}
}