!| Module for the FTorch `torch_tensor` type and associated procedures. ! Generated from `ftorch_tensor.fypp` using the ! [fypp Fortran preprocessor](https://fypp.readthedocs.io/en/stable/index.html). ! ! * License ! FTorch is released under an MIT license. ! See the [LICENSE](https://github.com/Cambridge-ICCS/FTorch/blob/main/LICENSE) ! file for details. module ftorch_tensor use, intrinsic :: iso_c_binding, only: c_associated, c_null_ptr, c_ptr use, intrinsic :: iso_fortran_env, only: int32, int64 use ftorch_devices, only: torch_kCPU, torch_kCUDA, torch_kHIP, torch_kXPU, torch_kMPS use ftorch_types, only: torch_kInt8, torch_kInt16, torch_kInt32, torch_kInt64, & torch_kFloat32, torch_kFloat64 implicit none public !> Type for holding a Torch tensor. type torch_tensor type(c_ptr) :: p = c_null_ptr !! pointer to the tensor in memory contains procedure :: rank => torch_tensor_get_rank procedure :: shape => torch_tensor_get_shape procedure :: stride => torch_tensor_get_stride procedure :: dtype => torch_tensor_get_dtype procedure :: device_type => torch_tensor_get_device_type procedure :: device_index => torch_tensor_get_device_index procedure :: requires_grad => torch_tensor_requires_grad procedure :: zero => torch_tensor_zero procedure :: zero_grad => torch_tensor_zero_grad procedure :: print => torch_tensor_print final :: torch_tensor_delete end type torch_tensor ! ============================================================================ ! --- Interfaces for tensor constructors ! ============================================================================ !> Interface for directing `torch_tensor_from_array` to possible input types and ranks !> Signature: (tensor, data, device_type, [device_index], [permute_dims], [requires_grad]) interface torch_tensor_from_array module procedure torch_tensor_from_array_int8_1d module procedure torch_tensor_from_array_int8_2d module procedure torch_tensor_from_array_int8_3d module procedure torch_tensor_from_array_int8_4d module procedure torch_tensor_from_array_int8_5d module procedure torch_tensor_from_array_int16_1d module procedure torch_tensor_from_array_int16_2d module procedure torch_tensor_from_array_int16_3d module procedure torch_tensor_from_array_int16_4d module procedure torch_tensor_from_array_int16_5d module procedure torch_tensor_from_array_int32_1d module procedure torch_tensor_from_array_int32_2d module procedure torch_tensor_from_array_int32_3d module procedure torch_tensor_from_array_int32_4d module procedure torch_tensor_from_array_int32_5d module procedure torch_tensor_from_array_int64_1d module procedure torch_tensor_from_array_int64_2d module procedure torch_tensor_from_array_int64_3d module procedure torch_tensor_from_array_int64_4d module procedure torch_tensor_from_array_int64_5d module procedure torch_tensor_from_array_real32_1d module procedure torch_tensor_from_array_real32_2d module procedure torch_tensor_from_array_real32_3d module procedure torch_tensor_from_array_real32_4d module procedure torch_tensor_from_array_real32_5d module procedure torch_tensor_from_array_real64_1d module procedure torch_tensor_from_array_real64_2d module procedure torch_tensor_from_array_real64_3d module procedure torch_tensor_from_array_real64_4d module procedure torch_tensor_from_array_real64_5d end interface !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array: !> `(tensor, data, layout, device_type, [device_index], [requires_grad])`. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. interface torch_tensor_from_array_legacy module procedure torch_tensor_from_array_int8_1d_legacy module procedure torch_tensor_from_array_int8_2d_legacy module procedure torch_tensor_from_array_int8_3d_legacy module procedure torch_tensor_from_array_int8_4d_legacy module procedure torch_tensor_from_array_int8_5d_legacy module procedure torch_tensor_from_array_int16_1d_legacy module procedure torch_tensor_from_array_int16_2d_legacy module procedure torch_tensor_from_array_int16_3d_legacy module procedure torch_tensor_from_array_int16_4d_legacy module procedure torch_tensor_from_array_int16_5d_legacy module procedure torch_tensor_from_array_int32_1d_legacy module procedure torch_tensor_from_array_int32_2d_legacy module procedure torch_tensor_from_array_int32_3d_legacy module procedure torch_tensor_from_array_int32_4d_legacy module procedure torch_tensor_from_array_int32_5d_legacy module procedure torch_tensor_from_array_int64_1d_legacy module procedure torch_tensor_from_array_int64_2d_legacy module procedure torch_tensor_from_array_int64_3d_legacy module procedure torch_tensor_from_array_int64_4d_legacy module procedure torch_tensor_from_array_int64_5d_legacy module procedure torch_tensor_from_array_real32_1d_legacy module procedure torch_tensor_from_array_real32_2d_legacy module procedure torch_tensor_from_array_real32_3d_legacy module procedure torch_tensor_from_array_real32_4d_legacy module procedure torch_tensor_from_array_real32_5d_legacy module procedure torch_tensor_from_array_real64_1d_legacy module procedure torch_tensor_from_array_real64_2d_legacy module procedure torch_tensor_from_array_real64_3d_legacy module procedure torch_tensor_from_array_real64_4d_legacy module procedure torch_tensor_from_array_real64_5d_legacy end interface interface function torch_from_blob_c(data, ndims, tensor_shape, strides, dtype, & device_type, device_index, & requires_grad) result(tensor_p) & bind(c, name = "torch_from_blob") use, intrinsic :: iso_c_binding, only : c_bool, c_int, c_int64_t, c_ptr implicit none ! Arguments type(c_ptr), value, intent(in) :: data integer(c_int), value, intent(in) :: ndims integer(c_int64_t), intent(in) :: tensor_shape(*) integer(c_int64_t), intent(in) :: strides(*) integer(c_int), value, intent(in) :: dtype integer(c_int), value, intent(in) :: device_type integer(c_int), value, intent(in) :: device_index logical(c_bool), value, intent(in) :: requires_grad type(c_ptr) :: tensor_p end function torch_from_blob_c end interface ! ============================================================================ ! --- Interfaces for overloaded operators acting on tensors ! ============================================================================ interface assignment (=) module procedure torch_tensor_assign end interface interface operator (+) module procedure torch_tensor_add end interface interface operator (-) module procedure torch_tensor_negative module procedure torch_tensor_subtract end interface interface operator (*) module procedure torch_tensor_multiply end interface interface subroutine torch_tensor_multiply_c(output_c, tensor1_c, tensor2_c) & bind(c, name = "torch_tensor_multiply") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: output_c type(c_ptr), value, intent(in) :: tensor1_c type(c_ptr), value, intent(in) :: tensor2_c end subroutine torch_tensor_multiply_c end interface interface operator (/) module procedure torch_tensor_divide end interface interface subroutine torch_tensor_divide_c(output_c, tensor1_c, tensor2_c) & bind(c, name = "torch_tensor_divide") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: output_c type(c_ptr), value, intent(in) :: tensor1_c type(c_ptr), value, intent(in) :: tensor2_c end subroutine torch_tensor_divide_c end interface interface operator (**) module procedure torch_tensor_power_int8 module procedure torch_tensor_power_int16 module procedure torch_tensor_power_int32 module procedure torch_tensor_power_int64 module procedure torch_tensor_power_real32 module procedure torch_tensor_power_real64 end interface ! ============================================================================ ! --- Interfaces related to automatic differentation functionality for tensors ! ============================================================================ interface torch_tensor_backward module procedure torch_tensor_backward_with_external_gradient module procedure torch_tensor_backward_without_external_gradient end interface contains ! ============================================================================ ! --- Procedures for constructing tensors ! ============================================================================ !> Returns a tensor with uninitialised values. subroutine torch_tensor_empty(tensor, ndims, tensor_shape, dtype, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_bool, c_int, c_int64_t type(torch_tensor), intent(out) :: tensor !! Returned tensor integer(int32), intent(in) :: ndims !! Number of dimensions of the tensor integer(int64), intent(in) :: tensor_shape(ndims) !! Shape of the tensor integer(c_int), intent(in) :: dtype !! Data type of the tensor integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor integer(c_int) :: ndims_c_int !! C-type ndims integer(c_int64_t) :: tensor_shape_c_int(ndims) !! C-type tensor_shape integer(c_int) :: device_index_value !! device index used logical(c_bool) :: requires_grad_value !! Whether gradients need to be computed for the created tensor interface function torch_empty_c(ndims_c, tensor_shape_c, dtype_c, device_type_c, & device_index_c, requires_grad_c) result(tensor_c) & bind(c, name = "torch_empty") use, intrinsic :: iso_c_binding, only : c_bool, c_int, c_int64_t, c_ptr implicit none integer(c_int), value, intent(in) :: ndims_c integer(c_int64_t), intent(in) :: tensor_shape_c(*) integer(c_int), value, intent(in) :: dtype_c integer(c_int), value, intent(in) :: device_type_c integer(c_int), value, intent(in) :: device_index_c logical(c_bool), value, intent(in) :: requires_grad_c type(c_ptr) :: tensor_c end function torch_empty_c end interface ! Process optional arguments if (present(device_index)) then device_index_value = device_index else if (device_type == torch_kCPU) then device_index_value = -1 else device_index_value = 0 end if if (.not. present(requires_grad)) then requires_grad_value = logical(.false., c_bool) else requires_grad_value = requires_grad end if ! Convert public arguments to C-types ndims_c_int = ndims tensor_shape_c_int(:) = tensor_shape(:) tensor%p = torch_empty_c(ndims_c_int, tensor_shape_c_int, dtype, device_type, & device_index_value, requires_grad_value) end subroutine torch_tensor_empty !> Returns a tensor filled with the scalar value 0. subroutine torch_tensor_zeros(tensor, ndims, tensor_shape, dtype, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_bool, c_int, c_int64_t type(torch_tensor), intent(out) :: tensor !! Returned tensor integer(int32), intent(in) :: ndims !! Number of dimensions of the tensor integer(int64), intent(in) :: tensor_shape(ndims) !! Shape of the tensor integer(c_int), intent(in) :: dtype !! Data type of the tensor integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor integer(c_int) :: ndims_c_int !! C-type ndims integer(c_int64_t) :: tensor_shape_c_int(ndims) !! C-type tensor_shape integer(c_int) :: device_index_value !! device index used logical(c_bool) :: requires_grad_value !! Whether gradients need to be computed for the created tensor interface function torch_zeros_c(ndims_c, tensor_shape_c, dtype_c, & device_type_c, device_index_c, requires_grad_c) result(tensor_c) & bind(c, name = "torch_zeros") use, intrinsic :: iso_c_binding, only : c_bool, c_int, c_int64_t, c_ptr implicit none integer(c_int), value, intent(in) :: ndims_c integer(c_int64_t), intent(in) :: tensor_shape_c(*) integer(c_int), value, intent(in) :: dtype_c integer(c_int), value, intent(in) :: device_type_c integer(c_int), value, intent(in) :: device_index_c logical(c_bool), value, intent(in) :: requires_grad_c type(c_ptr) :: tensor_c end function torch_zeros_c end interface ! Process optional arguments if (present(device_index)) then device_index_value = device_index else if (device_type == torch_kCPU) then device_index_value = -1 else device_index_value = 0 end if if (.not. present(requires_grad)) then requires_grad_value = logical(.false., c_bool) else requires_grad_value = requires_grad end if ! Convert public arguments to C-types ndims_c_int = ndims tensor_shape_c_int(:) = tensor_shape(:) tensor%p = torch_zeros_c(ndims_c_int, tensor_shape_c_int, dtype, device_type, & device_index_value, requires_grad_value) end subroutine torch_tensor_zeros !> Returns a tensor filled with the scalar value 1. subroutine torch_tensor_ones(tensor, ndims, tensor_shape, dtype, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_bool, c_int, c_int64_t type(torch_tensor), intent(out) :: tensor !! Returned tensor integer(int32), intent(in) :: ndims !! Number of dimensions of the tensor integer(int64), intent(in) :: tensor_shape(ndims) !! Shape of the tensor integer(c_int), intent(in) :: dtype !! Data type of the tensor integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor integer(c_int) :: ndims_c_int !! C-type ndims integer(c_int64_t) :: tensor_shape_c_int(ndims) !! C-type tensor_shape integer(c_int) :: device_index_value !! device index used logical(c_bool) :: requires_grad_value !! Whether gradients need to be computed for the created tensor interface function torch_ones_c(ndims_c, tensor_shape_c, dtype_c, & device_type_c, device_index_c, requires_grad_c) result(tensor_c) & bind(c, name = "torch_ones") use, intrinsic :: iso_c_binding, only : c_bool, c_int, c_int64_t, c_ptr implicit none integer(c_int), value, intent(in) :: ndims_c integer(c_int64_t), intent(in) :: tensor_shape_c(*) integer(c_int), value, intent(in) :: dtype_c integer(c_int), value, intent(in) :: device_type_c integer(c_int), value, intent(in) :: device_index_c logical(c_bool), value, intent(in) :: requires_grad_c type(c_ptr) :: tensor_c end function torch_ones_c end interface ! Process optional arguments if (present(device_index)) then device_index_value = device_index else if (device_type == torch_kCPU) then device_index_value = -1 else device_index_value = 0 end if if (.not. present(requires_grad)) then requires_grad_value = logical(.false., c_bool) else requires_grad_value = requires_grad end if ! Convert public arguments to C-types ndims_c_int = ndims tensor_shape_c_int(:) = tensor_shape(:) tensor%p = torch_ones_c(ndims_c_int, tensor_shape_c_int, dtype, device_type, & device_index_value, requires_grad_value) end subroutine torch_tensor_ones !| Exposes the given data as a tensor without taking ownership of the original data. ! This routine will take an array in memory and return a tensor as specified by ! the shape and stride input arguments. ! ! Note that `data` needs to be a pointer to a **contiguous** block of memory! ! This is not generally not the case when calling `c_loc` on a Fortran array as ! array slicing can lead to non-contiguous memory. ! Please consider asserting that the data is contiguous with the `is_contiguous` ! implicit procedure before calling this routine. subroutine torch_tensor_from_blob(tensor, data, ndims, tensor_shape, tensor_strides, dtype, & device_type, device_index, & requires_grad) use, intrinsic :: iso_c_binding, only : c_bool, c_int, c_int64_t, c_ptr type(torch_tensor), intent(out) :: tensor !! Returned tensor type(c_ptr), intent(in) :: data !! Pointer to data integer(int32), intent(in) :: ndims !! Number of dimensions of the tensor integer(int64), intent(in) :: tensor_shape(ndims) !! Shape of the returned tensor integer(int64), intent(in) :: tensor_strides(ndims) !! Strides for accessing data in the returned tensor. Note that these are integers !! representing the number of items of type `dtype` and NOT bytes/memory. integer(c_int), intent(in) :: dtype !! Data type of the input data and tensor integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(c_int) :: ndims_c !! C-type ndims integer(c_int64_t) :: tensor_shape_c(ndims) !! C-type tensor_shape integer(c_int64_t) :: tensor_strides_c(ndims) !! C-type strides integer(c_int) :: device_index_value !! device index used logical(c_bool) :: requires_grad_value !! Whether gradients need to be computed for the created tensor ! Process optional arguments if (.not. present(requires_grad)) then requires_grad_value = logical(.false., c_bool) else requires_grad_value = requires_grad end if if (present(device_index)) then device_index_value = device_index else if (device_type == torch_kCPU) then device_index_value = -1 else device_index_value = 0 end if ! Convert public arguments to C-types ndims_c = ndims tensor_shape_c(:) = tensor_shape(:) tensor_strides_c(:) = tensor_strides(:) tensor%p = torch_from_blob_c(data, ndims_c, tensor_shape_c, tensor_strides_c, dtype, & device_type, device_index_value, & requires_grad_value) end subroutine torch_tensor_from_blob !> Return a Torch tensor pointing to data_in array of rank 1 containing data of type `int8` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int8_1d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int8 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int8), intent(in), pointer, contiguous :: data_in(:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(1) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(1) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(1) !! Strides for the Fortran array integer(int64) :: torch_shape(1) !! Shape of the Torch tensor integer(int64) :: torch_strides(1) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt8 !! Data type integer(int32), parameter :: ndims = 1 !! Number of dimension of input data logical :: permute_valid(1) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 1 and contain numbers 1 to 1. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 1]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int8_1d !> Return a Torch tensor pointing to data_in array of rank 2 containing data of type `int8` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int8_2d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int8 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int8), intent(in), pointer, contiguous :: data_in(:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(2) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(2) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(2) !! Strides for the Fortran array integer(int64) :: torch_shape(2) !! Shape of the Torch tensor integer(int64) :: torch_strides(2) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt8 !! Data type integer(int32), parameter :: ndims = 2 !! Number of dimension of input data logical :: permute_valid(2) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 2 and contain numbers 1 to 2. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 2]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int8_2d !> Return a Torch tensor pointing to data_in array of rank 3 containing data of type `int8` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int8_3d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int8 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int8), intent(in), pointer, contiguous :: data_in(:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(3) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(3) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(3) !! Strides for the Fortran array integer(int64) :: torch_shape(3) !! Shape of the Torch tensor integer(int64) :: torch_strides(3) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt8 !! Data type integer(int32), parameter :: ndims = 3 !! Number of dimension of input data logical :: permute_valid(3) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 3 and contain numbers 1 to 3. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 3]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int8_3d !> Return a Torch tensor pointing to data_in array of rank 4 containing data of type `int8` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int8_4d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int8 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int8), intent(in), pointer, contiguous :: data_in(:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(4) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(4) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(4) !! Strides for the Fortran array integer(int64) :: torch_shape(4) !! Shape of the Torch tensor integer(int64) :: torch_strides(4) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt8 !! Data type integer(int32), parameter :: ndims = 4 !! Number of dimension of input data logical :: permute_valid(4) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 4 and contain numbers 1 to 4. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 4]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int8_4d !> Return a Torch tensor pointing to data_in array of rank 5 containing data of type `int8` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int8_5d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int8 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int8), intent(in), pointer, contiguous :: data_in(:,:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(5) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(5) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(5) !! Strides for the Fortran array integer(int64) :: torch_shape(5) !! Shape of the Torch tensor integer(int64) :: torch_strides(5) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt8 !! Data type integer(int32), parameter :: ndims = 5 !! Number of dimension of input data logical :: permute_valid(5) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 5 and contain numbers 1 to 5. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 5]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int8_5d !> Return a Torch tensor pointing to data_in array of rank 1 containing data of type `int16` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int16_1d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int16 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int16), intent(in), pointer, contiguous :: data_in(:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(1) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(1) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(1) !! Strides for the Fortran array integer(int64) :: torch_shape(1) !! Shape of the Torch tensor integer(int64) :: torch_strides(1) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt16 !! Data type integer(int32), parameter :: ndims = 1 !! Number of dimension of input data logical :: permute_valid(1) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 1 and contain numbers 1 to 1. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 1]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int16_1d !> Return a Torch tensor pointing to data_in array of rank 2 containing data of type `int16` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int16_2d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int16 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int16), intent(in), pointer, contiguous :: data_in(:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(2) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(2) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(2) !! Strides for the Fortran array integer(int64) :: torch_shape(2) !! Shape of the Torch tensor integer(int64) :: torch_strides(2) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt16 !! Data type integer(int32), parameter :: ndims = 2 !! Number of dimension of input data logical :: permute_valid(2) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 2 and contain numbers 1 to 2. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 2]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int16_2d !> Return a Torch tensor pointing to data_in array of rank 3 containing data of type `int16` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int16_3d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int16 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int16), intent(in), pointer, contiguous :: data_in(:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(3) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(3) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(3) !! Strides for the Fortran array integer(int64) :: torch_shape(3) !! Shape of the Torch tensor integer(int64) :: torch_strides(3) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt16 !! Data type integer(int32), parameter :: ndims = 3 !! Number of dimension of input data logical :: permute_valid(3) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 3 and contain numbers 1 to 3. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 3]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int16_3d !> Return a Torch tensor pointing to data_in array of rank 4 containing data of type `int16` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int16_4d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int16 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int16), intent(in), pointer, contiguous :: data_in(:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(4) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(4) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(4) !! Strides for the Fortran array integer(int64) :: torch_shape(4) !! Shape of the Torch tensor integer(int64) :: torch_strides(4) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt16 !! Data type integer(int32), parameter :: ndims = 4 !! Number of dimension of input data logical :: permute_valid(4) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 4 and contain numbers 1 to 4. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 4]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int16_4d !> Return a Torch tensor pointing to data_in array of rank 5 containing data of type `int16` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int16_5d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int16 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int16), intent(in), pointer, contiguous :: data_in(:,:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(5) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(5) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(5) !! Strides for the Fortran array integer(int64) :: torch_shape(5) !! Shape of the Torch tensor integer(int64) :: torch_strides(5) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt16 !! Data type integer(int32), parameter :: ndims = 5 !! Number of dimension of input data logical :: permute_valid(5) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 5 and contain numbers 1 to 5. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 5]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int16_5d !> Return a Torch tensor pointing to data_in array of rank 1 containing data of type `int32` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int32_1d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int32), intent(in), pointer, contiguous :: data_in(:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(1) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(1) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(1) !! Strides for the Fortran array integer(int64) :: torch_shape(1) !! Shape of the Torch tensor integer(int64) :: torch_strides(1) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt32 !! Data type integer(int32), parameter :: ndims = 1 !! Number of dimension of input data logical :: permute_valid(1) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 1 and contain numbers 1 to 1. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 1]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int32_1d !> Return a Torch tensor pointing to data_in array of rank 2 containing data of type `int32` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int32_2d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int32), intent(in), pointer, contiguous :: data_in(:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(2) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(2) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(2) !! Strides for the Fortran array integer(int64) :: torch_shape(2) !! Shape of the Torch tensor integer(int64) :: torch_strides(2) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt32 !! Data type integer(int32), parameter :: ndims = 2 !! Number of dimension of input data logical :: permute_valid(2) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 2 and contain numbers 1 to 2. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 2]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int32_2d !> Return a Torch tensor pointing to data_in array of rank 3 containing data of type `int32` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int32_3d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int32), intent(in), pointer, contiguous :: data_in(:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(3) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(3) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(3) !! Strides for the Fortran array integer(int64) :: torch_shape(3) !! Shape of the Torch tensor integer(int64) :: torch_strides(3) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt32 !! Data type integer(int32), parameter :: ndims = 3 !! Number of dimension of input data logical :: permute_valid(3) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 3 and contain numbers 1 to 3. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 3]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int32_3d !> Return a Torch tensor pointing to data_in array of rank 4 containing data of type `int32` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int32_4d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int32), intent(in), pointer, contiguous :: data_in(:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(4) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(4) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(4) !! Strides for the Fortran array integer(int64) :: torch_shape(4) !! Shape of the Torch tensor integer(int64) :: torch_strides(4) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt32 !! Data type integer(int32), parameter :: ndims = 4 !! Number of dimension of input data logical :: permute_valid(4) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 4 and contain numbers 1 to 4. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 4]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int32_4d !> Return a Torch tensor pointing to data_in array of rank 5 containing data of type `int32` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int32_5d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int32), intent(in), pointer, contiguous :: data_in(:,:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(5) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(5) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(5) !! Strides for the Fortran array integer(int64) :: torch_shape(5) !! Shape of the Torch tensor integer(int64) :: torch_strides(5) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt32 !! Data type integer(int32), parameter :: ndims = 5 !! Number of dimension of input data logical :: permute_valid(5) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 5 and contain numbers 1 to 5. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 5]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int32_5d !> Return a Torch tensor pointing to data_in array of rank 1 containing data of type `int64` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int64_1d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int64), intent(in), pointer, contiguous :: data_in(:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(1) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(1) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(1) !! Strides for the Fortran array integer(int64) :: torch_shape(1) !! Shape of the Torch tensor integer(int64) :: torch_strides(1) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt64 !! Data type integer(int32), parameter :: ndims = 1 !! Number of dimension of input data logical :: permute_valid(1) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 1 and contain numbers 1 to 1. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 1]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int64_1d !> Return a Torch tensor pointing to data_in array of rank 2 containing data of type `int64` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int64_2d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int64), intent(in), pointer, contiguous :: data_in(:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(2) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(2) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(2) !! Strides for the Fortran array integer(int64) :: torch_shape(2) !! Shape of the Torch tensor integer(int64) :: torch_strides(2) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt64 !! Data type integer(int32), parameter :: ndims = 2 !! Number of dimension of input data logical :: permute_valid(2) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 2 and contain numbers 1 to 2. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 2]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int64_2d !> Return a Torch tensor pointing to data_in array of rank 3 containing data of type `int64` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int64_3d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int64), intent(in), pointer, contiguous :: data_in(:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(3) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(3) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(3) !! Strides for the Fortran array integer(int64) :: torch_shape(3) !! Shape of the Torch tensor integer(int64) :: torch_strides(3) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt64 !! Data type integer(int32), parameter :: ndims = 3 !! Number of dimension of input data logical :: permute_valid(3) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 3 and contain numbers 1 to 3. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 3]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int64_3d !> Return a Torch tensor pointing to data_in array of rank 4 containing data of type `int64` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int64_4d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int64), intent(in), pointer, contiguous :: data_in(:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(4) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(4) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(4) !! Strides for the Fortran array integer(int64) :: torch_shape(4) !! Shape of the Torch tensor integer(int64) :: torch_strides(4) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt64 !! Data type integer(int32), parameter :: ndims = 4 !! Number of dimension of input data logical :: permute_valid(4) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 4 and contain numbers 1 to 4. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 4]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int64_4d !> Return a Torch tensor pointing to data_in array of rank 5 containing data of type `int64` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_int64_5d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int64), intent(in), pointer, contiguous :: data_in(:,:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(5) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(5) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(5) !! Strides for the Fortran array integer(int64) :: torch_shape(5) !! Shape of the Torch tensor integer(int64) :: torch_strides(5) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kInt64 !! Data type integer(int32), parameter :: ndims = 5 !! Number of dimension of input data logical :: permute_valid(5) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 5 and contain numbers 1 to 5. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 5]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int64_5d !> Return a Torch tensor pointing to data_in array of rank 1 containing data of type `real32` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_real32_1d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real32), intent(in), pointer, contiguous :: data_in(:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(1) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(1) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(1) !! Strides for the Fortran array integer(int64) :: torch_shape(1) !! Shape of the Torch tensor integer(int64) :: torch_strides(1) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kFloat32 !! Data type integer(int32), parameter :: ndims = 1 !! Number of dimension of input data logical :: permute_valid(1) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 1 and contain numbers 1 to 1. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 1]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real32_1d !> Return a Torch tensor pointing to data_in array of rank 2 containing data of type `real32` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_real32_2d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real32), intent(in), pointer, contiguous :: data_in(:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(2) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(2) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(2) !! Strides for the Fortran array integer(int64) :: torch_shape(2) !! Shape of the Torch tensor integer(int64) :: torch_strides(2) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kFloat32 !! Data type integer(int32), parameter :: ndims = 2 !! Number of dimension of input data logical :: permute_valid(2) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 2 and contain numbers 1 to 2. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 2]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real32_2d !> Return a Torch tensor pointing to data_in array of rank 3 containing data of type `real32` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_real32_3d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real32), intent(in), pointer, contiguous :: data_in(:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(3) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(3) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(3) !! Strides for the Fortran array integer(int64) :: torch_shape(3) !! Shape of the Torch tensor integer(int64) :: torch_strides(3) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kFloat32 !! Data type integer(int32), parameter :: ndims = 3 !! Number of dimension of input data logical :: permute_valid(3) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 3 and contain numbers 1 to 3. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 3]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real32_3d !> Return a Torch tensor pointing to data_in array of rank 4 containing data of type `real32` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_real32_4d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real32), intent(in), pointer, contiguous :: data_in(:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(4) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(4) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(4) !! Strides for the Fortran array integer(int64) :: torch_shape(4) !! Shape of the Torch tensor integer(int64) :: torch_strides(4) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kFloat32 !! Data type integer(int32), parameter :: ndims = 4 !! Number of dimension of input data logical :: permute_valid(4) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 4 and contain numbers 1 to 4. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 4]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real32_4d !> Return a Torch tensor pointing to data_in array of rank 5 containing data of type `real32` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_real32_5d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real32), intent(in), pointer, contiguous :: data_in(:,:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(5) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(5) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(5) !! Strides for the Fortran array integer(int64) :: torch_shape(5) !! Shape of the Torch tensor integer(int64) :: torch_strides(5) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kFloat32 !! Data type integer(int32), parameter :: ndims = 5 !! Number of dimension of input data logical :: permute_valid(5) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 5 and contain numbers 1 to 5. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 5]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real32_5d !> Return a Torch tensor pointing to data_in array of rank 1 containing data of type `real64` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_real64_1d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real64), intent(in), pointer, contiguous :: data_in(:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(1) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(1) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(1) !! Strides for the Fortran array integer(int64) :: torch_shape(1) !! Shape of the Torch tensor integer(int64) :: torch_strides(1) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kFloat64 !! Data type integer(int32), parameter :: ndims = 1 !! Number of dimension of input data logical :: permute_valid(1) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 1 and contain numbers 1 to 1. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 1]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real64_1d !> Return a Torch tensor pointing to data_in array of rank 2 containing data of type `real64` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_real64_2d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real64), intent(in), pointer, contiguous :: data_in(:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(2) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(2) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(2) !! Strides for the Fortran array integer(int64) :: torch_shape(2) !! Shape of the Torch tensor integer(int64) :: torch_strides(2) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kFloat64 !! Data type integer(int32), parameter :: ndims = 2 !! Number of dimension of input data logical :: permute_valid(2) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 2 and contain numbers 1 to 2. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 2]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real64_2d !> Return a Torch tensor pointing to data_in array of rank 3 containing data of type `real64` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_real64_3d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real64), intent(in), pointer, contiguous :: data_in(:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(3) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(3) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(3) !! Strides for the Fortran array integer(int64) :: torch_shape(3) !! Shape of the Torch tensor integer(int64) :: torch_strides(3) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kFloat64 !! Data type integer(int32), parameter :: ndims = 3 !! Number of dimension of input data logical :: permute_valid(3) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 3 and contain numbers 1 to 3. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 3]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real64_3d !> Return a Torch tensor pointing to data_in array of rank 4 containing data of type `real64` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_real64_4d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real64), intent(in), pointer, contiguous :: data_in(:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(4) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(4) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(4) !! Strides for the Fortran array integer(int64) :: torch_shape(4) !! Shape of the Torch tensor integer(int64) :: torch_strides(4) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kFloat64 !! Data type integer(int32), parameter :: ndims = 4 !! Number of dimension of input data logical :: permute_valid(4) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 4 and contain numbers 1 to 4. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 4]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real64_4d !> Return a Torch tensor pointing to data_in array of rank 5 containing data of type `real64` !> This subroutine is part of an interface and should be accessed through !> `torch_tensor_from_array`. subroutine torch_tensor_from_array_real64_5d(tensor, data_in, & device_type, device_index, permute_dims, & requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real64), intent(in), pointer, contiguous :: data_in(:,:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer, optional, intent(in) :: device_index !! Device index for GPU devices integer(int32), optional, intent(in) :: permute_dims(5) !! Permutation of dimensions to be applied to Fortran data in the resulting tensor. !! Takes the form of an array of length `n` with elements `1` to `n`, where `n` !! is the `rank`. Element `i` indicates which dimension of the Fortran array !! appears as dimension `i` on the Torch tensor. !! e.g. a Fortran array of shape [10, 20, 30] permuted by [2, 3, 1] will result !! in Torch shape [20, 30, 10]. This matches behaviour of `torch.permute()`, !! noting that this is Fortran so we index from 1! logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int64) :: fortran_shape(5) !! Shape of the unpermuted Fortran array integer(int64) :: fortran_strides(5) !! Strides for the Fortran array integer(int64) :: torch_shape(5) !! Shape of the Torch tensor integer(int64) :: torch_strides(5) !! Strides for the Torch tensor integer(c_int), parameter :: dtype = torch_kFloat64 !! Data type integer(int32), parameter :: ndims = 5 !! Number of dimension of input data logical :: permute_valid(5) !! Array to check supplied permutation is valid integer :: i fortran_shape = shape(data_in) ! Compute native Fortran strides do i = 1, ndims if (i == 1) then fortran_strides(1) = 1_int64 else fortran_strides(i) = fortran_strides(i - 1) * fortran_shape(i-1) end if end do if (present(permute_dims)) then ! Check that the supplied permutation is valid and raise an error if not. ! Should be of length 5 and contain numbers 1 to 5. permute_valid = .false. do i = 1, ndims if (permute_dims(i) < 1 .or. permute_dims(i) > ndims) then error stop "Invalid permute_dims: element out of range [1, 5]" end if if (permute_valid(permute_dims(i))) then error stop "Invalid permute_dims: duplicate dimension" end if permute_valid(permute_dims(i)) = .true. end do ! permute shape of torch tensor to match permutation requested ('transpose') do i = 1, ndims torch_shape(i) = fortran_shape(permute_dims(i)) torch_strides(i) = fortran_strides(permute_dims(i)) end do else ! Keep Torch shape and strides same as Fortran torch_shape = fortran_shape torch_strides = fortran_strides end if call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, torch_shape, & torch_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real64_5d !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int8_1d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int8 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int8), intent(in), pointer, contiguous :: data_in(:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(1) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 1 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt8 !! Data type integer(int64) :: tensor_shape(1) !! Shape of the input tensor integer(int64) :: tensor_strides(1) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int8_1d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int8_2d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int8 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int8), intent(in), pointer, contiguous :: data_in(:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(2) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 2 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt8 !! Data type integer(int64) :: tensor_shape(2) !! Shape of the input tensor integer(int64) :: tensor_strides(2) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int8_2d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int8_3d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int8 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int8), intent(in), pointer, contiguous :: data_in(:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(3) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 3 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt8 !! Data type integer(int64) :: tensor_shape(3) !! Shape of the input tensor integer(int64) :: tensor_strides(3) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int8_3d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int8_4d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int8 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int8), intent(in), pointer, contiguous :: data_in(:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(4) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 4 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt8 !! Data type integer(int64) :: tensor_shape(4) !! Shape of the input tensor integer(int64) :: tensor_strides(4) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int8_4d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int8_5d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int8 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int8), intent(in), pointer, contiguous :: data_in(:,:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(5) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 5 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt8 !! Data type integer(int64) :: tensor_shape(5) !! Shape of the input tensor integer(int64) :: tensor_strides(5) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int8_5d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int16_1d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int16 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int16), intent(in), pointer, contiguous :: data_in(:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(1) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 1 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt16 !! Data type integer(int64) :: tensor_shape(1) !! Shape of the input tensor integer(int64) :: tensor_strides(1) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int16_1d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int16_2d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int16 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int16), intent(in), pointer, contiguous :: data_in(:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(2) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 2 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt16 !! Data type integer(int64) :: tensor_shape(2) !! Shape of the input tensor integer(int64) :: tensor_strides(2) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int16_2d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int16_3d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int16 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int16), intent(in), pointer, contiguous :: data_in(:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(3) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 3 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt16 !! Data type integer(int64) :: tensor_shape(3) !! Shape of the input tensor integer(int64) :: tensor_strides(3) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int16_3d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int16_4d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int16 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int16), intent(in), pointer, contiguous :: data_in(:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(4) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 4 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt16 !! Data type integer(int64) :: tensor_shape(4) !! Shape of the input tensor integer(int64) :: tensor_strides(4) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int16_4d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int16_5d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int16 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int16), intent(in), pointer, contiguous :: data_in(:,:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(5) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 5 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt16 !! Data type integer(int64) :: tensor_shape(5) !! Shape of the input tensor integer(int64) :: tensor_strides(5) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int16_5d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int32_1d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int32), intent(in), pointer, contiguous :: data_in(:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(1) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 1 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt32 !! Data type integer(int64) :: tensor_shape(1) !! Shape of the input tensor integer(int64) :: tensor_strides(1) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int32_1d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int32_2d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int32), intent(in), pointer, contiguous :: data_in(:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(2) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 2 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt32 !! Data type integer(int64) :: tensor_shape(2) !! Shape of the input tensor integer(int64) :: tensor_strides(2) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int32_2d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int32_3d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int32), intent(in), pointer, contiguous :: data_in(:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(3) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 3 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt32 !! Data type integer(int64) :: tensor_shape(3) !! Shape of the input tensor integer(int64) :: tensor_strides(3) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int32_3d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int32_4d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int32), intent(in), pointer, contiguous :: data_in(:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(4) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 4 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt32 !! Data type integer(int64) :: tensor_shape(4) !! Shape of the input tensor integer(int64) :: tensor_strides(4) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int32_4d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int32_5d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int32), intent(in), pointer, contiguous :: data_in(:,:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(5) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 5 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt32 !! Data type integer(int64) :: tensor_shape(5) !! Shape of the input tensor integer(int64) :: tensor_strides(5) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int32_5d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int64_1d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int64), intent(in), pointer, contiguous :: data_in(:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(1) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 1 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt64 !! Data type integer(int64) :: tensor_shape(1) !! Shape of the input tensor integer(int64) :: tensor_strides(1) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int64_1d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int64_2d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int64), intent(in), pointer, contiguous :: data_in(:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(2) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 2 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt64 !! Data type integer(int64) :: tensor_shape(2) !! Shape of the input tensor integer(int64) :: tensor_strides(2) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int64_2d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int64_3d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int64), intent(in), pointer, contiguous :: data_in(:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(3) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 3 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt64 !! Data type integer(int64) :: tensor_shape(3) !! Shape of the input tensor integer(int64) :: tensor_strides(3) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int64_3d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int64_4d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int64), intent(in), pointer, contiguous :: data_in(:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(4) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 4 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt64 !! Data type integer(int64) :: tensor_shape(4) !! Shape of the input tensor integer(int64) :: tensor_strides(4) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int64_4d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_int64_5d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : int64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs integer(kind=int64), intent(in), pointer, contiguous :: data_in(:,:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(5) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 5 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kInt64 !! Data type integer(int64) :: tensor_shape(5) !! Shape of the input tensor integer(int64) :: tensor_strides(5) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_int64_5d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_real32_1d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real32), intent(in), pointer, contiguous :: data_in(:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(1) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 1 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kFloat32 !! Data type integer(int64) :: tensor_shape(1) !! Shape of the input tensor integer(int64) :: tensor_strides(1) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real32_1d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_real32_2d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real32), intent(in), pointer, contiguous :: data_in(:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(2) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 2 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kFloat32 !! Data type integer(int64) :: tensor_shape(2) !! Shape of the input tensor integer(int64) :: tensor_strides(2) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real32_2d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_real32_3d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real32), intent(in), pointer, contiguous :: data_in(:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(3) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 3 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kFloat32 !! Data type integer(int64) :: tensor_shape(3) !! Shape of the input tensor integer(int64) :: tensor_strides(3) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real32_3d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_real32_4d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real32), intent(in), pointer, contiguous :: data_in(:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(4) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 4 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kFloat32 !! Data type integer(int64) :: tensor_shape(4) !! Shape of the input tensor integer(int64) :: tensor_strides(4) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real32_4d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_real32_5d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real32 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real32), intent(in), pointer, contiguous :: data_in(:,:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(5) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 5 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kFloat32 !! Data type integer(int64) :: tensor_shape(5) !! Shape of the input tensor integer(int64) :: tensor_strides(5) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real32_5d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_real64_1d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real64), intent(in), pointer, contiguous :: data_in(:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(1) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 1 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kFloat64 !! Data type integer(int64) :: tensor_shape(1) !! Shape of the input tensor integer(int64) :: tensor_strides(1) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real64_1d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_real64_2d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real64), intent(in), pointer, contiguous :: data_in(:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(2) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 2 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kFloat64 !! Data type integer(int64) :: tensor_shape(2) !! Shape of the input tensor integer(int64) :: tensor_strides(2) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real64_2d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_real64_3d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real64), intent(in), pointer, contiguous :: data_in(:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(3) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 3 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kFloat64 !! Data type integer(int64) :: tensor_shape(3) !! Shape of the input tensor integer(int64) :: tensor_strides(3) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real64_3d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_real64_4d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real64), intent(in), pointer, contiguous :: data_in(:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(4) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 4 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kFloat64 !! Data type integer(int64) :: tensor_shape(4) !! Shape of the input tensor integer(int64) :: tensor_strides(4) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real64_4d_legacy !> deprecated: true !> This is the old layout-required signature for torch_tensor_from_array. !> Use `torch_tensor_from_array` instead. This will be removed in a future release. subroutine torch_tensor_from_array_real64_5d_legacy(tensor, data_in, layout, & device_type, device_index, requires_grad) use, intrinsic :: iso_c_binding, only : c_int, c_loc use, intrinsic :: iso_fortran_env, only : real64 ! output tensor type(torch_tensor), intent(out) :: tensor !! Returned tensor ! inputs real(kind=real64), intent(in), pointer, contiguous :: data_in(:,:,:,:,:) !! Input data that tensor will point at integer(c_int), intent(in) :: device_type !! Device type the tensor will live on (`torch_kCPU` or a GPU device type) integer(int32), intent(in) :: layout(5) !! Control order of indices integer, optional, intent(in) :: device_index !! Device index for GPU devices logical, optional, intent(in) :: requires_grad !! Whether gradients need to be computed for the created tensor ! local data integer(int32), parameter :: ndims = 5 !! Number of dimension of input data integer(c_int), parameter :: dtype = torch_kFloat64 !! Data type integer(int64) :: tensor_shape(5) !! Shape of the input tensor integer(int64) :: tensor_strides(5) !! Strides for accessing data appropriately integer :: i write(*,*) "Warning: torch_tensor_from_array_legacy is deprecated and will be " write(*,*) "removed in a future version of FTorch. Please use torch_tensor_from_array, " write(*,*) "passing permute_dims as an optional argument after device_type, where possible." tensor_shape = shape(data_in) tensor_strides(:) = 0 do i = 1, ndims if (i == 1) then tensor_strides(layout(i)) = 1_int64 else tensor_strides(layout(i)) = tensor_strides(layout(i - 1)) * tensor_shape(layout(i - 1)) end if end do call torch_tensor_from_blob(tensor, c_loc(data_in), ndims, tensor_shape, & tensor_strides, dtype, device_type, device_index, & requires_grad) end subroutine torch_tensor_from_array_real64_5d_legacy ! ============================================================================ ! --- Procedures for interrogating tensors ! ============================================================================ !> Prints the contents of a tensor. subroutine torch_tensor_print(self) class(torch_tensor), intent(in) :: self !! Tensor to print the contents of interface subroutine torch_tensor_print_c(tensor_c) & bind(c, name = "torch_tensor_print") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c end subroutine torch_tensor_print_c end interface call torch_tensor_print_c(self%p) end subroutine torch_tensor_print !> Determines the rank of a tensor. function torch_tensor_get_rank(self) result(rank) class(torch_tensor), intent(in) :: self !! Tensor to get the rank of integer(kind=int32) :: rank !! Rank of tensor interface function torch_tensor_get_rank_c(tensor_c) result(rank_c) & bind(c, name = "torch_tensor_get_rank") use, intrinsic :: iso_c_binding, only : c_int, c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c integer(c_int) :: rank_c end function torch_tensor_get_rank_c end interface if (.not. c_associated(self%p)) then write(*,*) "Error :: tensor has not been constructed so its rank is unset" stop 1 end if rank = torch_tensor_get_rank_c(self%p) end function torch_tensor_get_rank !> Determines the shape of a tensor. function torch_tensor_get_shape(self) result(sizes) use, intrinsic :: iso_c_binding, only : c_f_pointer, c_int64_t, c_ptr class(torch_tensor), intent(in) :: self !! Tensor to get the shape of integer(kind=int64), allocatable :: sizes(:) !! Array holding the shape of the tensor ! Local data integer(kind=int32) :: ndims(1) integer(kind=c_int64_t), pointer :: sizes_c_int64_ptr(:) !! Temporary pointer to Torch-owned memory containing c_int64 type(c_ptr) :: cptr interface function torch_tensor_get_sizes_c(tensor_c) result(sizes_c) & bind(c, name = "torch_tensor_get_sizes") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c type(c_ptr) :: sizes_c end function torch_tensor_get_sizes_c end interface if (.not. c_associated(self%p)) then write(*,*) "Error :: tensor has not been constructed so its shape is unset" stop 1 end if ndims(1) = self%rank() cptr = torch_tensor_get_sizes_c(self%p) call c_f_pointer(cptr, sizes_c_int64_ptr, ndims) ! Copy out of the Torch-owned memory so the result remains valid even if ! the tensor is subsequently deleted allocate(sizes(ndims(1))) sizes(:) = sizes_c_int64_ptr(:) end function torch_tensor_get_shape !> Return the strides of the tensor function torch_tensor_get_stride(self) result(strides) use, intrinsic :: iso_c_binding, only : c_f_pointer, c_int64_t, c_ptr class(torch_tensor), intent(in) :: self !! Tensor to get the strides of integer(kind=int64), allocatable :: strides(:) !! Array holding the strides of the tensor ! Local data integer(kind=int32) :: ndims(1) integer(kind=c_int64_t), pointer :: strides_c_int64_ptr(:) !! Temporary pointer to Torch-owned memory containing c_int64 type(c_ptr) :: cptr interface function torch_tensor_get_stride_c(tensor_c) result(strides_c) & bind(c, name = "torch_tensor_get_stride") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c type(c_ptr) :: strides_c end function torch_tensor_get_stride_c end interface if (.not. c_associated(self%p)) then write(*,*) "Error :: tensor has not been constructed so its strides are unset" stop 1 end if ndims(1) = self%rank() cptr = torch_tensor_get_stride_c(self%p) call c_f_pointer(cptr, strides_c_int64_ptr, ndims) ! Copy out of the Torch-owned memory so the result remains valid even if ! the tensor is subsequently deleted allocate(strides(ndims(1))) strides(:) = strides_c_int64_ptr(:) end function torch_tensor_get_stride !> Returns the data type of a tensor. function torch_tensor_get_dtype(self) result(dtype) use, intrinsic :: iso_c_binding, only : c_int class(torch_tensor), intent(in) :: self !! Tensor to get the data type of integer(c_int) :: dtype !! Data type of tensor interface function torch_tensor_get_dtype_c(tensor_c) result(dtype_c) & bind(c, name = "torch_tensor_get_dtype") use, intrinsic :: iso_c_binding, only : c_int, c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c integer(c_int) :: dtype_c end function torch_tensor_get_dtype_c end interface if (.not. c_associated(self%p)) then write(*,*) "Error :: tensor has not been constructed so its data type is unset" stop 1 end if dtype = torch_tensor_get_dtype_c(self%p) end function torch_tensor_get_dtype !> Returns the device type of a tensor. function torch_tensor_get_device_type(self) result(device_type) use, intrinsic :: iso_c_binding, only : c_int class(torch_tensor), intent(in) :: self !! Tensor to get the device type of integer(c_int) :: device_type !! Device type of tensor interface function torch_tensor_get_device_type_c(tensor_c) result(device_type_c) & bind(c, name = "torch_tensor_get_device_type") use, intrinsic :: iso_c_binding, only : c_int, c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c integer(c_int) :: device_type_c end function torch_tensor_get_device_type_c end interface if (.not. c_associated(self%p)) then write(*,*) "Error :: tensor has not been constructed so its device type is unset" stop 1 end if device_type = torch_tensor_get_device_type_c(self%p) end function torch_tensor_get_device_type !> Determines the device index of a tensor. function torch_tensor_get_device_index(self) result(device_index) use, intrinsic :: iso_c_binding, only : c_int class(torch_tensor), intent(in) :: self !! Tensor to get the device index of integer(c_int) :: device_index !! Device index of tensor interface function torch_tensor_get_device_index_c(tensor_c) result(device_index_c) & bind(c, name = "torch_tensor_get_device_index") use, intrinsic :: iso_c_binding, only : c_int, c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c integer(c_int) :: device_index_c end function torch_tensor_get_device_index_c end interface if (.not. c_associated(self%p)) then write(*,*) "Error :: tensor has not been constructed so its device index is unset" stop 1 end if device_index = torch_tensor_get_device_index_c(self%p) end function torch_tensor_get_device_index !> Determines whether a tensor requires the autograd module. function torch_tensor_requires_grad(self) result(requires_grad) class(torch_tensor), intent(in) :: self !! Tensor to query logical :: requires_grad !! Whether the tensor requires autograd interface function torch_tensor_requires_grad_c(tensor_c) result(requires_grad_c) & bind(c, name = "torch_tensor_requires_grad") use, intrinsic :: iso_c_binding, only : c_bool, c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c logical(c_bool) :: requires_grad_c end function torch_tensor_requires_grad_c end interface requires_grad = torch_tensor_requires_grad_c(self%p) end function torch_tensor_requires_grad ! ============================================================================ ! --- Procedures for deallocating tensors ! ============================================================================ !> Deallocates a tensor (elemental). !> Note: Marked as impure due to C interoperability, though the operation is !> conceptally pure (deletion of a specific C++ Tensor object). impure elemental subroutine torch_tensor_delete(tensor) use, intrinsic :: iso_c_binding, only : c_associated, c_null_ptr type(torch_tensor), intent(inout) :: tensor !! Tensor to deallocate interface subroutine torch_tensor_delete_c(tensor_c) & bind(c, name = "torch_tensor_delete") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c end subroutine torch_tensor_delete_c end interface ! Call the destructor, if it hasn't already been called if (c_associated(tensor%p)) then call torch_tensor_delete_c(tensor%p) tensor%p = c_null_ptr end if end subroutine torch_tensor_delete ! ============================================================================ ! --- Procedures for manipulating tensors ! ============================================================================ !> Fills a tensor with the scalar value 0. subroutine torch_tensor_zero(tensor) use, intrinsic :: iso_c_binding, only : c_associated class(torch_tensor), intent(inout) :: tensor !! Tensor whose values are to be zeroed interface subroutine torch_tensor_zero_c(tensor_c) bind(c, name = "torch_tensor_zero") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c end subroutine torch_tensor_zero_c end interface if (.not. c_associated(tensor%p)) then write(*,*) "Error :: tensor must be constructed before zeroing values" stop 1 end if call torch_tensor_zero_c(tensor%p) end subroutine torch_tensor_zero !> Moves a source_tensor tensor to a target tensor's device and dtype subroutine torch_tensor_to(source_tensor, target_tensor, non_blocking) use, intrinsic :: iso_c_binding, only : c_bool, c_int type(torch_tensor), intent(in) :: source_tensor !! Source tensor to be moved type(torch_tensor), intent(inout) :: target_tensor !! Target tensor with the desired device and dtype logical, optional, intent(in) :: non_blocking !! Whether to perform asynchronous copy logical(c_bool) :: non_blocking_value integer(c_int) :: source_rank, target_rank, i integer(int64), allocatable :: source_shape(:), target_shape(:) interface subroutine torch_tensor_to_c(source_tensor_c, target_tensor_c, non_blocking_c) & bind(c, name = "torch_tensor_to") use, intrinsic :: iso_c_binding, only : c_bool, c_ptr implicit none type(c_ptr), value, intent(in) :: source_tensor_c type(c_ptr), value, intent(in) :: target_tensor_c logical(c_bool), value, intent(in) :: non_blocking_c end subroutine torch_tensor_to_c end interface ! Check for rank and shape consistency between the source and target tensors source_rank = source_tensor%rank() target_rank = target_tensor%rank() if (source_rank /= target_rank) then write(*,*) "Error in torch_tensor_to :: Cannot move source_tensor to target_tensor & &because the ranks do not match." write(*,*) "Source tensor rank:", source_rank, "Target tensor rank:", target_rank stop 1 end if source_shape = source_tensor%shape() target_shape = target_tensor%shape() do i = 1, source_rank if (source_shape(i) /= target_shape(i)) then write(*,*) "Error in torch_tensor_to :: Cannot move source_tensor to target_tensor & &because the shapes do not match." write(*,*) "Dimension", i, "mismatch: source_tensor =", source_shape(i), & "Target =", target_shape(i) stop 1 end if end do ! Process optional arguments if (present(non_blocking)) then non_blocking_value = non_blocking else non_blocking_value = .false. end if call torch_tensor_to_c(source_tensor%p, target_tensor%p, non_blocking_value) end subroutine torch_tensor_to ! ============================================================================ ! --- Overloaded operators acting on tensors ! ============================================================================ !> Overloads assignment operator for tensors. subroutine torch_tensor_assign(output, input) use, intrinsic :: iso_c_binding, only : c_associated type(torch_tensor), intent(in) :: input !! Tensor whose values are to be used type(torch_tensor), intent(inout) :: output !! Tensor to assign values to interface subroutine torch_tensor_assign_c(output_c, input_c) bind(c, name = "torch_tensor_assign") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: output_c type(c_ptr), value, intent(in) :: input_c end subroutine torch_tensor_assign_c end interface if (.not. c_associated(output%p)) then call torch_tensor_empty(output, input%rank(), input%shape(), input%dtype(), & input%device_type(), device_index=input%device_index(), & requires_grad=input%requires_grad()) else if (input%device_type() /= output%device_type()) then write(*,*) "Error :: cannot assign tensors with different device types" stop 1 end if if (input%device_index() /= output%device_index()) then write(*,*) "Error :: cannot assign tensors with different device indices" stop 1 end if end if call torch_tensor_assign_c(output%p, input%p) end subroutine torch_tensor_assign !> Overloads addition operator for two tensors. function torch_tensor_add(tensor1, tensor2) result(output) use, intrinsic :: iso_c_binding, only : c_associated type(torch_tensor), intent(in) :: tensor1 !! First tensor to be added type(torch_tensor), intent(in) :: tensor2 !! Second tensor to be added type(torch_tensor) :: output !! Tensor to hold the sum interface subroutine torch_tensor_add_c(output_c, tensor1_c, tensor2_c) & bind(c, name = "torch_tensor_add") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: tensor1_c type(c_ptr), value, intent(in) :: tensor2_c type(c_ptr), value, intent(in) :: output_c end subroutine torch_tensor_add_c end interface if (tensor1%device_type() /= tensor2%device_type()) then write(*,*) "Error :: cannot add tensors with different device types" stop 1 end if if (tensor1%device_index() /= tensor2%device_index()) then write(*,*) "Error :: cannot add tensors with different device indices" stop 1 end if if (.not. c_associated(output%p)) then call torch_tensor_empty(output, tensor1%rank(), tensor1%shape(), & tensor1%dtype(), tensor1%device_type(), & device_index=tensor1%device_index(), & requires_grad=tensor1%requires_grad()) end if call torch_tensor_add_c(output%p,tensor1%p, tensor2%p) end function torch_tensor_add !> Overloads negative operator for a single tensor. function torch_tensor_negative(tensor) result(output) use, intrinsic :: iso_c_binding, only : c_associated type(torch_tensor), intent(in) :: tensor !! Tensor to take the negative of type(torch_tensor) :: output !! Tensor to hold the negative values interface subroutine torch_tensor_negative_c(output_c, tensor_c) bind(c, name = "torch_tensor_negative") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c type(c_ptr), value, intent(in) :: output_c end subroutine torch_tensor_negative_c end interface if (.not. c_associated(output%p)) then call torch_tensor_empty(output, tensor%rank(), tensor%shape(), tensor%dtype(), & tensor%device_type(), device_index=tensor%device_index(), & requires_grad=tensor%requires_grad()) end if call torch_tensor_negative_c(output%p, tensor%p) end function torch_tensor_negative !> Overloads subtraction operator for two tensors. function torch_tensor_subtract(tensor1, tensor2) result(output) use, intrinsic :: iso_c_binding, only : c_associated type(torch_tensor), intent(in) :: tensor1 !! First tensor for the subtraction type(torch_tensor), intent(in) :: tensor2 !! Second tensor for the subtraction type(torch_tensor) :: output !! Tensor to hold the difference interface subroutine torch_tensor_subtract_c(output_c, tensor1_c, tensor2_c) & bind(c, name = "torch_tensor_subtract") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: output_c type(c_ptr), value, intent(in) :: tensor1_c type(c_ptr), value, intent(in) :: tensor2_c end subroutine torch_tensor_subtract_c end interface if (tensor1%device_type() /= tensor2%device_type()) then write(*,*) "Error :: cannot subtract tensors with different device types" stop 1 end if if (tensor1%device_index() /= tensor2%device_index()) then write(*,*) "Error :: cannot subtract tensors with different device indices" stop 1 end if if (.not. c_associated(output%p)) then call torch_tensor_empty(output, tensor1%rank(), tensor1%shape(), & tensor1%dtype(), tensor1%device_type(), & device_index=tensor1%device_index(), & requires_grad=tensor1%requires_grad()) end if call torch_tensor_subtract_c(output%p, tensor1%p, tensor2%p) end function torch_tensor_subtract !> Overloads multiplication operator for two tensors. function torch_tensor_multiply(tensor1, tensor2) result(output) use, intrinsic :: iso_c_binding, only : c_associated type(torch_tensor), intent(in) :: tensor1 !! First tensor to be multiplied type(torch_tensor), intent(in) :: tensor2 !! Second tensor to be multiplied type(torch_tensor) :: output !! Tensor to hold the product if (tensor1%device_type() /= tensor2%device_type()) then write(*,*) "Error :: cannot multiply tensors with different device types" stop 1 end if if (tensor1%device_index() /= tensor2%device_index()) then write(*,*) "Error :: cannot multiply tensors with different device indices" stop 1 end if if (.not. c_associated(output%p)) then call torch_tensor_empty(output, tensor1%rank(), tensor1%shape(), & tensor1%dtype(), tensor1%device_type(), & device_index=tensor1%device_index(), & requires_grad=tensor1%requires_grad()) end if call torch_tensor_multiply_c(output%p, tensor1%p, tensor2%p) end function torch_tensor_multiply !> Overloads division operator for two tensors. function torch_tensor_divide(tensor1, tensor2) result(output) use, intrinsic :: iso_c_binding, only : c_associated type(torch_tensor), intent(in) :: tensor1 !! First tensor for the division type(torch_tensor), intent(in) :: tensor2 !! Second tensor for the division type(torch_tensor) :: output !! Tensor to hold the quotient if (tensor1%device_type() /= tensor2%device_type()) then write(*,*) "Error :: cannot divide tensors with different device types" stop 1 end if if (tensor1%device_index() /= tensor2%device_index()) then write(*,*) "Error :: cannot divide tensors with different device indices" stop 1 end if if (.not. c_associated(output%p)) then call torch_tensor_empty(output, tensor1%rank(), tensor1%shape(), & tensor1%dtype(), tensor1%device_type(), & device_index=tensor1%device_index(), & requires_grad=tensor1%requires_grad()) end if call torch_tensor_divide_c(output%p, tensor1%p, tensor2%p) end function torch_tensor_divide !> Overloads exponentiation operator for a tensor and a scalar of type `int8` function torch_tensor_power_int8(tensor, power) result(output) use, intrinsic :: iso_c_binding, only : c_associated, c_loc use, intrinsic :: iso_fortran_env, only : int8 type(torch_tensor), intent(in) :: tensor !! Tensor to take the power of integer(int8), target, intent(in) :: power !! Integer exponent type(torch_tensor) :: output !! Tensor to hold the exponentiation interface subroutine torch_tensor_power_int_c(output_c, tensor_c, power_c) & bind(c, name = "torch_tensor_power_int") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: output_c type(c_ptr), value, intent(in) :: tensor_c type(c_ptr), value, intent(in) :: power_c end subroutine torch_tensor_power_int_c end interface if (.not. c_associated(output%p)) then call torch_tensor_empty(output, tensor%rank(), tensor%shape(), tensor%dtype(), & tensor%device_type(), device_index=tensor%device_index(), & requires_grad=tensor%requires_grad()) end if call torch_tensor_power_int_c(output%p, tensor%p, c_loc(power)) end function torch_tensor_power_int8 !> Overloads exponentiation operator for a tensor and a scalar of type `int16` function torch_tensor_power_int16(tensor, power) result(output) use, intrinsic :: iso_c_binding, only : c_associated, c_loc use, intrinsic :: iso_fortran_env, only : int16 type(torch_tensor), intent(in) :: tensor !! Tensor to take the power of integer(int16), target, intent(in) :: power !! Integer exponent type(torch_tensor) :: output !! Tensor to hold the exponentiation interface subroutine torch_tensor_power_int_c(output_c, tensor_c, power_c) & bind(c, name = "torch_tensor_power_int") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: output_c type(c_ptr), value, intent(in) :: tensor_c type(c_ptr), value, intent(in) :: power_c end subroutine torch_tensor_power_int_c end interface if (.not. c_associated(output%p)) then call torch_tensor_empty(output, tensor%rank(), tensor%shape(), tensor%dtype(), & tensor%device_type(), device_index=tensor%device_index(), & requires_grad=tensor%requires_grad()) end if call torch_tensor_power_int_c(output%p, tensor%p, c_loc(power)) end function torch_tensor_power_int16 !> Overloads exponentiation operator for a tensor and a scalar of type `int32` function torch_tensor_power_int32(tensor, power) result(output) use, intrinsic :: iso_c_binding, only : c_associated, c_loc use, intrinsic :: iso_fortran_env, only : int32 type(torch_tensor), intent(in) :: tensor !! Tensor to take the power of integer(int32), target, intent(in) :: power !! Integer exponent type(torch_tensor) :: output !! Tensor to hold the exponentiation interface subroutine torch_tensor_power_int_c(output_c, tensor_c, power_c) & bind(c, name = "torch_tensor_power_int") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: output_c type(c_ptr), value, intent(in) :: tensor_c type(c_ptr), value, intent(in) :: power_c end subroutine torch_tensor_power_int_c end interface if (.not. c_associated(output%p)) then call torch_tensor_empty(output, tensor%rank(), tensor%shape(), tensor%dtype(), & tensor%device_type(), device_index=tensor%device_index(), & requires_grad=tensor%requires_grad()) end if call torch_tensor_power_int_c(output%p, tensor%p, c_loc(power)) end function torch_tensor_power_int32 !> Overloads exponentiation operator for a tensor and a scalar of type `int64` function torch_tensor_power_int64(tensor, power) result(output) use, intrinsic :: iso_c_binding, only : c_associated, c_loc use, intrinsic :: iso_fortran_env, only : int64 type(torch_tensor), intent(in) :: tensor !! Tensor to take the power of integer(int64), target, intent(in) :: power !! Integer exponent type(torch_tensor) :: output !! Tensor to hold the exponentiation interface subroutine torch_tensor_power_int_c(output_c, tensor_c, power_c) & bind(c, name = "torch_tensor_power_int") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: output_c type(c_ptr), value, intent(in) :: tensor_c type(c_ptr), value, intent(in) :: power_c end subroutine torch_tensor_power_int_c end interface if (.not. c_associated(output%p)) then call torch_tensor_empty(output, tensor%rank(), tensor%shape(), tensor%dtype(), & tensor%device_type(), device_index=tensor%device_index(), & requires_grad=tensor%requires_grad()) end if call torch_tensor_power_int_c(output%p, tensor%p, c_loc(power)) end function torch_tensor_power_int64 !> Overloads exponentiation operator for a tensor and a scalar of type `real32` function torch_tensor_power_real32(tensor, power) result(output) use, intrinsic :: iso_c_binding, only : c_associated, c_loc use, intrinsic :: iso_fortran_env, only : real32 type(torch_tensor), intent(in) :: tensor !! Tensor to take the power of real(kind=real32), target, intent(in) :: power !! Floating point exponent type(torch_tensor) :: output !! Tensor to hold the exponentiation interface subroutine torch_tensor_power_float_c(output_c, tensor_c, power_c) & bind(c, name = "torch_tensor_power_float") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: output_c type(c_ptr), value, intent(in) :: tensor_c type(c_ptr), value, intent(in) :: power_c end subroutine torch_tensor_power_float_c end interface if (.not. c_associated(output%p)) then call torch_tensor_empty(output, tensor%rank(), tensor%shape(), tensor%dtype(), & tensor%device_type(), device_index=tensor%device_index(), & requires_grad=tensor%requires_grad()) end if call torch_tensor_power_float_c(output%p, tensor%p, c_loc(power)) end function torch_tensor_power_real32 !> Overloads exponentiation operator for a tensor and a scalar of type `real64` function torch_tensor_power_real64(tensor, power) result(output) use, intrinsic :: iso_c_binding, only : c_associated, c_loc use, intrinsic :: iso_fortran_env, only : real64 type(torch_tensor), intent(in) :: tensor !! Tensor to take the power of real(kind=real64), target, intent(in) :: power !! Floating point exponent type(torch_tensor) :: output !! Tensor to hold the exponentiation interface subroutine torch_tensor_power_float_c(output_c, tensor_c, power_c) & bind(c, name = "torch_tensor_power_float") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: output_c type(c_ptr), value, intent(in) :: tensor_c type(c_ptr), value, intent(in) :: power_c end subroutine torch_tensor_power_float_c end interface if (.not. c_associated(output%p)) then call torch_tensor_empty(output, tensor%rank(), tensor%shape(), tensor%dtype(), & tensor%device_type(), device_index=tensor%device_index(), & requires_grad=tensor%requires_grad()) end if call torch_tensor_power_float_c(output%p, tensor%p, c_loc(power)) end function torch_tensor_power_real64 ! ============================================================================ ! --- Other operators for computations involving tensors ! ============================================================================ !> Overloads summation operator over the values in a tensor. subroutine torch_tensor_sum(output, tensor) use, intrinsic :: iso_c_binding, only : c_associated type(torch_tensor), intent(inout) :: output !! Tensor holding the summed values type(torch_tensor), intent(in) :: tensor !! Tensor to sum the values of interface subroutine torch_tensor_sum_c(output_c, tensor_c) & bind(c, name = "torch_tensor_sum") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: output_c type(c_ptr), value, intent(in) :: tensor_c end subroutine torch_tensor_sum_c end interface if (.not. c_associated(output%p)) then write(*,*) "Error :: output tensor has not been constructed" stop 1 end if call torch_tensor_sum_c(output%p, tensor%p) end subroutine torch_tensor_sum !> Overloads mean operator over the values in a tensor. subroutine torch_tensor_mean(output, tensor) use, intrinsic :: iso_c_binding, only : c_associated type(torch_tensor), intent(inout) :: output !! Tensor holding the averaged values type(torch_tensor), intent(in) :: tensor !! Tensor to average the values of interface subroutine torch_tensor_mean_c(output_c, tensor_c) & bind(c, name = "torch_tensor_mean") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: output_c type(c_ptr), value, intent(in) :: tensor_c end subroutine torch_tensor_mean_c end interface if (.not. c_associated(output%p)) then write(*,*) "Error :: output tensor has not been constructed" stop 1 end if call torch_tensor_mean_c(output%p, tensor%p) end subroutine torch_tensor_mean ! ============================================================================ ! --- Procedures related to automatic differentation functionality for tensors ! ============================================================================ !> Resets a tensor's gradient to zero. subroutine torch_tensor_zero_grad(tensor) class(torch_tensor), intent(inout) :: tensor !! Tensor to zero the gradient of interface subroutine torch_tensor_zero_grad_c(tensor_c) bind(c, name = "torch_tensor_zero_grad") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c end subroutine torch_tensor_zero_grad_c end interface ! TODO: Call torch_tensor_get_gradient to check it exists? call torch_tensor_zero_grad_c(tensor%p) end subroutine torch_tensor_zero_grad !> Performs back-propagation on a Torch Tensor, given some external gradient. subroutine torch_tensor_backward_with_external_gradient(tensor, external_gradient, retain_graph) use, intrinsic :: iso_c_binding, only : c_bool type(torch_tensor), intent(in) :: tensor !! Tensor to compute gradients of type(torch_tensor), intent(in) :: external_gradient !! External tensor used as an initial scaling of the gradient calculation logical, optional, intent(in) :: retain_graph !! Should the computational graph be retained? ! Local arguments logical(c_bool) :: retain_graph_value interface subroutine torch_tensor_backward_with_external_gradient_c(tensor_c, external_gradient_c, & retain_graph_c) & bind(c, name = "torch_tensor_backward_with_external_gradient") use, intrinsic :: iso_c_binding, only : c_bool, c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c type(c_ptr), value, intent(in) :: external_gradient_c logical(c_bool), value, intent(in) :: retain_graph_c end subroutine torch_tensor_backward_with_external_gradient_c end interface ! Do not retain the graph by default if (present(retain_graph)) then retain_graph_value = retain_graph else retain_graph_value = .false. end if ! Call back-propagation with the provided external gradient call torch_tensor_backward_with_external_gradient_c(tensor%p, external_gradient%p, & retain_graph_value) end subroutine torch_tensor_backward_with_external_gradient !> Performs back-propagation on a Torch Tensor, with an assumed external_gradient of ones. subroutine torch_tensor_backward_without_external_gradient(tensor, retain_graph) use, intrinsic :: iso_c_binding, only : c_bool type(torch_tensor), intent(in) :: tensor !! Tensor to compute gradients of logical, optional, intent(in) :: retain_graph !! Should the computational graph be retained? ! Local arguments logical(c_bool) :: retain_graph_value integer(int64) :: sizes(1) interface subroutine torch_tensor_backward_without_external_gradient_c(tensor_c, retain_graph_c) & bind(c, name = "torch_tensor_backward_without_external_gradient") use, intrinsic :: iso_c_binding, only : c_bool, c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c logical(c_bool), value, intent(in) :: retain_graph_c end subroutine torch_tensor_backward_without_external_gradient_c end interface if (tensor%rank() == 1) then ! Accept rank-1 tensors so long as they only have a single entry sizes(:) = tensor%shape() if (sizes(1) /= 1) then write(*,*) "Error :: external gradient can only be implicitly created for scalar fields" stop 1 end if else if (tensor%rank() /= 0) then ! Disallow anything else except rank-0 tensors (i.e., 0-dim PyTorch scalars) write(*,*) "Error :: external gradient can only be implicitly created for scalar fields" stop 1 end if ! Do not retain the graph by default if (present(retain_graph)) then retain_graph_value = retain_graph else retain_graph_value = .false. end if ! Call back-propagation call torch_tensor_backward_without_external_gradient_c(tensor%p, retain_graph_value) end subroutine torch_tensor_backward_without_external_gradient !> Retrieves the gradient with respect to a Torch Tensor. subroutine torch_tensor_get_gradient(gradient, tensor) type(torch_tensor), intent(inout) :: gradient !! Tensor holding the gradient type(torch_tensor), intent(in) :: tensor !! Tensor to compute the gradient with respect to interface subroutine torch_tensor_get_gradient_c(tensor_c, gradient_c) & bind(c, name = "torch_tensor_get_gradient") use, intrinsic :: iso_c_binding, only : c_ptr implicit none type(c_ptr), value, intent(in) :: tensor_c type(c_ptr), value, intent(in) :: gradient_c end subroutine torch_tensor_get_gradient_c end interface if (.not. c_associated(gradient%p)) then write(*,*) "Error :: tensors for holding gradients must be constructed before & &retrieving values" stop 1 end if call torch_tensor_get_gradient_c(tensor%p, gradient%p) end subroutine torch_tensor_get_gradient end module ftorch_tensor