2024-04-30 13:22:27 -03:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <math.h>
# include <cuda_runtime_api.h>
# include "tensor.h"
# include "cuda.h"
# include "cpu.h"
extern " C " {
Tensor * create_tensor ( float * data , int * shape , int ndim , char * device ) {
2024-05-02 13:22:52 -03:00
2024-04-30 13:22:27 -03:00
Tensor * tensor = ( Tensor * ) malloc ( sizeof ( Tensor ) ) ;
if ( tensor = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
2024-06-05 20:24:09 -03:00
tensor - > data = data ;
tensor - > shape = shape ;
2024-04-30 13:22:27 -03:00
tensor - > ndim = ndim ;
2024-06-05 20:24:09 -03:00
tensor - > device = ( char * ) malloc ( strlen ( device ) + 1 ) ;
if ( device ! = NULL ) {
strcpy ( tensor - > device , device ) ;
} else {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( - 1 ) ;
}
2024-04-30 13:22:27 -03:00
tensor - > size = 1 ;
for ( int i = 0 ; i < ndim ; i + + ) {
tensor - > size * = shape [ i ] ;
}
tensor - > strides = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
2024-06-05 20:24:09 -03:00
if ( tensor - > strides = = NULL ) {
2024-04-30 13:22:27 -03:00
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
int stride = 1 ;
for ( int i = ndim - 1 ; i > = 0 ; i - - ) {
tensor - > strides [ i ] = stride ;
stride * = shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
2024-04-30 13:22:27 -03:00
return tensor ;
}
2024-06-05 14:31:48 -03:00
void delete_tensor ( Tensor * tensor ) {
if ( tensor ! = NULL ) {
2024-06-05 21:04:09 -03:00
free ( tensor ) ;
tensor = NULL ;
}
}
2024-06-05 14:31:48 -03:00
2024-06-05 21:04:09 -03:00
void delete_shape ( Tensor * tensor ) {
if ( tensor - > shape ! = NULL ) {
free ( tensor - > shape ) ;
tensor - > shape = NULL ;
}
}
2024-06-05 14:31:48 -03:00
2024-06-05 21:04:09 -03:00
void delete_data ( Tensor * tensor ) {
if ( tensor - > data ! = NULL ) {
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
free ( tensor - > data ) ;
} else {
free_cuda ( tensor - > data ) ;
2024-06-05 14:31:48 -03:00
}
2024-06-05 21:04:09 -03:00
tensor - > data = NULL ;
2024-06-05 14:31:48 -03:00
}
}
2024-06-05 20:24:09 -03:00
void delete_strides ( Tensor * tensor ) {
if ( tensor - > strides ! = NULL ) {
free ( tensor - > strides ) ;
tensor - > strides = NULL ;
}
}
void delete_device ( Tensor * tensor ) {
if ( tensor - > device ! = NULL ) {
free ( tensor - > device ) ;
tensor - > device = NULL ;
}
}
2024-06-05 14:31:48 -03:00
2024-04-30 13:22:27 -03:00
float get_item ( Tensor * tensor , int * indices ) {
int index = 0 ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
index + = indices [ i ] * tensor - > strides [ i ] ;
}
float result ;
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-04-30 13:22:27 -03:00
result = tensor - > data [ index ] ;
2024-06-05 20:24:09 -03:00
} else {
cudaMemcpy ( & result , tensor - > data + index , sizeof ( float ) , cudaMemcpyDeviceToHost ) ;
2024-04-30 13:22:27 -03:00
}
return result ;
}
void to_device ( Tensor * tensor , char * target_device ) {
2024-05-23 19:15:30 -03:00
int device_id = 0 ;
char * endptr ;
2024-05-29 17:48:37 -03:00
2024-06-05 21:04:09 -03:00
char * target_device_type ;
2024-05-23 19:15:30 -03:00
long num = strtol ( target_device , & endptr , 10 ) ;
if ( * endptr = = ' \0 ' ) {
device_id = ( int ) num ;
2024-06-05 21:04:09 -03:00
target_device_type = new char [ strlen ( " cuda " ) + 1 ] ;
strcpy ( target_device_type , " cuda " ) ;
}
else {
target_device_type = new char [ strlen ( " cuda " ) + 1 ] ;
strcpy ( target_device_type , " cpu " ) ;
2024-05-23 19:15:30 -03:00
}
2024-06-05 21:04:09 -03:00
if ( ( strcmp ( target_device_type , " cuda " ) = = 0 ) & & ( strcmp ( tensor - > device , " cpu " ) = = 0 ) ) {
2024-05-23 19:15:30 -03:00
cpu_to_cuda ( tensor , device_id ) ;
2024-04-30 13:22:27 -03:00
}
2024-06-05 21:04:09 -03:00
else if ( ( strcmp ( target_device_type , " cpu " ) = = 0 ) & & ( strcmp ( tensor - > device , " cuda " ) = = 0 ) ) {
2024-04-30 13:22:27 -03:00
cuda_to_cpu ( tensor ) ;
}
2024-06-05 21:04:09 -03:00
free ( target_device_type ) ;
2024-04-30 13:22:27 -03:00
}
Tensor * add_tensor ( Tensor * tensor1 , Tensor * tensor2 ) {
if ( tensor1 - > ndim ! = tensor2 - > ndim ) {
fprintf ( stderr , " Tensors must have the same number of dimensions %d and %d for addition \n " , tensor1 - > ndim , tensor2 - > ndim ) ;
exit ( 1 ) ;
}
if ( strcmp ( tensor1 - > device , tensor2 - > device ) ! = 0 ) {
fprintf ( stderr , " Tensors must be on the same device: %s and %s \n " , tensor1 - > device , tensor2 - > device ) ;
exit ( 1 ) ;
}
int ndim = tensor1 - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
if ( tensor1 - > shape [ i ] ! = tensor2 - > shape [ i ] ) {
fprintf ( stderr , " Tensors must have the same shape %d and %d at index %d for addition \n " , tensor1 - > shape [ i ] , tensor2 - > shape [ i ] , i ) ;
exit ( 1 ) ;
}
shape [ i ] = tensor1 - > shape [ i ] ;
}
2024-05-09 22:32:36 -03:00
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor1 - > device , " cpu " ) = = 0 ) {
2024-04-30 13:22:27 -03:00
float * result_data = ( float * ) malloc ( tensor1 - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
add_tensor_cpu ( tensor1 , tensor2 , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor1 - > size * sizeof ( float ) ) ;
add_tensor_cuda ( tensor1 , tensor2 , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
2024-04-30 13:22:27 -03:00
}
}
2024-05-16 16:35:55 -03:00
Tensor * add_broadcasted_tensor ( Tensor * tensor1 , Tensor * tensor2 ) {
if ( strcmp ( tensor1 - > device , tensor2 - > device ) ! = 0 ) {
fprintf ( stderr , " Tensors must be on the same device: %s and %s \n " , tensor1 - > device , tensor2 - > device ) ;
exit ( 1 ) ;
}
int max_ndim = tensor1 - > ndim > tensor2 - > ndim ? tensor1 - > ndim : tensor2 - > ndim ;
// Determine the broadcasted shape
int * broadcasted_shape = ( int * ) malloc ( max_ndim * sizeof ( int ) ) ;
if ( broadcasted_shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < max_ndim ; i + + ) {
int dim1 = i < tensor1 - > ndim ? tensor1 - > shape [ tensor1 - > ndim - 1 - i ] : 1 ;
int dim2 = i < tensor2 - > ndim ? tensor2 - > shape [ tensor2 - > ndim - 1 - i ] : 1 ;
if ( dim1 ! = dim2 & & dim1 ! = 1 & & dim2 ! = 1 ) {
fprintf ( stderr , " Shapes are not compatible for broadcasting \n " ) ;
exit ( 1 ) ;
}
broadcasted_shape [ max_ndim - 1 - i ] = dim1 > dim2 ? dim1 : dim2 ;
}
2024-05-17 11:39:26 -03:00
int broadcasted_size = 1 ;
for ( int i = 0 ; i < max_ndim ; i + + ) {
broadcasted_size * = broadcasted_shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor1 - > device , " cpu " ) = = 0 ) {
2024-05-17 11:39:26 -03:00
float * result_data = ( float * ) malloc ( broadcasted_size * sizeof ( float ) ) ;
2024-05-16 17:23:38 -03:00
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
2024-05-16 16:35:55 -03:00
2024-05-17 11:39:26 -03:00
add_broadcasted_tensor_cpu ( tensor1 , tensor2 , result_data , broadcasted_shape , broadcasted_size ) ;
2024-05-16 17:23:38 -03:00
return create_tensor ( result_data , broadcasted_shape , max_ndim , tensor1 - > device ) ;
2024-06-05 20:24:09 -03:00
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , broadcasted_size * sizeof ( float ) ) ;
add_broadcasted_tensor_cuda ( tensor1 , tensor2 , result_data , broadcasted_shape , broadcasted_size ) ;
return create_tensor ( result_data , broadcasted_shape , max_ndim , tensor1 - > device ) ;
2024-05-16 17:23:38 -03:00
}
2024-05-16 16:35:55 -03:00
}
2024-05-17 19:08:09 -03:00
Tensor * sum_tensor ( Tensor * tensor , int axis , bool keepdim ) {
2024-05-16 16:35:55 -03:00
int ndim ;
int * shape ;
2024-05-22 21:07:09 -03:00
2024-05-22 19:55:00 -03:00
if ( axis > tensor - > ndim - 1 ) {
fprintf ( stderr , " Error: axis argument %d must be smaller than tensor dimension %d " , axis , tensor - > ndim ) ;
}
2024-05-16 16:35:55 -03:00
if ( axis = = - 1 ) {
2024-05-21 00:38:34 -03:00
2024-05-16 16:35:55 -03:00
shape = ( int * ) malloc ( sizeof ( int ) ) ;
shape [ 0 ] = 1 ;
ndim = 1 ;
} else {
2024-05-17 19:29:16 -03:00
shape = ( int * ) malloc ( ( tensor - > ndim - 1 ) * sizeof ( int ) ) ;
for ( int i = 0 , j = 0 ; i < tensor - > ndim ; + + i ) {
if ( i ! = axis ) {
shape [ j + + ] = tensor - > shape [ i ] ;
2024-05-17 19:08:09 -03:00
}
2024-05-16 16:35:55 -03:00
}
2024-05-17 19:29:16 -03:00
ndim = tensor - > ndim - 1 ;
2024-05-17 19:08:09 -03:00
}
2024-05-23 01:06:21 -03:00
int axis_size = 1 ;
2024-05-17 19:08:09 -03:00
for ( int i = 0 ; i < ndim ; i + + ) {
2024-05-23 01:06:21 -03:00
axis_size * = shape [ i ] ;
2024-04-30 13:22:27 -03:00
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
float * result_data = ( float * ) calloc ( axis_size , sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
2024-05-23 00:30:48 -03:00
}
2024-06-05 20:24:09 -03:00
sum_tensor_cpu ( tensor , result_data , axis_size , shape , axis ) ;
2024-05-22 19:32:47 -03:00
if ( keepdim ) {
if ( axis = = - 1 ) {
ndim = tensor - > ndim ;
shape = ( int * ) malloc ( ( tensor - > ndim ) * sizeof ( int ) ) ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
shape [ i ] = 1 ;
}
} else {
shape = ( int * ) malloc ( ( tensor - > ndim ) * sizeof ( int ) ) ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
shape [ axis ] = 1 ;
ndim = tensor - > ndim ;
}
}
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-04-30 13:22:27 -03:00
}
else {
2024-06-05 20:24:09 -03:00
float * result_data ;
if ( axis = = - 1 ) {
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
} else {
cudaMalloc ( ( void * * ) & result_data , axis_size * sizeof ( float ) ) ;
2024-04-30 13:22:27 -03:00
}
2024-06-05 20:24:09 -03:00
sum_tensor_cuda ( tensor , result_data , axis ) ;
2024-05-17 19:29:16 -03:00
if ( keepdim ) {
2024-05-21 00:38:34 -03:00
if ( axis = = - 1 ) {
ndim = tensor - > ndim ;
shape = ( int * ) malloc ( ( tensor - > ndim ) * sizeof ( int ) ) ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
2024-05-20 20:16:41 -03:00
shape [ i ] = 1 ;
2024-05-21 00:38:34 -03:00
}
} else {
shape = ( int * ) malloc ( ( tensor - > ndim ) * sizeof ( int ) ) ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
2024-05-20 20:16:41 -03:00
shape [ i ] = tensor - > shape [ i ] ;
}
2024-05-21 00:38:34 -03:00
shape [ axis ] = 1 ;
ndim = tensor - > ndim ;
2024-05-17 19:29:16 -03:00
}
2024-05-21 00:38:34 -03:00
2024-05-17 19:29:16 -03:00
}
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-04-30 13:22:27 -03:00
}
}
2024-05-20 12:50:45 -03:00
Tensor * max_tensor ( Tensor * tensor , int axis , bool keepdim ) {
int ndim ;
int * shape ;
2024-05-21 00:38:34 -03:00
if ( axis = = - 1 ) {
2024-05-20 12:50:45 -03:00
shape = ( int * ) malloc ( sizeof ( int ) ) ;
shape [ 0 ] = 1 ;
ndim = 1 ;
} else {
shape = ( int * ) malloc ( ( tensor - > ndim - 1 ) * sizeof ( int ) ) ;
for ( int i = 0 , j = 0 ; i < tensor - > ndim ; + + i ) {
if ( i ! = axis ) {
shape [ j + + ] = tensor - > shape [ i ] ;
}
}
ndim = tensor - > ndim - 1 ;
}
2024-05-23 01:26:28 -03:00
int axis_size = 1 ;
2024-05-20 12:50:45 -03:00
for ( int i = 0 ; i < ndim ; i + + ) {
2024-05-23 01:26:28 -03:00
axis_size * = shape [ i ] ;
2024-05-20 12:50:45 -03:00
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
float * result_data = ( float * ) malloc ( axis_size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
2024-05-23 01:26:28 -03:00
}
2024-06-05 20:24:09 -03:00
max_tensor_cpu ( tensor , result_data , axis_size , shape , axis ) ;
2024-05-23 01:26:28 -03:00
if ( keepdim ) {
if ( axis = = - 1 ) {
ndim = tensor - > ndim ;
shape = ( int * ) malloc ( ( tensor - > ndim ) * sizeof ( int ) ) ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
shape [ i ] = 1 ;
}
} else {
shape = ( int * ) malloc ( ( tensor - > ndim ) * sizeof ( int ) ) ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
shape [ axis ] = 1 ;
ndim = tensor - > ndim ;
}
}
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-23 01:26:28 -03:00
2024-05-20 12:50:45 -03:00
}
else {
2024-06-05 20:24:09 -03:00
float * result_data ;
if ( axis = = - 1 ) {
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
} else {
cudaMalloc ( ( void * * ) & result_data , axis_size * sizeof ( float ) ) ;
2024-05-20 12:50:45 -03:00
}
2024-06-05 20:24:09 -03:00
max_tensor_cuda ( tensor , result_data , axis ) ;
2024-05-20 12:50:45 -03:00
if ( keepdim ) {
2024-05-21 00:38:34 -03:00
if ( axis = = - 1 ) {
ndim = tensor - > ndim ;
shape = ( int * ) malloc ( ( tensor - > ndim ) * sizeof ( int ) ) ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
2024-05-20 20:16:41 -03:00
shape [ i ] = 1 ;
2024-05-21 00:38:34 -03:00
}
} else {
shape = ( int * ) malloc ( ( tensor - > ndim ) * sizeof ( int ) ) ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
2024-05-20 20:16:41 -03:00
shape [ i ] = tensor - > shape [ i ] ;
}
2024-05-21 00:38:34 -03:00
shape [ axis ] = 1 ;
ndim = tensor - > ndim ;
2024-05-23 01:26:28 -03:00
}
2024-05-20 12:50:45 -03:00
}
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-20 12:50:45 -03:00
}
}
Tensor * min_tensor ( Tensor * tensor , int axis , bool keepdim ) {
int ndim ;
int * shape ;
if ( axis = = - 1 ) {
shape = ( int * ) malloc ( sizeof ( int ) ) ;
shape [ 0 ] = 1 ;
ndim = 1 ;
} else {
shape = ( int * ) malloc ( ( tensor - > ndim - 1 ) * sizeof ( int ) ) ;
for ( int i = 0 , j = 0 ; i < tensor - > ndim ; + + i ) {
if ( i ! = axis ) {
shape [ j + + ] = tensor - > shape [ i ] ;
}
}
ndim = tensor - > ndim - 1 ;
}
2024-05-21 00:38:34 -03:00
2024-05-23 01:39:37 -03:00
int axis_size = 1 ;
2024-05-20 12:50:45 -03:00
for ( int i = 0 ; i < ndim ; i + + ) {
2024-05-23 01:39:37 -03:00
axis_size * = shape [ i ] ;
2024-05-20 12:50:45 -03:00
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
float * result_data = ( float * ) malloc ( axis_size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
2024-05-23 01:39:37 -03:00
}
2024-06-05 20:24:09 -03:00
min_tensor_cpu ( tensor , result_data , axis_size , shape , axis ) ;
2024-05-23 01:39:37 -03:00
if ( keepdim ) {
if ( axis = = - 1 ) {
ndim = tensor - > ndim ;
shape = ( int * ) malloc ( ( tensor - > ndim ) * sizeof ( int ) ) ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
shape [ i ] = 1 ;
}
} else {
shape = ( int * ) malloc ( ( tensor - > ndim ) * sizeof ( int ) ) ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
shape [ axis ] = 1 ;
ndim = tensor - > ndim ;
}
}
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-23 01:39:37 -03:00
2024-05-20 12:50:45 -03:00
}
else {
2024-06-05 20:24:09 -03:00
float * result_data ;
if ( axis = = - 1 ) {
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
} else {
cudaMalloc ( ( void * * ) & result_data , axis_size * sizeof ( float ) ) ;
2024-05-20 12:50:45 -03:00
}
2024-06-05 20:24:09 -03:00
min_tensor_cuda ( tensor , result_data , axis ) ;
2024-05-20 12:50:45 -03:00
if ( keepdim ) {
2024-05-21 00:38:34 -03:00
if ( axis = = - 1 ) {
ndim = tensor - > ndim ;
shape = ( int * ) malloc ( ( tensor - > ndim ) * sizeof ( int ) ) ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
2024-05-20 20:16:41 -03:00
shape [ i ] = 1 ;
2024-05-21 00:38:34 -03:00
}
} else {
shape = ( int * ) malloc ( ( tensor - > ndim ) * sizeof ( int ) ) ;
for ( int i = 0 ; i < tensor - > ndim ; i + + ) {
2024-05-20 20:16:41 -03:00
shape [ i ] = tensor - > shape [ i ] ;
}
2024-05-21 00:38:34 -03:00
shape [ axis ] = 1 ;
ndim = tensor - > ndim ;
2024-05-23 01:39:37 -03:00
}
2024-05-20 12:50:45 -03:00
}
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-23 01:39:37 -03:00
}
2024-05-20 12:50:45 -03:00
}
2024-04-30 13:22:27 -03:00
Tensor * sub_tensor ( Tensor * tensor1 , Tensor * tensor2 ) {
if ( tensor1 - > ndim ! = tensor2 - > ndim ) {
fprintf ( stderr , " Tensors must have the same number of dimensions %d and %d for subtraction \n " , tensor1 - > ndim , tensor2 - > ndim ) ;
exit ( 1 ) ;
}
if ( strcmp ( tensor1 - > device , tensor2 - > device ) ! = 0 ) {
fprintf ( stderr , " Tensors must be on the same device: %s and %s \n " , tensor1 - > device , tensor2 - > device ) ;
exit ( 1 ) ;
}
int ndim = tensor1 - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
if ( tensor1 - > shape [ i ] ! = tensor2 - > shape [ i ] ) {
fprintf ( stderr , " Tensors must have the same shape %d and %d at index %d for subtraction \n " , tensor1 - > shape [ i ] , tensor2 - > shape [ i ] , i ) ;
exit ( 1 ) ;
}
shape [ i ] = tensor1 - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor1 - > device , " cpu " ) = = 0 ) {
2024-04-30 13:22:27 -03:00
float * result_data = ( float * ) malloc ( tensor1 - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
sub_tensor_cpu ( tensor1 , tensor2 , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor1 - > size * sizeof ( float ) ) ;
sub_tensor_cuda ( tensor1 , tensor2 , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
2024-04-30 13:22:27 -03:00
}
}
2024-05-16 17:03:09 -03:00
Tensor * sub_broadcasted_tensor ( Tensor * tensor1 , Tensor * tensor2 ) {
if ( strcmp ( tensor1 - > device , tensor2 - > device ) ! = 0 ) {
fprintf ( stderr , " Tensors must be on the same device: %s and %s \n " , tensor1 - > device , tensor2 - > device ) ;
exit ( 1 ) ;
}
int max_ndim = tensor1 - > ndim > tensor2 - > ndim ? tensor1 - > ndim : tensor2 - > ndim ;
// Determine the broadcasted shape
int * broadcasted_shape = ( int * ) malloc ( max_ndim * sizeof ( int ) ) ;
if ( broadcasted_shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < max_ndim ; i + + ) {
int dim1 = i < tensor1 - > ndim ? tensor1 - > shape [ tensor1 - > ndim - 1 - i ] : 1 ;
int dim2 = i < tensor2 - > ndim ? tensor2 - > shape [ tensor2 - > ndim - 1 - i ] : 1 ;
if ( dim1 ! = dim2 & & dim1 ! = 1 & & dim2 ! = 1 ) {
fprintf ( stderr , " Shapes are not compatible for broadcasting \n " ) ;
exit ( 1 ) ;
}
broadcasted_shape [ max_ndim - 1 - i ] = dim1 > dim2 ? dim1 : dim2 ;
}
2024-05-17 13:15:33 -03:00
int broadcasted_size = 1 ;
for ( int i = 0 ; i < max_ndim ; i + + ) {
broadcasted_size * = broadcasted_shape [ i ] ;
2024-05-16 17:03:09 -03:00
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor1 - > device , " cpu " ) = = 0 ) {
2024-05-17 13:15:33 -03:00
float * result_data = ( float * ) malloc ( broadcasted_size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
2024-05-16 17:03:09 -03:00
2024-05-17 13:15:33 -03:00
sub_broadcasted_tensor_cpu ( tensor1 , tensor2 , result_data , broadcasted_shape , broadcasted_size ) ;
return create_tensor ( result_data , broadcasted_shape , max_ndim , tensor1 - > device ) ;
2024-06-05 20:24:09 -03:00
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , broadcasted_size * sizeof ( float ) ) ;
sub_broadcasted_tensor_cuda ( tensor1 , tensor2 , result_data , broadcasted_shape , broadcasted_size ) ;
return create_tensor ( result_data , broadcasted_shape , max_ndim , tensor1 - > device ) ;
2024-05-17 13:15:33 -03:00
}
2024-05-16 17:03:09 -03:00
}
2024-04-30 13:22:27 -03:00
Tensor * elementwise_mul_tensor ( Tensor * tensor1 , Tensor * tensor2 ) {
if ( tensor1 - > ndim ! = tensor2 - > ndim ) {
fprintf ( stderr , " Tensors must have the same number of dimensions %d and %d for element-wise multiplication \n " , tensor1 - > ndim , tensor2 - > ndim ) ;
exit ( 1 ) ;
}
if ( strcmp ( tensor1 - > device , tensor2 - > device ) ! = 0 ) {
fprintf ( stderr , " Tensors must be on the same device: %s and %s \n " , tensor1 - > device , tensor2 - > device ) ;
exit ( 1 ) ;
}
int ndim = tensor1 - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
if ( tensor1 - > shape [ i ] ! = tensor2 - > shape [ i ] ) {
fprintf ( stderr , " Tensors must have the same shape %d and %d at index %d for element-wise multiplication \n " , tensor1 - > shape [ i ] , tensor2 - > shape [ i ] , i ) ;
exit ( 1 ) ;
}
shape [ i ] = tensor1 - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor1 - > device , " cpu " ) = = 0 ) {
2024-04-30 13:22:27 -03:00
float * result_data = ( float * ) malloc ( tensor1 - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
elementwise_mul_tensor_cpu ( tensor1 , tensor2 , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor1 - > size * sizeof ( float ) ) ;
elementwise_mul_tensor_cuda ( tensor1 , tensor2 , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
2024-04-30 13:22:27 -03:00
}
}
Tensor * scalar_mul_tensor ( Tensor * tensor , float scalar ) {
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-04-30 13:22:27 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
scalar_mul_tensor_cpu ( tensor , scalar , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
scalar_mul_tensor_cuda ( tensor , scalar , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-04-30 13:22:27 -03:00
}
}
2024-05-06 01:21:18 -03:00
Tensor * scalar_div_tensor ( float scalar , Tensor * tensor ) {
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-05-06 01:21:18 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
scalar_div_tensor_cpu ( scalar , tensor , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
scalar_div_tensor_cuda ( scalar , tensor , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-06 01:21:18 -03:00
}
}
Tensor * tensor_div_scalar ( Tensor * tensor , float scalar ) {
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-05-06 01:21:18 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
tensor_div_scalar_cpu ( tensor , scalar , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
tensor_div_scalar_cuda ( tensor , scalar , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-06 01:21:18 -03:00
}
}
2024-05-06 10:18:12 -03:00
Tensor * tensor_div_tensor ( Tensor * tensor1 , Tensor * tensor2 ) {
if ( tensor1 - > ndim ! = tensor2 - > ndim ) {
2024-05-21 01:22:38 -03:00
fprintf ( stderr , " Tensors must have the same number of dimensions %d and %d for element-wise division \n " , tensor1 - > ndim , tensor2 - > ndim ) ;
2024-05-06 10:18:12 -03:00
exit ( 1 ) ;
}
if ( strcmp ( tensor1 - > device , tensor2 - > device ) ! = 0 ) {
fprintf ( stderr , " Tensors must be on the same device: %s and %s \n " , tensor1 - > device , tensor2 - > device ) ;
exit ( 1 ) ;
}
int ndim = tensor1 - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
if ( tensor1 - > shape [ i ] ! = tensor2 - > shape [ i ] ) {
2024-05-21 01:22:38 -03:00
fprintf ( stderr , " Tensors must have the same shape %d and %d at index %d for division \n " , tensor1 - > shape [ i ] , tensor2 - > shape [ i ] , i ) ;
2024-05-06 10:18:12 -03:00
exit ( 1 ) ;
}
shape [ i ] = tensor1 - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor1 - > device , " cpu " ) = = 0 ) {
2024-05-06 10:18:12 -03:00
float * result_data = ( float * ) malloc ( tensor1 - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
tensor_div_tensor_cpu ( tensor1 , tensor2 , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor1 - > size * sizeof ( float ) ) ;
tensor_div_tensor_cuda ( tensor1 , tensor2 , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
2024-05-06 10:18:12 -03:00
}
}
2024-04-30 13:22:27 -03:00
Tensor * matmul_tensor ( Tensor * tensor1 , Tensor * tensor2 ) {
2024-05-02 19:13:05 -03:00
//MxN @ NxP = MxP
2024-04-30 13:22:27 -03:00
// Check if tensors have compatible shapes for matrix multiplication
if ( tensor1 - > shape [ 1 ] ! = tensor2 - > shape [ 0 ] ) {
2024-05-02 19:13:05 -03:00
fprintf ( stderr , " Incompatible shapes for matrix multiplication %dx%d and %dx%d \n " , tensor1 - > shape [ 0 ] , tensor1 - > shape [ 1 ] , tensor2 - > shape [ 0 ] , tensor2 - > shape [ 1 ] ) ;
2024-04-30 13:22:27 -03:00
exit ( 1 ) ;
}
if ( strcmp ( tensor1 - > device , tensor2 - > device ) ! = 0 ) {
fprintf ( stderr , " Tensors must be on the same device: %s and %s \n " , tensor1 - > device , tensor2 - > device ) ;
exit ( 1 ) ;
}
int ndim = tensor1 - > ndim + tensor2 - > ndim - 2 ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < tensor1 - > ndim - 1 ; i + + ) {
shape [ i ] = tensor1 - > shape [ i ] ;
}
for ( int i = tensor1 - > ndim - 1 ; i < ndim ; i + + ) {
shape [ i ] = tensor2 - > shape [ i - tensor1 - > ndim + 2 ] ;
}
int size = 1 ;
for ( int i = 0 ; i < ndim ; i + + ) {
size * = shape [ i ] ;
}
float * result_data = ( float * ) malloc ( size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor1 - > device , " cpu " ) = = 0 ) {
2024-04-30 13:22:27 -03:00
float * result_data = ( float * ) malloc ( size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
matmul_tensor_cpu ( tensor1 , tensor2 , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , size * sizeof ( float ) ) ;
matmul_tensor_cuda ( tensor1 , tensor2 , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
2024-04-30 13:22:27 -03:00
}
}
2024-05-02 20:21:19 -03:00
Tensor * broadcasted_batched_matmul_tensor ( Tensor * tensor1 , Tensor * tensor2 ) {
2024-05-22 19:20:54 -03:00
//BATCHxMxP = MxN @ BATCHxNxP
2024-05-02 19:13:05 -03:00
// Check if tensors have compatible shapes for matrix multiplication
if ( tensor1 - > shape [ 1 ] ! = tensor2 - > shape [ 1 ] ) {
2024-05-02 20:21:19 -03:00
fprintf ( stderr , " Incompatible shapes for broadcasted batched matrix multiplication %dx%d and %dx%dx%d \n " , tensor1 - > shape [ 0 ] , tensor1 - > shape [ 1 ] , tensor2 - > shape [ 0 ] , tensor2 - > shape [ 1 ] , tensor2 - > shape [ 2 ] ) ;
2024-05-02 19:13:05 -03:00
exit ( 1 ) ;
}
if ( strcmp ( tensor1 - > device , tensor2 - > device ) ! = 0 ) {
fprintf ( stderr , " Tensors must be on the same device: %s and %s \n " , tensor1 - > device , tensor2 - > device ) ;
exit ( 1 ) ;
}
int ndim = 3 ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
shape [ 0 ] = tensor2 - > shape [ 0 ] ; ;
shape [ 1 ] = tensor1 - > shape [ 0 ] ;
shape [ 2 ] = tensor2 - > shape [ 2 ] ;
int size = 1 ;
for ( int i = 0 ; i < ndim ; i + + ) {
size * = shape [ i ] ;
}
float * result_data = ( float * ) malloc ( size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor1 - > device , " cpu " ) = = 0 ) {
2024-05-02 20:21:19 -03:00
float * result_data = ( float * ) malloc ( size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
broadcasted_batched_matmul_tensor_cpu ( tensor1 , tensor2 , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , size * sizeof ( float ) ) ;
broadcasted_batched_matmul_tensor_cuda ( tensor1 , tensor2 , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
2024-05-02 20:21:19 -03:00
}
}
Tensor * batched_matmul_tensor ( Tensor * tensor1 , Tensor * tensor2 ) {
2024-05-22 19:20:54 -03:00
//BATCHxMxP = BATCHxMxN @ BATCHxNxP
2024-05-02 20:21:19 -03:00
// Check if tensors have compatible shapes for matrix multiplication
if ( tensor1 - > shape [ 0 ] ! = tensor2 - > shape [ 0 ] ) {
fprintf ( stderr , " Tensors must have same batch dimension for batch matmul %d and %d \n " , tensor1 - > shape [ 0 ] , tensor2 - > shape [ 0 ] ) ;
exit ( 1 ) ;
}
if ( tensor1 - > shape [ 2 ] ! = tensor2 - > shape [ 1 ] ) {
fprintf ( stderr , " Incompatible shapes for matrix multiplication %dx%d and %dx%d \n " , tensor1 - > shape [ 0 ] , tensor1 - > shape [ 1 ] , tensor2 - > shape [ 0 ] , tensor2 - > shape [ 1 ] ) ;
exit ( 1 ) ;
}
if ( strcmp ( tensor1 - > device , tensor2 - > device ) ! = 0 ) {
fprintf ( stderr , " Tensors must be on the same device: %s and %s \n " , tensor1 - > device , tensor2 - > device ) ;
exit ( 1 ) ;
}
int ndim = 3 ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
shape [ 0 ] = tensor2 - > shape [ 0 ] ; ;
shape [ 1 ] = tensor1 - > shape [ 1 ] ;
shape [ 2 ] = tensor2 - > shape [ 2 ] ;
int size = 1 ;
for ( int i = 0 ; i < ndim ; i + + ) {
size * = shape [ i ] ;
}
float * result_data = ( float * ) malloc ( size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor1 - > device , " cpu " ) = = 0 ) {
2024-05-02 19:13:05 -03:00
float * result_data = ( float * ) malloc ( size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
batched_matmul_tensor_cpu ( tensor1 , tensor2 , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , size * sizeof ( float ) ) ;
batched_matmul_tensor_cuda ( tensor1 , tensor2 , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
2024-05-02 19:13:05 -03:00
}
}
2024-05-06 01:21:18 -03:00
Tensor * tensor_pow_scalar ( Tensor * tensor , float exponent ) {
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-05-06 01:21:18 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
tensor_pow_scalar_cpu ( tensor , exponent , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
tensor_pow_scalar_cuda ( tensor , exponent , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-06 01:21:18 -03:00
}
}
Tensor * scalar_pow_tensor ( float base , Tensor * tensor ) {
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-05-06 01:21:18 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
scalar_pow_tensor_cpu ( base , tensor , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
scalar_pow_tensor_cuda ( base , tensor , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-06 01:21:18 -03:00
}
}
Tensor * log_tensor ( Tensor * tensor ) {
2024-04-30 13:22:27 -03:00
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-04-30 13:22:27 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
2024-05-06 01:21:18 -03:00
log_tensor_cpu ( tensor , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
log_tensor_cuda ( tensor , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-04-30 13:22:27 -03:00
}
}
2024-05-01 12:11:50 -03:00
Tensor * reshape_tensor ( Tensor * tensor , int * new_shape , int new_ndim ) {
2024-05-03 13:34:43 -03:00
int ndim = new_ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = new_shape [ i ] ;
}
2024-04-30 13:22:27 -03:00
// Calculate the total number of elements in the new shape
2024-05-03 13:34:43 -03:00
int size = 1 ;
2024-04-30 13:22:27 -03:00
for ( int i = 0 ; i < new_ndim ; i + + ) {
2024-05-03 13:34:43 -03:00
size * = shape [ i ] ;
2024-04-30 13:22:27 -03:00
}
// Check if the total number of elements matches the current tensor's size
2024-05-03 13:34:43 -03:00
if ( size ! = tensor - > size ) {
2024-04-30 13:22:27 -03:00
fprintf ( stderr , " Cannot reshape tensor. Total number of elements in new shape does not match the current size of the tensor. \n " ) ;
exit ( 1 ) ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-05-01 12:11:50 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
assign_tensor_cpu ( tensor , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
assign_tensor_cuda ( tensor , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-04-30 13:22:27 -03:00
}
}
2024-04-30 20:09:08 -03:00
2024-05-20 12:50:45 -03:00
Tensor * equal_tensor ( Tensor * tensor1 , Tensor * tensor2 ) {
if ( tensor1 - > ndim ! = tensor2 - > ndim ) {
fprintf ( stderr , " Tensors must have the same number of dimensions %d and %d for equal \n " , tensor1 - > ndim , tensor2 - > ndim ) ;
exit ( 1 ) ;
}
if ( strcmp ( tensor1 - > device , tensor2 - > device ) ! = 0 ) {
fprintf ( stderr , " Tensors must be on the same device: %s and %s \n " , tensor1 - > device , tensor2 - > device ) ;
exit ( 1 ) ;
}
int ndim = tensor1 - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
if ( tensor1 - > shape [ i ] ! = tensor2 - > shape [ i ] ) {
fprintf ( stderr , " Tensors must have the same shape %d and %d at index %d for equal \n " , tensor1 - > shape [ i ] , tensor2 - > shape [ i ] , i ) ;
exit ( 1 ) ;
}
shape [ i ] = tensor1 - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor1 - > device , " cpu " ) = = 0 ) {
2024-05-20 12:50:45 -03:00
float * result_data = ( float * ) malloc ( tensor1 - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
equal_tensor_cpu ( tensor1 , tensor2 , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor1 - > size * sizeof ( float ) ) ;
equal_tensor_cuda ( tensor1 , tensor2 , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor1 - > device ) ;
2024-05-20 12:50:45 -03:00
}
}
2024-05-20 16:42:45 -03:00
Tensor * equal_broadcasted_tensor ( Tensor * tensor1 , Tensor * tensor2 ) {
if ( strcmp ( tensor1 - > device , tensor2 - > device ) ! = 0 ) {
fprintf ( stderr , " Tensors must be on the same device: %s and %s \n " , tensor1 - > device , tensor2 - > device ) ;
exit ( 1 ) ;
}
int max_ndim = tensor1 - > ndim > tensor2 - > ndim ? tensor1 - > ndim : tensor2 - > ndim ;
// Determine the broadcasted shape
int * broadcasted_shape = ( int * ) malloc ( max_ndim * sizeof ( int ) ) ;
if ( broadcasted_shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < max_ndim ; i + + ) {
int dim1 = i < tensor1 - > ndim ? tensor1 - > shape [ tensor1 - > ndim - 1 - i ] : 1 ;
int dim2 = i < tensor2 - > ndim ? tensor2 - > shape [ tensor2 - > ndim - 1 - i ] : 1 ;
if ( dim1 ! = dim2 & & dim1 ! = 1 & & dim2 ! = 1 ) {
fprintf ( stderr , " Shapes are not compatible for broadcasting \n " ) ;
exit ( 1 ) ;
}
broadcasted_shape [ max_ndim - 1 - i ] = dim1 > dim2 ? dim1 : dim2 ;
}
int broadcasted_size = 1 ;
for ( int i = 0 ; i < max_ndim ; i + + ) {
broadcasted_size * = broadcasted_shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor1 - > device , " cpu " ) = = 0 ) {
2024-05-20 16:42:45 -03:00
float * result_data = ( float * ) malloc ( broadcasted_size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
equal_broadcasted_tensor_cpu ( tensor1 , tensor2 , result_data , broadcasted_shape , broadcasted_size ) ;
return create_tensor ( result_data , broadcasted_shape , max_ndim , tensor1 - > device ) ;
2024-06-05 20:24:09 -03:00
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , broadcasted_size * sizeof ( float ) ) ;
equal_broadcasted_tensor_cuda ( tensor1 , tensor2 , result_data , broadcasted_shape , broadcasted_size ) ;
return create_tensor ( result_data , broadcasted_shape , max_ndim , tensor1 - > device ) ;
2024-05-20 16:42:45 -03:00
}
}
2024-05-20 12:50:45 -03:00
2024-04-30 20:09:08 -03:00
Tensor * ones_like_tensor ( Tensor * tensor ) {
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-04-30 20:09:08 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
ones_like_tensor_cpu ( tensor , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
ones_like_tensor_cuda ( tensor , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-04-30 20:09:08 -03:00
}
}
Tensor * zeros_like_tensor ( Tensor * tensor ) {
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-04-30 20:09:08 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
zeros_like_tensor_cpu ( tensor , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
zeros_like_tensor_cuda ( tensor , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-04-30 20:09:08 -03:00
}
2024-05-01 02:12:47 -03:00
}
2024-05-09 22:32:36 -03:00
Tensor * sin_tensor ( Tensor * tensor ) {
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-05-09 22:32:36 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
sin_tensor_cpu ( tensor , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
sin_tensor_cuda ( tensor , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-09 22:32:36 -03:00
}
}
Tensor * cos_tensor ( Tensor * tensor ) {
2024-06-05 20:24:09 -03:00
2024-05-09 22:32:36 -03:00
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-05-09 22:32:36 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
cos_tensor_cpu ( tensor , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
cos_tensor_cuda ( tensor , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-09 22:32:36 -03:00
}
}
2024-05-22 13:24:01 -03:00
Tensor * sigmoid_tensor ( Tensor * tensor ) {
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-05-22 13:24:01 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
sigmoid_tensor_cpu ( tensor , result_data ) ;
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
}
else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
sigmoid_tensor_cuda ( tensor , result_data ) ;
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-22 13:24:01 -03:00
}
}
2024-05-01 02:12:47 -03:00
Tensor * transpose_tensor ( Tensor * tensor ) {
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( - 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ ndim - 1 - i ] ;
}
int size = tensor - > size ;
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
float * result_data = ( float * ) malloc ( size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
2024-05-23 02:09:32 -03:00
switch ( ndim ) {
case 1 :
2024-06-05 20:24:09 -03:00
transpose_1D_tensor_cpu ( tensor , result_data ) ;
2024-05-23 02:09:32 -03:00
break ;
case 2 :
2024-06-05 20:24:09 -03:00
transpose_2D_tensor_cpu ( tensor , result_data ) ;
2024-05-23 02:09:32 -03:00
break ;
case 3 :
2024-06-05 20:24:09 -03:00
transpose_3D_tensor_cpu ( tensor , result_data ) ;
2024-05-23 02:09:32 -03:00
break ;
default :
fprintf ( stderr , " Transpose only supports tensors up to 3 dimensions. \n " ) ;
exit ( - 1 ) ;
}
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-01 02:12:47 -03:00
}
else {
2024-06-05 20:24:09 -03:00
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , size * sizeof ( float ) ) ;
2024-05-04 13:37:18 -03:00
switch ( ndim ) {
case 1 :
2024-06-05 20:24:09 -03:00
transpose_1D_tensor_cuda ( tensor , result_data ) ;
2024-05-04 13:37:18 -03:00
break ;
case 2 :
2024-06-05 20:24:09 -03:00
transpose_2D_tensor_cuda ( tensor , result_data ) ;
2024-05-04 13:37:18 -03:00
break ;
case 3 :
2024-06-05 20:24:09 -03:00
transpose_3D_tensor_cuda ( tensor , result_data ) ;
2024-05-04 13:37:18 -03:00
break ;
default :
fprintf ( stderr , " Transpose only supports tensors up to 3 dimensions. \n " ) ;
exit ( - 1 ) ;
}
2024-06-05 20:24:09 -03:00
return create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-04 13:37:18 -03:00
}
}
Tensor * transpose_axes_tensor ( Tensor * tensor , int axis1 , int axis2 ) {
int ndim = tensor - > ndim ;
int * shape = ( int * ) malloc ( ndim * sizeof ( int ) ) ;
if ( shape = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( - 1 ) ;
}
for ( int i = 0 ; i < ndim ; i + + ) {
shape [ i ] = tensor - > shape [ i ] ;
}
shape [ axis1 ] = tensor - > shape [ axis2 ] ;
shape [ axis2 ] = tensor - > shape [ axis1 ] ;
int size = tensor - > size ;
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
float * result_data = ( float * ) malloc ( size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
exit ( 1 ) ;
}
assign_tensor_cpu ( tensor , result_data ) ;
Tensor * new_tensor = create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-23 02:09:32 -03:00
for ( int i = 0 ; i < ndim ; i + + ) {
new_tensor - > strides [ i ] = tensor - > strides [ i ] ;
}
new_tensor - > strides [ axis1 ] = tensor - > strides [ axis2 ] ;
new_tensor - > strides [ axis2 ] = tensor - > strides [ axis1 ] ;
make_contiguous ( new_tensor ) ;
return new_tensor ;
2024-05-04 13:37:18 -03:00
}
else {
2024-06-05 20:24:09 -03:00
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , size * sizeof ( float ) ) ;
assign_tensor_cuda ( tensor , result_data ) ;
Tensor * new_tensor = create_tensor ( result_data , shape , ndim , tensor - > device ) ;
2024-05-04 13:37:18 -03:00
for ( int i = 0 ; i < ndim ; i + + ) {
new_tensor - > strides [ i ] = tensor - > strides [ i ] ;
}
new_tensor - > strides [ axis1 ] = tensor - > strides [ axis2 ] ;
new_tensor - > strides [ axis2 ] = tensor - > strides [ axis1 ] ;
make_contiguous ( new_tensor ) ;
return new_tensor ;
}
}
void make_contiguous ( Tensor * tensor ) {
2024-05-23 02:27:46 -03:00
2024-05-04 13:37:18 -03:00
int * new_strides = ( int * ) malloc ( tensor - > ndim * sizeof ( int ) ) ;
if ( new_strides = = NULL ) {
2024-05-23 02:27:46 -03:00
fprintf ( stderr , " Memory allocation failed \n " ) ;
2024-05-04 13:37:18 -03:00
}
// Calculate new strides assuming C-contiguous order
int stride = 1 ;
for ( int i = tensor - > ndim - 1 ; i > = 0 ; i - - ) {
new_strides [ i ] = stride ;
stride * = tensor - > shape [ i ] ;
}
2024-06-05 20:24:09 -03:00
if ( strcmp ( tensor - > device , " cpu " ) = = 0 ) {
2024-05-23 02:27:46 -03:00
float * result_data = ( float * ) malloc ( tensor - > size * sizeof ( float ) ) ;
if ( result_data = = NULL ) {
fprintf ( stderr , " Memory allocation failed \n " ) ;
}
make_contiguous_tensor_cpu ( tensor , result_data , new_strides ) ;
2024-06-05 20:24:09 -03:00
} else {
float * result_data ;
cudaMalloc ( ( void * * ) & result_data , tensor - > size * sizeof ( float ) ) ;
make_contiguous_tensor_cuda ( tensor , result_data , new_strides ) ;
2024-05-01 02:12:47 -03:00
}
}
2024-05-23 02:27:46 -03:00
}