1
0
mirror of https://github.com/TREX-CoE/qmckl.git synced 2024-12-22 20:36:01 +01:00
qmckl/org/qmckl_blas.org

2759 lines
92 KiB
Org Mode
Raw Normal View History

2021-09-07 16:36:26 +02:00
#+TITLE: BLAS functions
#+SETUPFILE: ../tools/theme.setup
#+INCLUDE: ../tools/lib.org
* Headers :noexport:
#+begin_src elisp :noexport :results none
(org-babel-lob-ingest "../tools/lib.org")
#+end_src
#+begin_src c :tangle (eval h_private_type)
#ifndef QMCKL_BLAS_HPT
#define QMCKL_BLAS_HPT
#+end_src
#+begin_src c :tangle (eval h_private_func)
#ifndef QMCKL_BLAS_HPF
#define QMCKL_BLAS_HPF
#include "qmckl_blas_private_type.h"
#+end_src
#+begin_src c :tangle (eval c)
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#elif HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <assert.h>
#include <math.h>
#include "qmckl.h"
#include "qmckl_context_private_type.h"
#include "qmckl_memory_private_type.h"
#include "qmckl_blas_private_type.h"
2022-01-23 16:18:46 +01:00
#include "qmckl_memory_private_func.h"
#include "qmckl_blas_private_func.h"
#+end_src
2021-09-07 16:36:26 +02:00
#+begin_src c :comments link :tangle (eval c_test) :noweb yes
#include "qmckl.h"
2022-02-25 13:57:13 +01:00
#include <stdio.h>
#include <assert.h>
2021-09-07 16:36:26 +02:00
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2023-03-16 16:52:01 +01:00
#include "qmckl_memory_private_type.h"
#include "qmckl_blas_private_type.h"
2023-03-16 16:52:01 +01:00
#include "qmckl_memory_private_func.h"
#include "qmckl_blas_private_func.h"
2021-09-07 16:36:26 +02:00
int main() {
qmckl_context context;
context = qmckl_context_create();
#+end_src
2022-02-24 19:06:19 +01:00
* -
:PROPERTIES:
:UNNUMBERED: t
:END:
Basic linear algebra data types and operations are described in this file.
The data types are private, so that HPC implementations can use
whatever data structures they prefer.
These data types are expected to be used internally in QMCkl. They
are not intended to be passed to external codes.
2022-07-07 18:25:49 +02:00
2022-02-24 19:06:19 +01:00
* Data types
** Vector
2022-07-07 18:25:49 +02:00
| Variable | Type | Description |
|----------+-----------+-------------------------|
| ~size~ | ~int64_t~ | Dimension of the vector |
| ~data~ | ~double*~ | Elements |
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval h_private_type) :exports none
typedef struct qmckl_vector {
2022-03-21 18:32:39 +01:00
double* restrict data;
2022-04-05 11:44:17 +02:00
int64_t size;
} qmckl_vector;
#+end_src
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_vector
2022-07-07 18:25:49 +02:00
qmckl_vector_alloc( qmckl_context context,
const int64_t size);
#+end_src
Allocates a new vector. If the allocation failed the size is zero.
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_vector
2022-07-07 18:25:49 +02:00
qmckl_vector_alloc( qmckl_context context,
const int64_t size)
{
/* Should always be true by contruction */
assert (size > (int64_t) 0);
2022-07-07 18:25:49 +02:00
qmckl_vector result;
result.size = size;
qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero;
mem_info.size = size * sizeof(double);
result.data = (double*) qmckl_malloc (context, mem_info);
if (result.data == NULL) {
result.size = (int64_t) 0;
}
return result;
}
#+end_src
2022-07-07 18:25:49 +02:00
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_exit_code
2022-07-07 18:25:49 +02:00
qmckl_vector_free( qmckl_context context,
2022-02-16 15:14:41 +01:00
qmckl_vector* vector);
#+end_src
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_exit_code
2022-07-07 18:25:49 +02:00
qmckl_vector_free( qmckl_context context,
2022-02-16 15:14:41 +01:00
qmckl_vector* vector)
{
2022-07-07 18:25:49 +02:00
if (vector == NULL) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_vector_free",
"Null pointer");
}
/* Always true */
2022-02-16 15:14:41 +01:00
assert (vector->data != NULL);
2022-07-07 18:25:49 +02:00
qmckl_exit_code rc;
2022-07-07 18:25:49 +02:00
2022-02-16 15:14:41 +01:00
rc = qmckl_free(context, vector->data);
if (rc != QMCKL_SUCCESS) {
return rc;
}
2022-02-16 15:14:41 +01:00
vector->size = (int64_t) 0;
vector->data = NULL;
return QMCKL_SUCCESS;
}
#+end_src
** Matrix
2022-07-07 18:25:49 +02:00
| Variable | Type | Description |
|----------+--------------+-----------------------------|
| ~size~ | ~int64_t[2]~ | Dimension of each component |
| ~data~ | ~double*~ | Elements |
The dimensions use Fortran ordering: two elements differing by one
in the first dimension are consecutive in memory.
2022-07-07 18:25:49 +02:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval h_private_type) :exports none
typedef struct qmckl_matrix {
2022-03-21 18:32:39 +01:00
double* restrict data;
2022-04-05 11:44:17 +02:00
int64_t size[2];
} qmckl_matrix;
#+end_src
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_matrix
2022-07-07 18:25:49 +02:00
qmckl_matrix_alloc( qmckl_context context,
const int64_t size1,
const int64_t size2);
#+end_src
Allocates a new matrix. If the allocation failed the sizes are zero.
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_matrix
2022-07-07 18:25:49 +02:00
qmckl_matrix_alloc( qmckl_context context,
const int64_t size1,
const int64_t size2)
{
/* Should always be true by contruction */
assert (size1 * size2 > (int64_t) 0);
2022-07-07 18:25:49 +02:00
qmckl_matrix result;
result.size[0] = size1;
result.size[1] = size2;
qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero;
mem_info.size = size1 * size2 * sizeof(double);
result.data = (double*) qmckl_malloc (context, mem_info);
if (result.data == NULL) {
result.size[0] = (int64_t) 0;
result.size[1] = (int64_t) 0;
}
return result;
}
#+end_src
2022-07-07 18:25:49 +02:00
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_exit_code
2022-07-07 18:25:49 +02:00
qmckl_matrix_free( qmckl_context context,
2022-02-16 15:14:41 +01:00
qmckl_matrix* matrix);
#+end_src
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_exit_code
2022-07-07 18:25:49 +02:00
qmckl_matrix_free( qmckl_context context,
2022-02-16 15:14:41 +01:00
qmckl_matrix* matrix)
{
2022-07-07 18:25:49 +02:00
if (matrix == NULL) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_matrix_free",
"Null pointer");
}
/* Always true */
2022-02-16 15:14:41 +01:00
assert (matrix->data != NULL);
2022-07-07 18:25:49 +02:00
qmckl_exit_code rc;
2022-07-07 18:25:49 +02:00
2022-02-16 15:14:41 +01:00
rc = qmckl_free(context, matrix->data);
if (rc != QMCKL_SUCCESS) {
return rc;
}
2022-02-16 15:14:41 +01:00
matrix->data = NULL;
matrix->size[0] = (int64_t) 0;
matrix->size[1] = (int64_t) 0;
return QMCKL_SUCCESS;
}
#+end_src
** Tensor
2022-07-07 18:25:49 +02:00
| Variable | Type | Description |
|----------+-----------------------------------+-----------------------------|
2023-03-14 19:13:49 +01:00
| ~order~ | ~int32_t~ | Order of the tensor |
| ~size~ | ~int64_t[QMCKL_TENSOR_ORDER_MAX]~ | Dimension of each component |
| ~data~ | ~double*~ | Elements |
The dimensions use Fortran ordering: two elements differing by one
in the first dimension are consecutive in memory.
2022-07-07 18:25:49 +02:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval h_private_type) :exports none
#define QMCKL_TENSOR_ORDER_MAX 16
typedef struct qmckl_tensor {
2022-04-05 11:44:17 +02:00
double* restrict data;
2023-03-14 19:13:49 +01:00
int32_t order;
int32_t __space__;
int64_t size[QMCKL_TENSOR_ORDER_MAX];
} qmckl_tensor;
#+end_src
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_tensor
2022-07-07 18:25:49 +02:00
qmckl_tensor_alloc( qmckl_context context,
2023-03-14 19:13:49 +01:00
const int32_t order,
const int64_t* size);
#+end_src
Allocates memory for a tensor. If the allocation failed, the size
is zero.
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_tensor
2022-07-07 18:25:49 +02:00
qmckl_tensor_alloc( qmckl_context context,
2023-03-14 19:13:49 +01:00
const int32_t order,
const int64_t* size)
{
/* Should always be true by contruction */
assert (order > 0);
assert (order <= QMCKL_TENSOR_ORDER_MAX);
assert (size != NULL);
2022-07-07 18:25:49 +02:00
qmckl_tensor result;
2023-03-14 19:13:49 +01:00
memset(&result, 0, sizeof(qmckl_tensor));
result.order = order;
int64_t prod_size = (int64_t) 1;
2023-03-14 19:13:49 +01:00
for (int32_t i=0 ; i<order ; ++i) {
assert (size[i] > (int64_t) 0);
result.size[i] = size[i];
prod_size *= size[i];
}
qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero;
mem_info.size = prod_size * sizeof(double);
result.data = (double*) qmckl_malloc (context, mem_info);
if (result.data == NULL) {
memset(&result, 0, sizeof(qmckl_tensor));
}
return result;
}
#+end_src
2022-07-07 18:25:49 +02:00
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_exit_code
2022-07-07 18:25:49 +02:00
qmckl_tensor_free (qmckl_context context,
2022-02-16 15:14:41 +01:00
qmckl_tensor* tensor);
#+end_src
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_exit_code
2022-07-07 18:25:49 +02:00
qmckl_tensor_free( qmckl_context context,
2022-02-16 15:14:41 +01:00
qmckl_tensor* tensor)
{
2022-07-07 18:25:49 +02:00
if (tensor == NULL) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_tensor_free",
"Null pointer");
}
/* Always true */
2022-02-16 15:14:41 +01:00
assert (tensor->data != NULL);
2022-07-07 18:25:49 +02:00
qmckl_exit_code rc;
2022-07-07 18:25:49 +02:00
2022-02-16 15:14:41 +01:00
rc = qmckl_free(context, tensor->data);
if (rc != QMCKL_SUCCESS) {
return rc;
}
2022-07-07 18:25:49 +02:00
2022-02-16 15:14:41 +01:00
memset(tensor, 0, sizeof(qmckl_tensor));
return QMCKL_SUCCESS;
}
#+end_src
** Reshaping
Reshaping occurs in-place and the pointer to the data is copied.
2022-07-07 18:25:49 +02:00
*** Vector -> Matrix
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_matrix
qmckl_matrix_of_vector(const qmckl_vector vector,
const int64_t size1,
const int64_t size2);
#+end_src
Reshapes a vector into a matrix.
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_matrix
qmckl_matrix_of_vector(const qmckl_vector vector,
const int64_t size1,
const int64_t size2)
2022-07-07 18:25:49 +02:00
{
/* Always true */
assert (size1 * size2 == vector.size);
qmckl_matrix result;
result.size[0] = size1;
result.size[1] = size2;
result.data = vector.data;
return result;
}
#+end_src
*** Vector -> Tensor
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_tensor
qmckl_tensor_of_vector(const qmckl_vector vector,
2023-03-14 19:13:49 +01:00
const int32_t order,
const int64_t* size);
#+end_src
Reshapes a vector into a tensor.
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_tensor
qmckl_tensor_of_vector(const qmckl_vector vector,
2023-03-14 19:13:49 +01:00
const int32_t order,
const int64_t* size)
2022-07-07 18:25:49 +02:00
{
qmckl_tensor result;
int64_t prod_size = 1;
2023-03-14 19:13:49 +01:00
for (int32_t i=0 ; i<order ; ++i) {
result.size[i] = size[i];
prod_size *= size[i];
}
assert (prod_size == vector.size);
2023-03-16 16:52:01 +01:00
result.order = order;
result.data = vector.data;
return result;
}
#+end_src
*** Matrix -> Vector
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_vector
2022-01-23 16:18:46 +01:00
qmckl_vector_of_matrix(const qmckl_matrix matrix);
#+end_src
Reshapes a matrix into a vector.
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_vector
2022-01-23 16:18:46 +01:00
qmckl_vector_of_matrix(const qmckl_matrix matrix)
2022-07-07 18:25:49 +02:00
{
qmckl_vector result;
2022-01-23 16:18:46 +01:00
result.size = matrix.size[0] * matrix.size[1];
result.data = matrix.data;
return result;
}
#+end_src
*** Matrix -> Tensor
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_tensor
qmckl_tensor_of_matrix(const qmckl_matrix matrix,
2023-03-14 19:13:49 +01:00
const int32_t order,
const int64_t* size);
#+end_src
Reshapes a matrix into a tensor.
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_tensor
qmckl_tensor_of_matrix(const qmckl_matrix matrix,
2023-03-14 19:13:49 +01:00
const int32_t order,
const int64_t* size)
2022-07-07 18:25:49 +02:00
{
qmckl_tensor result;
int64_t prod_size = 1;
2023-03-14 19:13:49 +01:00
for (int32_t i=0 ; i<order ; ++i) {
result.size[i] = size[i];
prod_size *= size[i];
}
assert (prod_size == matrix.size[0] * matrix.size[1]);
result.data = matrix.data;
return result;
}
#+end_src
*** Tensor -> Vector
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_vector
2022-01-23 16:18:46 +01:00
qmckl_vector_of_tensor(const qmckl_tensor tensor);
#+end_src
Reshapes a tensor into a vector.
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_vector
2022-01-23 16:18:46 +01:00
qmckl_vector_of_tensor(const qmckl_tensor tensor)
2022-07-07 18:25:49 +02:00
{
2022-01-23 16:18:46 +01:00
int64_t prod_size = (int64_t) tensor.size[0];
2023-03-14 19:13:49 +01:00
for (int32_t i=1 ; i<tensor.order ; i++) {
prod_size *= tensor.size[i];
}
qmckl_vector result;
2022-01-23 16:18:46 +01:00
result.size = prod_size;
result.data = tensor.data;
return result;
}
#+end_src
*** Tensor -> Matrix
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_matrix
qmckl_matrix_of_tensor(const qmckl_tensor tensor,
const int64_t size1,
const int64_t size2);
#+end_src
Reshapes a tensor into a vector.
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_matrix
qmckl_matrix_of_tensor(const qmckl_tensor tensor,
const int64_t size1,
const int64_t size2)
2022-07-07 18:25:49 +02:00
{
/* Always true */
int64_t prod_size = (int64_t) 1;
2023-03-14 19:13:49 +01:00
for (int32_t i=0 ; i<tensor.order ; i++) {
prod_size *= tensor.size[i];
}
assert (prod_size == size1 * size2);
qmckl_matrix result;
result.size[0] = size1;
result.size[1] = size2;
result.data = tensor.data;
return result;
}
#+end_src
** Access macros
2022-02-24 19:06:19 +01:00
Macros are provided to ease the access to vectors, matrices and
tensors. Matrices use column-major ordering, as in Fortran.
#+begin_src c :tangle no
2022-07-07 18:25:49 +02:00
double qmckl_vec (qmckl_vector v, int64_t i); // v[i]
2022-02-24 19:06:19 +01:00
double qmckl_mat (qmckl_matrix m, int64_t i, int64_t j) // m[j][i]
double qmckl_ten3(qmckl_tensor t, int64_t i, int64_t j, int64_t k); // t[k][j][i]
double qmckl_ten4(qmckl_tensor t, int64_t i, int64_t j, int64_t k, int64_t l);
double qmckl_ten5(qmckl_tensor t, int64_t i, int64_t j, int64_t k, int64_t l, int64_t m);
double qmckl_ten6(qmckl_tensor t, int64_t i, int64_t j, int64_t k, int64_t l, int64_t m, int64_t n);
2022-02-24 19:06:19 +01:00
...
#+end_src
#+begin_src c :comments org :tangle (eval h_private_func) :exports none
#define qmckl_vec(v, i) v.data[i]
#define qmckl_mat(m, i, j) m.data[(i) + (j)*m.size[0]]
2022-02-25 20:39:20 +01:00
#define qmckl_ten3(t, i, j, k) t.data[(i) + t.size[0]*((j) + t.size[1]*(k))]
#define qmckl_ten4(t, i, j, k, l) t.data[(i) + t.size[0]*((j) + t.size[1]*((k) + t.size[2]*(l)))]
#define qmckl_ten5(t, i, j, k, l, m) t.data[(i) + t.size[0]*((j) + t.size[1]*((k) + t.size[2]*((l) + t.size[3]*(m))))]
#define qmckl_ten6(t, i, j, k, l, m, n) t.data[(i) + t.size[0]*((j) + t.size[1]*((k) + t.size[2]*((l) + t.size[3]*((m) + t.size[4]*(n)))))]
#+end_src
2022-07-07 18:25:49 +02:00
2022-02-24 19:06:19 +01:00
For example:
2022-07-07 18:25:49 +02:00
2022-02-25 20:39:20 +01:00
** Set all elements
2022-07-07 18:25:49 +02:00
2022-02-25 20:39:20 +01:00
*** Vector
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_vector
qmckl_vector_set(qmckl_vector vector, double value);
#+end_src
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_vector
qmckl_vector_set(qmckl_vector vector, double value)
{
for (int64_t i=0 ; i<vector.size ; ++i) {
qmckl_vec(vector, i) = value;
}
return vector;
}
#+end_src
*** Matrix
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_matrix
qmckl_matrix_set(qmckl_matrix matrix, double value);
#+end_src
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_matrix
qmckl_matrix_set(qmckl_matrix matrix, double value)
{
qmckl_vector vector = qmckl_vector_of_matrix(matrix);
for (int64_t i=0 ; i<vector.size ; ++i) {
qmckl_vec(vector, i) = value;
}
return qmckl_matrix_of_vector(vector, matrix.size[0], matrix.size[1]);
}
#+end_src
2022-07-07 18:25:49 +02:00
2022-02-25 20:39:20 +01:00
*** Tensor
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_tensor
qmckl_tensor_set(qmckl_tensor tensor, double value);
#+end_src
#+begin_src c :comments org :tangle (eval c) :exports none
qmckl_tensor
qmckl_tensor_set(qmckl_tensor tensor, double value)
{
qmckl_vector vector = qmckl_vector_of_tensor(tensor);
2023-03-16 16:52:01 +01:00
for (int64_t i=0 ; i<vector.size ; ++i) {
2022-02-25 20:39:20 +01:00
qmckl_vec(vector, i) = value;
}
return qmckl_tensor_of_vector(vector, tensor.order, tensor.size);
}
#+end_src
2022-07-07 18:25:49 +02:00
2022-01-23 16:18:46 +01:00
** Copy to/from to ~double*~
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_exit_code
qmckl_double_of_vector(const qmckl_context context,
const qmckl_vector vector,
double* const target,
const int64_t size_max);
#+end_src
Converts a vector to a ~double*~.
2022-07-07 18:25:49 +02:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
2022-01-23 16:18:46 +01:00
qmckl_exit_code
qmckl_double_of_vector(const qmckl_context context,
const qmckl_vector vector,
double* const target,
const int64_t size_max)
{
/* Always true by construction */
assert (qmckl_context_check(context) != QMCKL_NULL_CONTEXT);
assert (vector.size > (int64_t) 0);
assert (target != NULL);
assert (size_max > (int64_t) 0);
assert (size_max >= vector.size);
memcpy(target, vector.data, vector.size*sizeof(double));
2022-01-23 16:18:46 +01:00
return QMCKL_SUCCESS;
}
#+end_src
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_exit_code
qmckl_double_of_matrix(const qmckl_context context,
const qmckl_matrix matrix,
double* const target,
const int64_t size_max);
#+end_src
Converts a matrix to a ~double*~.
2022-07-07 18:25:49 +02:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
2022-01-23 16:18:46 +01:00
qmckl_exit_code
qmckl_double_of_matrix(const qmckl_context context,
const qmckl_matrix matrix,
double* const target,
const int64_t size_max)
{
qmckl_vector vector = qmckl_vector_of_matrix(matrix);
return qmckl_double_of_vector(context, vector, target, size_max);
}
#+end_src
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_exit_code
qmckl_double_of_tensor(const qmckl_context context,
const qmckl_tensor tensor,
double* const target,
const int64_t size_max);
#+end_src
Converts a tensor to a ~double*~.
2022-07-07 18:25:49 +02:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
2022-01-23 16:18:46 +01:00
qmckl_exit_code
qmckl_double_of_tensor(const qmckl_context context,
const qmckl_tensor tensor,
double* const target,
const int64_t size_max)
{
qmckl_vector vector = qmckl_vector_of_tensor(tensor);
return qmckl_double_of_vector(context, vector, target, size_max);
}
#+end_src
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_exit_code
qmckl_vector_of_double(const qmckl_context context,
const double* target,
const int64_t size_max,
qmckl_vector* vector);
#+end_src
Converts a ~double*~ to a vector.
2022-07-07 18:25:49 +02:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
2022-01-23 16:18:46 +01:00
qmckl_exit_code
qmckl_vector_of_double(const qmckl_context context,
const double* target,
const int64_t size_max,
qmckl_vector* vector_out)
{
qmckl_vector vector = *vector_out;
/* Always true by construction */
assert (qmckl_context_check(context) != QMCKL_NULL_CONTEXT);
if (vector.size == 0) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_4,
"qmckl_double_of_vector",
"Vector not allocated");
}
if (vector.size != size_max) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_4,
"qmckl_double_of_vector",
"Wrong vector size");
}
for (int64_t i=0 ; i<vector.size ; ++i) {
vector.data[i] = target[i];
}
*vector_out = vector;
return QMCKL_SUCCESS;
}
#+end_src
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_exit_code
qmckl_matrix_of_double(const qmckl_context context,
const double* target,
const int64_t size_max,
qmckl_matrix* matrix);
#+end_src
2022-02-24 19:06:19 +01:00
Converts a ~double*~ to a matrix.
2022-07-07 18:25:49 +02:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
2022-01-23 16:18:46 +01:00
qmckl_exit_code
qmckl_matrix_of_double(const qmckl_context context,
const double* target,
const int64_t size_max,
qmckl_matrix* matrix)
{
qmckl_vector vector = qmckl_vector_of_matrix(*matrix);
qmckl_exit_code rc =
qmckl_vector_of_double(context, target, size_max, &vector);
,*matrix = qmckl_matrix_of_vector(vector, matrix->size[0], matrix->size[1]);
return rc;
}
#+end_src
#+begin_src c :comments org :tangle (eval h_private_func)
qmckl_exit_code
qmckl_tensor_of_double(const qmckl_context context,
const double* target,
const int64_t size_max,
qmckl_tensor* tensor);
#+end_src
2022-02-24 19:06:19 +01:00
Converts a ~double*~ to a tensor.
2022-07-07 18:25:49 +02:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments org :tangle (eval c) :exports none
2022-01-23 16:18:46 +01:00
qmckl_exit_code
qmckl_tensor_of_double(const qmckl_context context,
const double* target,
const int64_t size_max,
qmckl_tensor* tensor)
{
qmckl_vector vector = qmckl_vector_of_tensor(*tensor);
qmckl_exit_code rc =
qmckl_vector_of_double(context, target, size_max, &vector);
*tensor = qmckl_tensor_of_vector(vector, tensor->order, tensor->size);
return rc;
}
#+end_src
2023-03-16 16:52:01 +01:00
** Allocate and copy to ~double*~
#+begin_src c :comments org :tangle (eval h_private_func)
double* qmckl_alloc_double_of_vector(const qmckl_context context,
const qmckl_vector vector);
#+end_src
#+begin_src c :comments org :tangle (eval c) :exports none
double* qmckl_alloc_double_of_vector(const qmckl_context context,
const qmckl_vector vector)
{
/* Always true by construction */
assert (qmckl_context_check(context) != QMCKL_NULL_CONTEXT);
assert (vector.size > (int64_t) 0);
qmckl_memory_info_struct mem_info = qmckl_memory_info_struct_zero;
mem_info.size = vector.size * sizeof(double);
double* target = (double*) qmckl_malloc(context, mem_info);
if (target == NULL) {
return NULL;
}
qmckl_exit_code rc;
rc = qmckl_double_of_vector(context, vector, target, vector.size);
assert (rc == QMCKL_SUCCESS);
if (rc != QMCKL_SUCCESS) {
rc = qmckl_free(context, target);
target = NULL;
}
return target;
}
#+end_src
#+begin_src c :comments org :tangle (eval h_private_func)
double* qmckl_alloc_double_of_matrix(const qmckl_context context,
const qmckl_matrix matrix);
#+end_src
#+begin_src c :comments org :tangle (eval c) :exports none
double* qmckl_alloc_double_of_matrix(const qmckl_context context,
const qmckl_matrix matrix)
{
qmckl_vector vector = qmckl_vector_of_matrix(matrix);
return qmckl_alloc_double_of_vector(context, vector);
}
#+end_src
#+begin_src c :comments org :tangle (eval h_private_func)
double* qmckl_alloc_double_of_tensor(const qmckl_context context,
const qmckl_tensor tensor);
#+end_src
#+begin_src c :comments org :tangle (eval c) :exports none
double* qmckl_alloc_double_of_tensor(const qmckl_context context,
const qmckl_tensor tensor)
{
qmckl_vector vector = qmckl_vector_of_tensor(tensor);
return qmckl_alloc_double_of_vector(context, vector);
}
#+end_src
2022-02-24 19:06:19 +01:00
** Tests :noexport:
2022-01-23 16:18:46 +01:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments link :tangle (eval c_test) :exports none
{
int64_t m = 3;
int64_t n = 4;
int64_t p = m*n;
qmckl_vector vec = qmckl_vector_alloc(context, p);
2022-07-07 18:25:49 +02:00
for (int64_t i=0 ; i<p ; ++i)
qmckl_vec(vec, i) = (double) i;
2022-07-07 18:25:49 +02:00
for (int64_t i=0 ; i<p ; ++i)
assert( vec.data[i] == (double) i );
2023-03-16 16:52:01 +01:00
printf("qmckl_vector ok\n");
qmckl_matrix mat = qmckl_matrix_of_vector(vec, m, n);
assert (mat.size[0] == m);
assert (mat.size[1] == n);
assert (mat.data == vec.data);
2022-07-07 18:25:49 +02:00
for (int64_t j=0 ; j<n ; ++j)
for (int64_t i=0 ; i<m ; ++i)
assert ( qmckl_mat(mat, i, j) == qmckl_vec(vec, i+j*m)) ;
2023-03-16 16:52:01 +01:00
printf("qmckl_matrix_of_vector ok\n");
2022-01-23 16:18:46 +01:00
qmckl_vector vec2 = qmckl_vector_of_matrix(mat);
assert (vec2.size == p);
assert (vec2.data == vec.data);
2022-07-07 18:25:49 +02:00
for (int64_t i=0 ; i<p ; ++i)
assert ( qmckl_vec(vec2, i) == qmckl_vec(vec, i) ) ;
2023-03-16 16:52:01 +01:00
printf("qmckl_vector_of_matrix ok\n");
double* dbl = qmckl_alloc_double_of_matrix(context, mat);
for (int64_t i=0 ; i<p ; ++i)
assert ( dbl[i] == qmckl_vec(vec, i) ) ;
printf("qmckl_double_of_matrix ok\n");
qmckl_exit_code rc = qmckl_free(context, dbl);
assert (rc == QMCKL_SUCCESS);
printf("qmckl_free ok\n");
2022-02-16 15:14:41 +01:00
qmckl_vector_free(context, &vec);
2023-03-16 16:52:01 +01:00
printf("qmckl_vector_free ok\n");
}
#+end_src
2021-09-07 16:36:26 +02:00
* Matrix operations
** ~qmckl_dgemm~
2022-01-08 15:36:07 +01:00
2022-02-24 19:06:19 +01:00
Matrix multiplication with a BLAS interface:
2021-10-14 21:53:00 +02:00
2022-01-06 00:51:42 +01:00
\[
C_{ij} = \beta C_{ij} + \alpha \sum_{k} A_{ik} \cdot B_{kj}
2022-01-08 15:36:07 +01:00
\]
2022-01-06 00:51:42 +01:00
# TODO: Add description about the external library dependence.
2021-09-07 16:36:26 +02:00
#+NAME: qmckl_dgemm_args
2022-01-06 00:51:42 +01:00
| Variable | Type | In/Out | Description |
|-----------+-----------------+--------+---------------------------------------|
| ~context~ | ~qmckl_context~ | in | Global state |
2022-01-06 02:28:13 +01:00
| ~TransA~ | ~char~ | in | 'T' is transposed |
| ~TransB~ | ~char~ | in | 'T' is transposed |
2022-01-06 00:51:42 +01:00
| ~m~ | ~int64_t~ | in | Number of rows of the input matrix |
| ~n~ | ~int64_t~ | in | Number of columns of the input matrix |
| ~k~ | ~int64_t~ | in | Number of columns of the input matrix |
2022-01-23 16:18:46 +01:00
| ~alpha~ | ~double~ | in | \alpha |
2022-01-06 00:51:42 +01:00
| ~A~ | ~double[][lda]~ | in | Array containing the matrix $A$ |
| ~lda~ | ~int64_t~ | in | Leading dimension of array ~A~ |
| ~B~ | ~double[][ldb]~ | in | Array containing the matrix $B$ |
| ~ldb~ | ~int64_t~ | in | Leading dimension of array ~B~ |
2022-01-23 16:18:46 +01:00
| ~beta~ | ~double~ | in | \beta |
| ~C~ | ~double[][ldc]~ | out | Array containing the matrix $C$ |
| ~ldc~ | ~int64_t~ | in | Leading dimension of array ~C~ |
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
Requirements:
2021-09-07 16:36:26 +02:00
- ~context~ is not ~QMCKL_NULL_CONTEXT~
- ~m > 0~
- ~n > 0~
- ~k > 0~
- ~lda >= m~
- ~ldb >= n~
- ~ldc >= n~
- ~A~ is allocated with at least $m \times k \times 8$ bytes
- ~B~ is allocated with at least $k \times n \times 8$ bytes
- ~C~ is allocated with at least $m \times n \times 8$ bytes
2022-01-08 15:36:07 +01:00
2021-09-07 16:36:26 +02:00
#+CALL: generate_c_header(table=qmckl_dgemm_args,rettyp="qmckl_exit_code",fname="qmckl_dgemm")
#+RESULTS:
2022-01-06 00:51:42 +01:00
#+begin_src c :tangle (eval h_func) :comments org
2021-09-07 16:36:26 +02:00
qmckl_exit_code qmckl_dgemm (
2022-01-06 00:51:42 +01:00
const qmckl_context context,
2022-01-06 02:28:13 +01:00
const char TransA,
const char TransB,
2022-01-06 00:51:42 +01:00
const int64_t m,
const int64_t n,
const int64_t k,
const double alpha,
const double* A,
const int64_t lda,
const double* B,
const int64_t ldb,
const double beta,
double* const C,
2023-09-22 16:56:48 +02:00
const int64_t ldc );
2022-01-06 00:51:42 +01:00
#+end_src
2022-02-24 19:06:19 +01:00
#+begin_src f90 :tangle (eval f) :exports none
2023-09-22 16:56:48 +02:00
function qmckl_dgemm(context, TransA, TransB, &
2022-01-06 00:51:42 +01:00
m, n, k, alpha, A, LDA, B, LDB, beta, C, LDC) &
2023-09-22 16:56:48 +02:00
bind(C) result(info)
use, intrinsic :: iso_c_binding
use qmckl_constants
#ifdef HAVE_LIBQMCKLDGEMM
use qmckl_dgemm_tiled_module
#endif
2021-09-07 16:36:26 +02:00
implicit none
2023-09-22 16:56:48 +02:00
integer (qmckl_context), intent(in) , value :: context
character(c_char ) , intent(in) , value :: TransA
character(c_char ) , intent(in) , value :: TransB
integer (c_int64_t) , intent(in) , value :: m
integer (c_int64_t) , intent(in) , value :: n
integer (c_int64_t) , intent(in) , value :: k
real (c_double ) , intent(in) , value :: alpha
real (c_double ) , intent(in) :: A(lda,*)
integer (c_int64_t) , intent(in) , value :: lda
real (c_double ) , intent(in) :: B(ldb,*)
integer (c_int64_t) , intent(in) , value :: ldb
real (c_double ) , intent(in) , value :: beta
real (c_double ) , intent(out) :: C(ldc,*)
integer (c_int64_t) , intent(in) , value :: ldc
integer(qmckl_exit_code) :: info
#ifdef HAVE_LIBQMCKLDGEMM
double precision,allocatable,dimension(:,:) :: A1
double precision,allocatable,dimension(:,:) :: B1
double precision,allocatable,dimension(:,:) :: C1
2023-09-22 16:56:48 +02:00
#endif
integer*8 :: i, j, LDA1, LDB1, LDC1
2021-12-12 20:02:43 +01:00
2022-01-08 15:36:07 +01:00
info = QMCKL_SUCCESS
2021-09-07 16:36:26 +02:00
if (context == QMCKL_NULL_CONTEXT) then
info = QMCKL_INVALID_CONTEXT
return
endif
2022-01-08 15:36:07 +01:00
2021-09-07 16:36:26 +02:00
if (m <= 0_8) then
info = QMCKL_INVALID_ARG_4
return
endif
2022-01-08 15:36:07 +01:00
2021-09-07 16:36:26 +02:00
if (n <= 0_8) then
info = QMCKL_INVALID_ARG_5
return
endif
2022-01-08 15:36:07 +01:00
2021-09-07 16:36:26 +02:00
if (k <= 0_8) then
info = QMCKL_INVALID_ARG_6
return
endif
2022-01-08 15:36:07 +01:00
2022-01-06 02:28:13 +01:00
if (LDA <= 0) then
2021-09-07 16:36:26 +02:00
info = QMCKL_INVALID_ARG_9
return
endif
2022-01-06 02:28:13 +01:00
if (LDB <= 0) then
info = QMCKL_INVALID_ARG_11
2021-09-07 16:36:26 +02:00
return
endif
2022-01-06 02:28:13 +01:00
if (LDC <= 0) then
info = QMCKL_INVALID_ARG_14
2021-09-07 16:36:26 +02:00
return
endif
#ifdef HAVE_LIBQMCKLDGEMM
! Copy A to A1
allocate(A1(k,m))
do j=1,m
2023-09-22 16:56:48 +02:00
do i=1,k
A1(i,j) = A(j,i)
end do
end do
! Copy B to B1
allocate(B1(n,k))
do j=1,k
2023-09-22 16:56:48 +02:00
do i=1,n
B1(i,j) = B(j,i)
end do
end do
! Copy C to C1
allocate(C1(n,m))
do j=1,m
2023-09-22 16:56:48 +02:00
do i=1,n
C1(i,j) = C(j,i)
end do
end do
LDA1 = size(A1,1)
LDB1 = size(B1,1)
LDC1 = size(C1,1)
info = qmckl_dgemm_tiled_avx2(int(m,8), int(n,8), int(k,8), &
A1, int(LDA1,8), B1, int(LDB1,8), C1, int(LDC1,8))
do j=1,n
2023-03-16 16:52:01 +01:00
do i=1,m
2023-09-22 16:56:48 +02:00
transpose C(i,j) = alpha*C1(j,i) + beta*C(i,j)
2023-03-16 16:52:01 +01:00
end do
end do
deallocate(A1,B1,C1)
#else
call dgemm(transA, transB, int(m,4), int(n,4), int(k,4), &
alpha, A, int(LDA,4), B, int(LDB,4), beta, C, int(LDC,4))
#endif
2021-09-07 16:36:26 +02:00
2023-09-22 16:56:48 +02:00
end function qmckl_dgemm
2022-01-06 00:51:42 +01:00
#+end_src
2022-01-08 15:36:07 +01:00
2023-09-22 16:56:48 +02:00
*** C interface :noexport:
2021-09-07 16:36:26 +02:00
#+CALL: generate_f_interface(table=qmckl_dgemm_args,rettyp="qmckl_exit_code",fname="qmckl_dgemm")
#+RESULTS:
#+begin_src f90 :tangle (eval fh_func) :comments org :exports none
2022-01-06 00:51:42 +01:00
interface
2023-09-22 16:56:48 +02:00
integer(qmckl_exit_code) function qmckl_dgemm &
2021-09-15 11:55:45 +02:00
(context, TransA, TransB, m, n, k, alpha, A, lda, B, ldb, beta, C, ldc) &
2021-09-07 16:36:26 +02:00
bind(C)
2022-01-06 00:51:42 +01:00
use, intrinsic :: iso_c_binding
import
implicit none
2023-09-22 16:56:48 +02:00
integer (qmckl_context), intent(in) , value :: context
character(c_char ) , intent(in) , value :: TransA
character(c_char ) , intent(in) , value :: TransB
2022-01-06 00:51:42 +01:00
integer (c_int64_t) , intent(in) , value :: m
integer (c_int64_t) , intent(in) , value :: n
integer (c_int64_t) , intent(in) , value :: k
real (c_double ) , intent(in) , value :: alpha
real (c_double ) , intent(in) :: A(lda,*)
integer (c_int64_t) , intent(in) , value :: lda
real (c_double ) , intent(in) :: B(ldb,*)
integer (c_int64_t) , intent(in) , value :: ldb
real (c_double ) , intent(in) , value :: beta
real (c_double ) , intent(out) :: C(ldc,*)
integer (c_int64_t) , intent(in) , value :: ldc
end function qmckl_dgemm
end interface
2021-09-07 16:36:26 +02:00
#+end_src
2022-01-08 15:36:07 +01:00
2021-09-07 16:36:26 +02:00
*** Test :noexport:
2022-01-06 00:51:42 +01:00
2021-09-07 16:36:26 +02:00
#+begin_src f90 :tangle (eval f_test)
integer(qmckl_exit_code) function test_qmckl_dgemm(context) bind(C)
use qmckl
implicit none
integer(qmckl_context), intent(in), value :: context
2022-01-08 15:36:07 +01:00
2021-09-07 16:36:26 +02:00
double precision, allocatable :: A(:,:), B(:,:), C(:,:), D(:,:)
integer*8 :: m, n, k, LDA, LDB, LDC
2021-09-15 11:55:45 +02:00
integer*8 :: i,j,l
2022-01-06 02:28:13 +01:00
character :: TransA, TransB
2021-09-15 11:55:45 +02:00
double precision :: x, alpha, beta
2022-01-08 15:36:07 +01:00
2022-01-06 02:28:13 +01:00
TransA = 'N'
TransB = 'N'
2021-09-27 23:36:11 +02:00
m = 1_8
2021-09-15 11:55:45 +02:00
k = 4_8
n = 6_8
2021-09-07 16:36:26 +02:00
LDA = m
LDB = k
LDC = m
allocate( A(LDA,k), B(LDB,n) , C(LDC,n), D(LDC,n))
2022-01-08 15:36:07 +01:00
2021-09-07 16:36:26 +02:00
A = 0.d0
B = 0.d0
C = 0.d0
D = 0.d0
2021-09-15 16:21:42 +02:00
alpha = 1.0d0
beta = 0.0d0
do j=1,k
do i=1,m
2021-09-07 16:36:26 +02:00
A(i,j) = -10.d0 + dble(i+j)
end do
end do
2022-01-08 15:36:07 +01:00
2021-09-15 16:21:42 +02:00
do j=1,n
do i=1,k
2021-09-07 16:36:26 +02:00
B(i,j) = -10.d0 + dble(i+j)
end do
end do
2022-01-08 15:36:07 +01:00
2023-03-16 16:52:01 +01:00
test_qmckl_dgemm = qmckl_dgemm(context, TransA, TransB, m, n, k, &
alpha, A, LDA, B, LDB, beta, C, LDC)
2022-01-08 15:36:07 +01:00
2021-09-07 16:36:26 +02:00
if (test_qmckl_dgemm /= QMCKL_SUCCESS) return
2022-01-08 15:36:07 +01:00
2021-09-07 16:36:26 +02:00
test_qmckl_dgemm = QMCKL_FAILURE
2022-01-08 15:36:07 +01:00
2021-09-07 16:36:26 +02:00
x = 0.d0
2021-09-15 16:21:42 +02:00
do j=1,n
do i=1,m
2021-12-12 20:02:43 +01:00
do l=1,k
D(i,j) = D(i,j) + A(i,l)*B(l,j)
end do
x = x + (D(i,j) - C(i,j))**2
2021-09-07 16:36:26 +02:00
end do
end do
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
if (dabs(x) <= 1.d-12) then
2021-09-07 16:36:26 +02:00
test_qmckl_dgemm = QMCKL_SUCCESS
endif
2022-01-08 15:36:07 +01:00
2021-09-15 16:21:42 +02:00
deallocate(A,B,C,D)
2021-12-12 20:02:43 +01:00
2021-09-07 16:36:26 +02:00
end function test_qmckl_dgemm
#+end_src
2021-10-14 21:53:00 +02:00
2022-02-24 19:06:19 +01:00
#+begin_src c :comments link :tangle (eval c_test) :exports none
2021-09-07 16:36:26 +02:00
qmckl_exit_code test_qmckl_dgemm(qmckl_context context);
assert(QMCKL_SUCCESS == test_qmckl_dgemm(context));
2023-03-16 16:52:01 +01:00
printf("qmckl_dgemm ok\n");
2021-09-07 16:36:26 +02:00
#+end_src
2022-08-22 12:05:28 +02:00
** ~qmckl_dgemm_safe~
2022-08-22 17:31:15 +02:00
"Size-safe" proxy function with the same functionality as ~qmckl_dgemm~
2022-08-22 12:05:28 +02:00
but with 3 additional arguments. These arguments ~size_max_M~ (where ~M~ is a matix)
are required primarily for the Python API, where compatibility with
NumPy arrays implies that sizes of the input and output arrays are provided.
#+NAME: qmckl_dgemm_safe_args
| Variable | Type | In/Out | Description |
|--------------+-----------------+--------+---------------------------------------|
| ~context~ | ~qmckl_context~ | in | Global state |
| ~TransA~ | ~char~ | in | 'T' is transposed |
| ~TransB~ | ~char~ | in | 'T' is transposed |
| ~m~ | ~int64_t~ | in | Number of rows of the input matrix |
| ~n~ | ~int64_t~ | in | Number of columns of the input matrix |
| ~k~ | ~int64_t~ | in | Number of columns of the input matrix |
| ~alpha~ | ~double~ | in | \alpha |
| ~A~ | ~double[][lda]~ | in | Array containing the matrix $A$ |
| ~size_max_A~ | ~int64_t~ | in | Size of the matrix $A$ |
| ~lda~ | ~int64_t~ | in | Leading dimension of array ~A~ |
| ~B~ | ~double[][ldb]~ | in | Array containing the matrix $B$ |
| ~size_max_B~ | ~int64_t~ | in | Size of the matrix $B$ |
| ~ldb~ | ~int64_t~ | in | Leading dimension of array ~B~ |
| ~beta~ | ~double~ | in | \beta |
| ~C~ | ~double[][ldc]~ | out | Array containing the matrix $C$ |
| ~size_max_C~ | ~int64_t~ | in | Size of the matrix $C$ |
| ~ldc~ | ~int64_t~ | in | Leading dimension of array ~C~ |
Requirements:
- ~context~ is not ~QMCKL_NULL_CONTEXT~
- ~m > 0~
- ~n > 0~
- ~k > 0~
- ~lda >= m~
- ~ldb >= n~
- ~ldc >= n~
- ~A~ is allocated with at least $m \times k \times 8$ bytes
- ~B~ is allocated with at least $k \times n \times 8$ bytes
- ~C~ is allocated with at least $m \times n \times 8$ bytes
- ~size_max_A >= m * k~
- ~size_max_B >= k * n~
- ~size_max_C >= m * n~
#+CALL: generate_c_header(table=qmckl_dgemm_safe_args,rettyp="qmckl_exit_code",fname="qmckl_dgemm_safe")
#+RESULTS:
#+BEGIN_src c :tangle (eval h_func) :comments org
qmckl_exit_code qmckl_dgemm_safe (
const qmckl_context context,
const char TransA,
const char TransB,
const int64_t m,
const int64_t n,
const int64_t k,
const double alpha,
const double* A,
const int64_t size_max_A,
const int64_t lda,
const double* B,
const int64_t size_max_B,
const int64_t ldb,
const double beta,
double* const C,
const int64_t size_max_C,
const int64_t ldc );
#+END_src
#+begin_src f90 :tangle (eval f) :exports none
2023-09-22 16:56:48 +02:00
function qmckl_dgemm_safe(context, TransA, TransB, &
2022-08-22 12:05:28 +02:00
m, n, k, alpha, A, size_A, LDA, B, size_B, LDB, beta, C, size_C, LDC) &
2023-09-22 16:56:48 +02:00
result(info) bind(C)
use, intrinsic :: iso_c_binding
use qmckl_constants
2022-08-22 12:05:28 +02:00
implicit none
2023-09-22 16:56:48 +02:00
integer (qmckl_context), intent(in) , value :: context
character(c_char ) , intent(in) , value :: TransA
character(c_char ) , intent(in) , value :: TransB
integer (c_int64_t) , intent(in) , value :: m
integer (c_int64_t) , intent(in) , value :: n
integer (c_int64_t) , intent(in) , value :: k
real (c_double ) , intent(in) , value :: alpha
real (c_double ) , intent(in) :: A(lda,*)
integer (c_int64_t) , intent(in) , value :: size_A
integer (c_int64_t) , intent(in) , value :: lda
real (c_double ) , intent(in) :: B(ldb,*)
integer (c_int64_t) , intent(in) , value :: size_B
integer (c_int64_t) , intent(in) , value :: ldb
real (c_double ) , intent(in) , value :: beta
real (c_double ) , intent(out) :: C(ldc,*)
integer (c_int64_t) , intent(in) , value :: size_C
integer (c_int64_t) , intent(in) , value :: ldc
integer(qmckl_exit_code) :: info
2022-08-22 12:05:28 +02:00
info = QMCKL_SUCCESS
if (context == QMCKL_NULL_CONTEXT) then
info = QMCKL_INVALID_CONTEXT
return
endif
if (m <= 0_8) then
info = QMCKL_INVALID_ARG_4
return
endif
if (n <= 0_8) then
info = QMCKL_INVALID_ARG_5
return
endif
if (k <= 0_8) then
info = QMCKL_INVALID_ARG_6
return
endif
if (LDA <= 0) then
info = QMCKL_INVALID_ARG_10
return
endif
if (LDB <= 0) then
info = QMCKL_INVALID_ARG_13
return
endif
if (LDC <= 0) then
info = QMCKL_INVALID_ARG_17
return
endif
if (size_A <= 0) then
info = QMCKL_INVALID_ARG_9
return
endif
if (size_B <= 0) then
info = QMCKL_INVALID_ARG_12
return
endif
if (size_C <= 0) then
info = QMCKL_INVALID_ARG_16
return
endif
call dgemm(transA, transB, int(m,4), int(n,4), int(k,4), &
alpha, A, int(LDA,4), B, int(LDB,4), beta, C, int(LDC,4))
2023-09-22 16:56:48 +02:00
end function qmckl_dgemm_safe
2022-08-22 12:05:28 +02:00
#+end_src
*** C interface :noexport:
#+CALL: generate_f_interface(table=qmckl_dgemm_safe_args,rettyp="qmckl_exit_code",fname="qmckl_dgemm_safe")
#+RESULTS:
#+begin_src f90 :tangle (eval fh_func) :comments org :exports none
interface
2023-09-22 16:56:48 +02:00
integer(qmckl_exit_code) function qmckl_dgemm_safe &
(context, TransA, TransB, m, n, k, alpha, A, size_max_A, lda, B, size_max_B, ldb, beta, C, size_max_C, ldc) &
2022-08-22 12:05:28 +02:00
bind(C)
use, intrinsic :: iso_c_binding
import
implicit none
2023-09-22 16:56:48 +02:00
integer (qmckl_context), intent(in) , value :: context
character(c_char ) , intent(in) , value :: TransA
character(c_char ) , intent(in) , value :: TransB
2022-08-22 12:05:28 +02:00
integer (c_int64_t) , intent(in) , value :: m
integer (c_int64_t) , intent(in) , value :: n
integer (c_int64_t) , intent(in) , value :: k
real (c_double ) , intent(in) , value :: alpha
real (c_double ) , intent(in) :: A(lda,*)
2023-09-22 16:56:48 +02:00
integer (c_int64_t) , intent(in) , value :: size_max_A
2022-08-22 12:05:28 +02:00
integer (c_int64_t) , intent(in) , value :: lda
real (c_double ) , intent(in) :: B(ldb,*)
2023-09-22 16:56:48 +02:00
integer (c_int64_t) , intent(in) , value :: size_max_B
2022-08-22 12:05:28 +02:00
integer (c_int64_t) , intent(in) , value :: ldb
real (c_double ) , intent(in) , value :: beta
real (c_double ) , intent(out) :: C(ldc,*)
2023-09-22 16:56:48 +02:00
integer (c_int64_t) , intent(in) , value :: size_max_C
2022-08-22 12:05:28 +02:00
integer (c_int64_t) , intent(in) , value :: ldc
end function qmckl_dgemm_safe
end interface
#+end_src
2022-01-23 16:18:46 +01:00
** ~qmckl_matmul~
2022-02-24 19:06:19 +01:00
Matrix multiplication using the =qmckl_matrix= data type:
2022-01-23 16:18:46 +01:00
\[
C_{ij} = \beta C_{ij} + \alpha \sum_{k} A_{ik} \cdot B_{kj}
\]
# TODO: Add description about the external library dependence.
#+NAME: qmckl_matmul_args
| Variable | Type | In/Out | Description |
|-----------+-----------------+--------+-------------------|
| ~context~ | ~qmckl_context~ | in | Global state |
| ~TransA~ | ~char~ | in | 'T' is transposed |
| ~TransB~ | ~char~ | in | 'T' is transposed |
| ~alpha~ | ~double~ | in | \alpha |
| ~A~ | ~qmckl_matrix~ | in | Matrix $A$ |
| ~B~ | ~qmckl_matrix~ | in | Matrix $B$ |
| ~beta~ | ~double~ | in | \beta |
| ~C~ | ~qmckl_matrix~ | out | Matrix $C$ |
#+CALL: generate_c_header(table=qmckl_matmul_args,rettyp="qmckl_exit_code",fname="qmckl_matmul")
#+RESULTS:
#+begin_src c :tangle (eval h_private_func) :comments org
qmckl_exit_code
qmckl_matmul (const qmckl_context context,
const char TransA,
const char TransB,
const double alpha,
const qmckl_matrix A,
const qmckl_matrix B,
const double beta,
2022-07-07 18:25:49 +02:00
qmckl_matrix* const C );
2022-01-23 16:18:46 +01:00
#+end_src
2022-02-24 19:06:19 +01:00
#+begin_src c :tangle (eval c) :comments org :exports none
2022-01-23 16:18:46 +01:00
qmckl_exit_code
qmckl_matmul (const qmckl_context context,
const char TransA,
const char TransB,
const double alpha,
const qmckl_matrix A,
const qmckl_matrix B,
const double beta,
qmckl_matrix* const C )
{
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
return QMCKL_INVALID_CONTEXT;
}
qmckl_exit_code rc = QMCKL_SUCCESS;
if (TransA != 'N' && TransA != 'T') {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_matmul",
"TransA should be 'N' or 'T'");
}
if (TransB != 'N' && TransB != 'T') {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_3,
"qmckl_matmul",
"TransB should be 'N' or 'T'");
}
if (A.size[0] < 1) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_5,
"qmckl_matmul",
"Invalid size for A");
}
if (B.size[0] < 1) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_6,
"qmckl_matmul",
"Invalid size for B");
}
if (C == NULL) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_8,
"qmckl_matmul",
"Null pointer");
}
int t = 0;
if (TransA == 'T') t +=1;
if (TransB == 'T') t +=2;
/*
| t | TransA | TransB |
+---+--------+--------+
| 0 | N | N |
| 1 | T | N |
| 2 | N | T |
| 3 | T | T |
,*/
switch (t) {
case 0:
if (A.size[1] != B.size[0]) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_matmul",
"A and B have incompatible dimensions");
}
C->size[0] = A.size[0];
C->size[1] = B.size[1];
rc = qmckl_dgemm (context, 'N', 'N',
C->size[0], C->size[1], A.size[1],
alpha,
A.data, A.size[0],
B.data, B.size[0],
beta,
C->data, C->size[0]);
break;
case 1:
2022-07-07 18:25:49 +02:00
if (A.size[0] != B.size[0]) {
2022-01-23 16:18:46 +01:00
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_matmul",
"A and B have incompatible dimensions");
}
C->size[0] = A.size[1];
C->size[1] = B.size[1];
rc = qmckl_dgemm (context, 'T', 'N',
C->size[0], C->size[1], A.size[0],
alpha,
A.data, A.size[0],
B.data, B.size[0],
beta,
C->data, C->size[0]);
break;
case 2:
if (A.size[1] != B.size[1]) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_matmul",
"A and B have incompatible dimensions");
}
C->size[0] = A.size[0];
C->size[1] = B.size[0];
rc = qmckl_dgemm (context, 'N', 'T',
C->size[0], C->size[1], A.size[1],
alpha,
A.data, A.size[0],
B.data, B.size[0],
beta,
C->data, C->size[0]);
break;
case 3:
if (A.size[0] != B.size[1]) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_matmul",
"A and B have incompatible dimensions");
}
C->size[0] = A.size[1];
C->size[1] = B.size[0];
rc = qmckl_dgemm (context, 'T', 'T',
C->size[0], C->size[1], A.size[0],
alpha,
A.data, A.size[0],
B.data, B.size[0],
beta,
C->data, C->size[0]);
break;
}
return rc;
}
#+end_src
2022-02-24 19:06:19 +01:00
*** Test :noexport:
#+begin_src python :exports none :results output
import numpy as np
2022-01-23 16:18:46 +01:00
2022-07-07 18:25:49 +02:00
A = np.array([[ 1., 2., 3., 4. ],
2022-02-24 19:06:19 +01:00
[ 5., 6., 7., 8. ],
[ 9., 10., 11., 12. ]])
B = np.array([[ 1., -2., 3., 4., 5. ],
[ 5., -6., 7., 8., 9. ],
[ 9., 10., 11., 12., 13. ],
[10., 11., 12., 15., 14. ]])
C = 0.5 * A @ B
print(A.T)
print(B.T)
print(C.T)
#+end_src
2022-01-23 16:18:46 +01:00
2022-02-24 19:06:19 +01:00
#+RESULTS:
#+begin_example
[[ 1. 5. 9.]
[ 2. 6. 10.]
[ 3. 7. 11.]
[ 4. 8. 12.]]
[[ 1. 5. 9. 10.]
[-2. -6. 10. 11.]
[ 3. 7. 11. 12.]
[ 4. 8. 12. 15.]
[ 5. 9. 13. 14.]]
[[ 39. 89. 139.]
[ 30. 56. 82.]
[ 49. 115. 181.]
[ 58. 136. 214.]
[ 59. 141. 223.]]
#+end_example
#+begin_src c :comments link :tangle (eval c_test) :exports none
{
double a[12] = { 1., 5., 9.,
2., 6., 10.,
3., 7., 11.,
4., 8., 12. };
2022-07-07 18:25:49 +02:00
2022-02-24 19:06:19 +01:00
double b[20] = { 1., 5., 9., 10.,
-2., -6., 10., 11.,
3., 7., 11., 12.,
4., 8., 12., 15.,
5., 9., 13., 14. };
double c[15] = { 39., 89., 139.,
30., 56., 82.,
49., 115., 181.,
58., 136., 214.,
59., 141., 223. };
qmckl_exit_code rc;
qmckl_matrix A = qmckl_matrix_alloc(context, 3, 4);
rc = qmckl_matrix_of_double(context, a, 12, &A);
assert(rc == QMCKL_SUCCESS);
2023-03-16 16:52:01 +01:00
printf("A ok\n");
2022-02-24 19:06:19 +01:00
qmckl_matrix B = qmckl_matrix_alloc(context, 4, 5);
rc = qmckl_matrix_of_double(context, b, 20, &B);
assert(rc == QMCKL_SUCCESS);
2023-03-16 16:52:01 +01:00
printf("B ok\n");
2022-02-24 19:06:19 +01:00
qmckl_matrix C = qmckl_matrix_alloc(context, 3, 5);
rc = qmckl_matmul(context, 'N', 'N', 0.5, A, B, 0., &C);
2023-03-16 16:52:01 +01:00
printf("C ok\n");
2022-02-24 19:06:19 +01:00
assert(rc == QMCKL_SUCCESS);
2023-03-16 16:52:01 +01:00
double cnew[15];
rc = qmckl_double_of_matrix(context, C, &(cnew[0]), 15);
2022-02-24 19:06:19 +01:00
assert(rc == QMCKL_SUCCESS);
2023-03-16 16:52:01 +01:00
printf("cnew ok\n");
2022-02-24 19:06:19 +01:00
for (int i=0 ; i<15 ; ++i) {
printf("%f %f\n", cnew[i], c[i]);
assert (c[i] == cnew[i]);
}
2023-03-16 16:52:01 +01:00
printf("qmckl_matmul ok\n");
2022-07-07 18:25:49 +02:00
}
2022-02-24 19:06:19 +01:00
#+end_src
2021-12-12 20:02:43 +01:00
** ~qmckl_adjugate~
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
Given a matrix $\mathbf{A}$, the adjugate matrix
$\text{adj}(\mathbf{A})$ is the transpose of the cofactors matrix
of $\mathbf{A}$.
2021-10-04 22:45:44 +02:00
\[
2022-01-06 00:51:42 +01:00
\mathbf{B} = \text{adj}(\mathbf{A}) = \text{det}(\mathbf{A}) \, \mathbf{A}^{-1}
2021-12-12 20:02:43 +01:00
\]
2021-10-04 22:45:44 +02:00
2021-12-12 20:02:43 +01:00
See also: https://en.wikipedia.org/wiki/Adjugate_matrix
2021-10-04 22:45:44 +02:00
2021-12-12 20:02:43 +01:00
#+NAME: qmckl_adjugate_args
2022-01-06 00:51:42 +01:00
| Variable | Type | In/Out | Description |
|-----------+-----------------+--------+------------------------------------------------|
| ~context~ | ~qmckl_context~ | in | Global state |
| ~n~ | ~int64_t~ | in | Number of rows and columns of the input matrix |
| ~A~ | ~double[][lda]~ | in | Array containing the $n \times n$ matrix $A$ |
| ~lda~ | ~int64_t~ | in | Leading dimension of array ~A~ |
| ~B~ | ~double[][ldb]~ | out | Adjugate of $A$ |
| ~ldb~ | ~int64_t~ | in | Leading dimension of array ~B~ |
| ~det_l~ | ~double~ | inout | determinant of $A$ |
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
Requirements:
2021-10-04 22:45:44 +02:00
- ~context~ is not ~QMCKL_NULL_CONTEXT~
- ~n > 0~
- ~lda >= m~
2021-12-12 20:02:43 +01:00
- ~A~ is allocated with at least $m \times m \times 8$ bytes
2022-01-06 00:51:42 +01:00
- ~ldb >= m~
- ~B~ is allocated with at least $m \times m \times 8$ bytes
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
#+CALL: generate_c_header(table=qmckl_adjugate_args,rettyp="qmckl_exit_code",fname="qmckl_adjugate")
2022-01-08 15:36:07 +01:00
2021-10-04 22:45:44 +02:00
#+RESULTS:
#+begin_src c :tangle (eval h_func) :comments org
2021-12-12 20:02:43 +01:00
qmckl_exit_code qmckl_adjugate (
2022-01-06 00:51:42 +01:00
const qmckl_context context,
const int64_t n,
const double* A,
const int64_t lda,
double* const B,
const int64_t ldb,
2022-01-08 15:36:07 +01:00
double* det_l );
2021-10-04 22:45:44 +02:00
#+end_src
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
For small matrices (\le 5\times 5), we use specialized routines
for performance motivations. For larger sizes, we rely on the
LAPACK library.
2022-01-08 15:36:07 +01:00
2022-02-24 19:06:19 +01:00
#+begin_src f90 :tangle (eval f) :exports none
2023-09-22 16:56:48 +02:00
function qmckl_adjugate(context, n, A, LDA, B, ldb, det_l) &
result(info) bind(C)
use qmckl_constants
use, intrinsic :: iso_c_binding
2021-10-04 22:45:44 +02:00
implicit none
2023-09-22 16:56:48 +02:00
integer (qmckl_context), intent(in) , value :: context
integer (c_int64_t) , intent(in) , value :: n
real (c_double ) , intent(in) :: A(lda,*)
integer (c_int64_t) , intent(in) , value :: lda
real (c_double ) , intent(out) :: B(ldb,*)
integer (c_int64_t) , intent(in) , value :: ldb
real (c_double ) , intent(inout) :: det_l
integer(qmckl_exit_code) :: info
2021-12-12 20:02:43 +01:00
info = QMCKL_SUCCESS
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
if (context == QMCKL_NULL_CONTEXT) then
info = QMCKL_INVALID_CONTEXT
return
endif
2022-01-08 15:36:07 +01:00
2023-09-22 16:56:48 +02:00
if (n <= 0_8) then
2022-01-06 00:51:42 +01:00
info = QMCKL_INVALID_ARG_2
return
endif
if (LDA <= 0_8) then
info = QMCKL_INVALID_ARG_4
return
endif
2023-09-22 16:56:48 +02:00
if (LDA < n) then
2022-01-06 00:51:42 +01:00
info = QMCKL_INVALID_ARG_4
return
endif
2023-09-22 16:56:48 +02:00
select case (n)
2021-10-04 22:45:44 +02:00
case (5)
2023-09-22 16:56:48 +02:00
call adjugate5(A,LDA,B,LDB,n,det_l)
2021-10-04 22:45:44 +02:00
case (4)
2023-09-22 16:56:48 +02:00
call adjugate4(A,LDA,B,LDB,n,det_l)
2021-10-04 22:45:44 +02:00
case (3)
2023-09-22 16:56:48 +02:00
call adjugate3(A,LDA,B,LDB,n,det_l)
2021-10-04 22:45:44 +02:00
case (2)
2023-09-22 16:56:48 +02:00
call adjugate2(A,LDA,B,LDB,n,det_l)
2021-10-04 22:45:44 +02:00
case (1)
2023-09-22 16:56:48 +02:00
det_l = a(1,1)
b(1,1) = 1.d0
2022-01-06 00:51:42 +01:00
case default
2023-09-22 16:56:48 +02:00
call adjugate_general(context, n, A, LDA, B, LDB, det_l)
2021-12-12 20:02:43 +01:00
end select
2022-01-08 15:36:07 +01:00
2023-09-22 16:56:48 +02:00
end function qmckl_adjugate
2021-12-12 20:02:43 +01:00
#+end_src
2022-07-07 18:25:49 +02:00
2022-01-06 00:51:42 +01:00
#+begin_src f90 :tangle (eval f) :exports none
subroutine adjugate2(A,LDA,B,LDB,na,det_l)
2021-12-12 20:02:43 +01:00
implicit none
2022-01-06 00:51:42 +01:00
double precision, intent(in) :: A (LDA,na)
double precision, intent(out) :: B (LDA,na)
integer*8, intent(in) :: LDA, LDB
integer*8, intent(in) :: na
2021-12-12 20:02:43 +01:00
double precision, intent(inout) :: det_l
2022-01-06 00:51:42 +01:00
double precision :: C(2,2)
2022-01-08 15:36:07 +01:00
2022-01-06 02:28:13 +01:00
call cofactor2(A,LDA,C,2_8,na,det_l)
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
B(1,1) = C(1,1)
B(2,1) = C(1,2)
B(1,2) = C(2,1)
B(2,2) = C(2,2)
2021-12-12 20:02:43 +01:00
end subroutine adjugate2
2022-01-06 00:51:42 +01:00
subroutine adjugate3(a,LDA,B,LDB,na,det_l)
2021-12-12 20:02:43 +01:00
implicit none
2022-01-06 00:51:42 +01:00
double precision, intent(in) :: A (LDA,na)
double precision, intent(out) :: B (LDA,na)
integer*8, intent(in) :: LDA, LDB
integer*8, intent(in) :: na
2021-12-12 20:02:43 +01:00
double precision, intent(inout) :: det_l
2022-01-06 00:51:42 +01:00
double precision :: C(4,3)
2022-01-08 15:36:07 +01:00
2022-01-06 02:28:13 +01:00
call cofactor3(A,LDA,C,4_8,na,det_l)
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
B(1,1) = C(1,1)
B(1,2) = C(2,1)
B(1,3) = C(3,1)
B(2,1) = C(1,2)
B(2,2) = C(2,2)
B(2,3) = C(3,2)
B(3,1) = C(1,3)
B(3,2) = C(2,3)
B(3,3) = C(3,3)
2021-12-12 20:02:43 +01:00
end subroutine adjugate3
2022-01-06 00:51:42 +01:00
subroutine adjugate4(a,LDA,B,LDB,na,det_l)
2021-12-12 20:02:43 +01:00
implicit none
2022-01-06 00:51:42 +01:00
double precision, intent(in) :: A (LDA,na)
double precision, intent(out) :: B (LDA,na)
integer*8, intent(in) :: LDA, LDB
integer*8, intent(in) :: na
2021-12-12 20:02:43 +01:00
double precision, intent(inout) :: det_l
2022-01-06 00:51:42 +01:00
double precision :: C(4,4)
2022-01-08 15:36:07 +01:00
call cofactor4(A,LDA,C,4_8,na,det_l)
2022-01-06 00:51:42 +01:00
B(1,1) = C(1,1)
B(1,2) = C(2,1)
B(1,3) = C(3,1)
B(1,4) = C(4,1)
B(2,1) = C(1,2)
B(2,2) = C(2,2)
B(2,3) = C(3,2)
B(2,4) = C(4,2)
B(3,1) = C(1,3)
B(3,2) = C(2,3)
B(3,3) = C(3,3)
B(3,4) = C(4,3)
B(4,1) = C(1,4)
B(4,2) = C(2,4)
B(4,3) = C(3,4)
B(4,4) = C(4,4)
2021-12-12 20:02:43 +01:00
end subroutine adjugate4
2022-01-06 00:51:42 +01:00
subroutine adjugate5(A,LDA,B,LDB,na,det_l)
2021-12-12 20:02:43 +01:00
implicit none
2022-01-06 00:51:42 +01:00
double precision, intent(in) :: A (LDA,na)
double precision, intent(out) :: B (LDA,na)
integer*8, intent(in) :: LDA, LDB
integer*8, intent(in) :: na
2021-12-12 20:02:43 +01:00
double precision, intent(inout) :: det_l
2022-01-06 00:51:42 +01:00
double precision :: C(8,5)
2022-01-08 15:36:07 +01:00
2022-01-06 02:28:13 +01:00
call cofactor5(A,LDA,C,8_8,na,det_l)
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
B(1,1) = C(1,1)
B(1,2) = C(2,1)
B(1,3) = C(3,1)
B(1,4) = C(4,1)
B(1,5) = C(5,1)
B(2,1) = C(1,2)
B(2,2) = C(2,2)
B(2,3) = C(3,2)
B(2,4) = C(4,2)
B(2,5) = C(5,2)
B(3,1) = C(1,3)
B(3,2) = C(2,3)
B(3,3) = C(3,3)
B(3,4) = C(4,3)
B(3,5) = C(5,3)
B(4,1) = C(1,4)
B(4,2) = C(2,4)
B(4,3) = C(3,4)
B(4,4) = C(4,4)
B(4,5) = C(5,4)
B(5,1) = C(1,5)
B(5,2) = C(2,5)
B(5,3) = C(3,5)
B(5,4) = C(4,5)
B(5,5) = C(5,5)
2022-01-06 00:51:42 +01:00
end subroutine adjugate5
2021-10-04 22:45:44 +02:00
2022-01-06 00:51:42 +01:00
subroutine cofactor2(a,LDA,b,LDB,na,det_l)
2021-12-12 20:02:43 +01:00
implicit none
2022-01-06 00:51:42 +01:00
double precision, intent(in) :: A (LDA,na)
double precision, intent(out) :: B (LDA,na)
integer*8, intent(in) :: LDA, LDB
2021-12-12 20:02:43 +01:00
integer*8 :: na
double precision :: det_l
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
det_l = a(1,1)*a(2,2) - a(1,2)*a(2,1)
b(1,1) = a(2,2)
b(2,1) = -a(2,1)
b(1,2) = -a(1,2)
b(2,2) = a(1,1)
2021-12-12 20:02:43 +01:00
end subroutine cofactor2
2021-10-04 22:45:44 +02:00
2022-01-06 00:51:42 +01:00
subroutine cofactor3(a,LDA,b,LDB,na,det_l)
2021-12-12 20:02:43 +01:00
implicit none
2022-01-06 00:51:42 +01:00
double precision, intent(in) :: A (LDA,na)
double precision, intent(out) :: B (LDA,na)
integer*8, intent(in) :: LDA, LDB
integer*8, intent(in) :: na
2021-12-12 20:02:43 +01:00
double precision, intent(inout) :: det_l
integer :: i
2022-01-06 00:51:42 +01:00
2021-12-12 20:02:43 +01:00
det_l = a(1,1)*(a(2,2)*a(3,3)-a(2,3)*a(3,2)) &
-a(1,2)*(a(2,1)*a(3,3)-a(2,3)*a(3,1)) &
+a(1,3)*(a(2,1)*a(3,2)-a(2,2)*a(3,1))
2022-01-06 00:51:42 +01:00
b(1,1) = a(2,2)*a(3,3) - a(2,3)*a(3,2)
b(2,1) = a(2,3)*a(3,1) - a(2,1)*a(3,3)
b(3,1) = a(2,1)*a(3,2) - a(2,2)*a(3,1)
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
b(1,2) = a(1,3)*a(3,2) - a(1,2)*a(3,3)
b(2,2) = a(1,1)*a(3,3) - a(1,3)*a(3,1)
b(3,2) = a(1,2)*a(3,1) - a(1,1)*a(3,2)
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
b(1,3) = a(1,2)*a(2,3) - a(1,3)*a(2,2)
b(2,3) = a(1,3)*a(2,1) - a(1,1)*a(2,3)
b(3,3) = a(1,1)*a(2,2) - a(1,2)*a(2,1)
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
end subroutine cofactor3
2021-10-04 22:45:44 +02:00
2022-01-06 00:51:42 +01:00
subroutine cofactor4(a,LDA,b,LDB,na,det_l)
2021-12-12 20:02:43 +01:00
implicit none
2022-01-06 00:51:42 +01:00
double precision, intent(in) :: A (LDA,na)
double precision, intent(out) :: B (LDA,na)
integer*8, intent(in) :: LDA, LDB
integer*8, intent(in) :: na
2021-12-12 20:02:43 +01:00
double precision, intent(inout) :: det_l
integer :: i,j
det_l = a(1,1)*(a(2,2)*(a(3,3)*a(4,4)-a(3,4)*a(4,3)) &
-a(2,3)*(a(3,2)*a(4,4)-a(3,4)*a(4,2)) &
+a(2,4)*(a(3,2)*a(4,3)-a(3,3)*a(4,2))) &
-a(1,2)*(a(2,1)*(a(3,3)*a(4,4)-a(3,4)*a(4,3)) &
-a(2,3)*(a(3,1)*a(4,4)-a(3,4)*a(4,1)) &
+a(2,4)*(a(3,1)*a(4,3)-a(3,3)*a(4,1))) &
+a(1,3)*(a(2,1)*(a(3,2)*a(4,4)-a(3,4)*a(4,2)) &
-a(2,2)*(a(3,1)*a(4,4)-a(3,4)*a(4,1)) &
+a(2,4)*(a(3,1)*a(4,2)-a(3,2)*a(4,1))) &
-a(1,4)*(a(2,1)*(a(3,2)*a(4,3)-a(3,3)*a(4,2)) &
-a(2,2)*(a(3,1)*a(4,3)-a(3,3)*a(4,1)) &
+a(2,3)*(a(3,1)*a(4,2)-a(3,2)*a(4,1)))
2022-01-06 00:51:42 +01:00
b(1,1) = a(2,2)*(a(3,3)*a(4,4)-a(3,4)*a(4,3))-a(2,3)*(a(3,2)*a(4,4)-a(3,4)*a(4,2))+a(2,4)*(a(3,2)*a(4,3)-a(3,3)*a(4,2))
b(2,1) = -a(2,1)*(a(3,3)*a(4,4)-a(3,4)*a(4,3))+a(2,3)*(a(3,1)*a(4,4)-a(3,4)*a(4,1))-a(2,4)*(a(3,1)*a(4,3)-a(3,3)*a(4,1))
b(3,1) = a(2,1)*(a(3,2)*a(4,4)-a(3,4)*a(4,2))-a(2,2)*(a(3,1)*a(4,4)-a(3,4)*a(4,1))+a(2,4)*(a(3,1)*a(4,2)-a(3,2)*a(4,1))
b(4,1) = -a(2,1)*(a(3,2)*a(4,3)-a(3,3)*a(4,2))+a(2,2)*(a(3,1)*a(4,3)-a(3,3)*a(4,1))-a(2,3)*(a(3,1)*a(4,2)-a(3,2)*a(4,1))
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
b(1,2) = -a(1,2)*(a(3,3)*a(4,4)-a(3,4)*a(4,3))+a(1,3)*(a(3,2)*a(4,4)-a(3,4)*a(4,2))-a(1,4)*(a(3,2)*a(4,3)-a(3,3)*a(4,2))
b(2,2) = a(1,1)*(a(3,3)*a(4,4)-a(3,4)*a(4,3))-a(1,3)*(a(3,1)*a(4,4)-a(3,4)*a(4,1))+a(1,4)*(a(3,1)*a(4,3)-a(3,3)*a(4,1))
b(3,2) = -a(1,1)*(a(3,2)*a(4,4)-a(3,4)*a(4,2))+a(1,2)*(a(3,1)*a(4,4)-a(3,4)*a(4,1))-a(1,4)*(a(3,1)*a(4,2)-a(3,2)*a(4,1))
b(4,2) = a(1,1)*(a(3,2)*a(4,3)-a(3,3)*a(4,2))-a(1,2)*(a(3,1)*a(4,3)-a(3,3)*a(4,1))+a(1,3)*(a(3,1)*a(4,2)-a(3,2)*a(4,1))
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
b(1,3) = a(1,2)*(a(2,3)*a(4,4)-a(2,4)*a(4,3))-a(1,3)*(a(2,2)*a(4,4)-a(2,4)*a(4,2))+a(1,4)*(a(2,2)*a(4,3)-a(2,3)*a(4,2))
b(2,3) = -a(1,1)*(a(2,3)*a(4,4)-a(2,4)*a(4,3))+a(1,3)*(a(2,1)*a(4,4)-a(2,4)*a(4,1))-a(1,4)*(a(2,1)*a(4,3)-a(2,3)*a(4,1))
b(3,3) = a(1,1)*(a(2,2)*a(4,4)-a(2,4)*a(4,2))-a(1,2)*(a(2,1)*a(4,4)-a(2,4)*a(4,1))+a(1,4)*(a(2,1)*a(4,2)-a(2,2)*a(4,1))
b(4,3) = -a(1,1)*(a(2,2)*a(4,3)-a(2,3)*a(4,2))+a(1,2)*(a(2,1)*a(4,3)-a(2,3)*a(4,1))-a(1,3)*(a(2,1)*a(4,2)-a(2,2)*a(4,1))
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
b(1,4) = -a(1,2)*(a(2,3)*a(3,4)-a(2,4)*a(3,3))+a(1,3)*(a(2,2)*a(3,4)-a(2,4)*a(3,2))-a(1,4)*(a(2,2)*a(3,3)-a(2,3)*a(3,2))
b(2,4) = a(1,1)*(a(2,3)*a(3,4)-a(2,4)*a(3,3))-a(1,3)*(a(2,1)*a(3,4)-a(2,4)*a(3,1))+a(1,4)*(a(2,1)*a(3,3)-a(2,3)*a(3,1))
b(3,4) = -a(1,1)*(a(2,2)*a(3,4)-a(2,4)*a(3,2))+a(1,2)*(a(2,1)*a(3,4)-a(2,4)*a(3,1))-a(1,4)*(a(2,1)*a(3,2)-a(2,2)*a(3,1))
b(4,4) = a(1,1)*(a(2,2)*a(3,3)-a(2,3)*a(3,2))-a(1,2)*(a(2,1)*a(3,3)-a(2,3)*a(3,1))+a(1,3)*(a(2,1)*a(3,2)-a(2,2)*a(3,1))
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
end subroutine cofactor4
2021-10-04 22:45:44 +02:00
2022-01-06 00:51:42 +01:00
subroutine cofactor5(A,LDA,B,LDB,na,det_l)
2021-12-12 20:02:43 +01:00
implicit none
2022-01-06 00:51:42 +01:00
double precision, intent(in) :: A (LDA,na)
double precision, intent(out) :: B (LDA,na)
integer*8, intent(in) :: LDA, LDB
integer*8, intent(in) :: na
2021-12-12 20:02:43 +01:00
double precision, intent(inout) :: det_l
integer :: i,j
2021-10-04 22:45:44 +02:00
det_l = a(1,1)*(a(2,2)*(a(3,3)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*( &
a(4,3)*a(5,5)-a(4,5)*a(5,3))+a(3,5)*(a(4,3)*a(5,4)-a(4,4)*a(5,3)))- &
a(2,3)*(a(3,2)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,2)*a(5,5)- &
a(4,5)*a(5,2))+a(3,5)*(a(4,2)*a(5,4)-a(4,4)*a(5,2)))+a(2,4)*(a(3,2)*( &
a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(3,3)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+ &
a(3,5)*(a(4,2)*a(5,3)-a(4,3)*a(5,2)))-a(2,5)*(a(3,2)*(a(4,3)*a(5,4)- &
a(4,4)*a(5,3))-a(3,3)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))+a(3,4)*(a(4,2)* &
a(5,3)-a(4,3)*a(5,2))))-a(1,2)*(a(2,1)*(a(3,3)*(a(4,4)*a(5,5)-a(4,5)* &
a(5,4))-a(3,4)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))+a(3,5)*(a(4,3)*a(5,4)- &
a(4,4)*a(5,3)))-a(2,3)*(a(3,1)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*( &
a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,4)-a(4,4)*a(5,1)))+ &
a(2,4)*(a(3,1)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(3,3)*(a(4,1)*a(5,5)- &
a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,3)-a(4,3)*a(5,1)))-a(2,5)*(a(3,1)*( &
a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(3,3)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+ &
a(3,4)*(a(4,1)*a(5,3)-a(4,3)*a(5,1))))+a(1,3)*(a(2,1)*(a(3,2)*(a(4,4)* &
a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(3,5)*( &
a(4,2)*a(5,4)-a(4,4)*a(5,2)))-a(2,2)*(a(3,1)*(a(4,4)*a(5,5)-a(4,5)* &
a(5,4))-a(3,4)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,4)- &
a(4,4)*a(5,1)))+a(2,4)*(a(3,1)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))-a(3,2)*( &
a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,2)-a(4,2)*a(5,1)))- &
a(2,5)*(a(3,1)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))-a(3,2)*(a(4,1)*a(5,4)- &
a(4,4)*a(5,1))+a(3,4)*(a(4,1)*a(5,2)-a(4,2)*a(5,1))))-a(1,4)*(a(2,1)*( &
a(3,2)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(3,3)*(a(4,2)*a(5,5)-a(4,5)* &
a(5,2))+a(3,5)*(a(4,2)*a(5,3)-a(4,3)*a(5,2)))-a(2,2)*(a(3,1)*(a(4,3)* &
a(5,5)-a(4,5)*a(5,3))-a(3,3)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*( &
a(4,1)*a(5,3)-a(4,3)*a(5,1)))+a(2,3)*(a(3,1)*(a(4,2)*a(5,5)-a(4,5)* &
a(5,2))-a(3,2)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,2)- &
a(4,2)*a(5,1)))-a(2,5)*(a(3,1)*(a(4,2)*a(5,3)-a(4,3)*a(5,2))-a(3,2)*( &
a(4,1)*a(5,3)-a(4,3)*a(5,1))+a(3,3)*(a(4,1)*a(5,2)-a(4,2)*a(5,1))))+ &
a(1,5)*(a(2,1)*(a(3,2)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(3,3)*(a(4,2)* &
a(5,4)-a(4,4)*a(5,2))+a(3,4)*(a(4,2)*a(5,3)-a(4,3)*a(5,2)))-a(2,2)*( &
a(3,1)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(3,3)*(a(4,1)*a(5,4)-a(4,4)* &
a(5,1))+a(3,4)*(a(4,1)*a(5,3)-a(4,3)*a(5,1)))+a(2,3)*(a(3,1)*(a(4,2)* &
a(5,4)-a(4,4)*a(5,2))-a(3,2)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(3,4)*( &
a(4,1)*a(5,2)-a(4,2)*a(5,1)))-a(2,4)*(a(3,1)*(a(4,2)*a(5,3)-a(4,3)* &
a(5,2))-a(3,2)*(a(4,1)*a(5,3)-a(4,3)*a(5,1))+a(3,3)*(a(4,1)*a(5,2)- &
a(4,2)*a(5,1))))
2022-01-06 00:51:42 +01:00
b(1,1) = &
(a(2,2)*(a(3,3)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))+a(3,5)*(a(4,3)*a(5,4)-a(4,4)*a(5,3)))-a(2,3)* &
(a(3,2)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(3,5)*(a(4,2)*a(5,4)-a(4,4)*a(5,2)))+a(2,4)* &
(a(3,2)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(3,3)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(3,5)*(a(4,2)*a(5,3)-a(4,3)*a(5,2)))-a(2,5)* &
(a(3,2)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(3,3)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))+a(3,4)*(a(4,2)*a(5,3)-a(4,3)*a(5,2))))
b(2,1) = &
(-a(2,1)*(a(3,3)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))+a(3,5)*(a(4,3)*a(5,4)-a(4,4)*a(5,3)))+a(2,3)* &
(a(3,1)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,4)-a(4,4)*a(5,1)))-a(2,4)* &
(a(3,1)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(3,3)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,3)-a(4,3)*a(5,1)))+a(2,5)* &
(a(3,1)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(3,3)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(3,4)*(a(4,1)*a(5,3)-a(4,3)*a(5,1))))
b(3,1) = &
(a(2,1)*(a(3,2)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(3,5)*(a(4,2)*a(5,4)-a(4,4)*a(5,2)))-a(2,2)* &
(a(3,1)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,4)-a(4,4)*a(5,1)))+a(2,4)* &
(a(3,1)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))-a(3,2)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,2)-a(4,2)*a(5,1)))-a(2,5)* &
(a(3,1)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))-a(3,2)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(3,4)*(a(4,1)*a(5,2)-a(4,2)*a(5,1))))
b(4,1) = &
(-a(2,1)*(a(3,2)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(3,3)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(3,5)*(a(4,2)*a(5,3)-a(4,3)*a(5,2)))+a(2,2)* &
(a(3,1)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(3,3)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,3)-a(4,3)*a(5,1)))-a(2,3)* &
(a(3,1)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))-a(3,2)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,2)-a(4,2)*a(5,1)))+a(2,5)* &
(a(3,1)*(a(4,2)*a(5,3)-a(4,3)*a(5,2))-a(3,2)*(a(4,1)*a(5,3)-a(4,3)*a(5,1))+a(3,3)*(a(4,1)*a(5,2)-a(4,2)*a(5,1))))
b(5,1) = &
(a(2,1)*(a(3,2)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(3,3)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))+a(3,4)*(a(4,2)*a(5,3)-a(4,3)*a(5,2)))-a(2,2)* &
(a(3,1)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(3,3)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(3,4)*(a(4,1)*a(5,3)-a(4,3)*a(5,1)))+a(2,3)* &
(a(3,1)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))-a(3,2)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(3,4)*(a(4,1)*a(5,2)-a(4,2)*a(5,1)))-a(2,4)* &
(a(3,1)*(a(4,2)*a(5,3)-a(4,3)*a(5,2))-a(3,2)*(a(4,1)*a(5,3)-a(4,3)*a(5,1))+a(3,3)*(a(4,1)*a(5,2)-a(4,2)*a(5,1))))
b(1,2) = &
(-a(1,2)*(a(3,3)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))+a(3,5)*(a(4,3)*a(5,4)-a(4,4)*a(5,3)))+a(1,3)* &
(a(3,2)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(3,5)*(a(4,2)*a(5,4)-a(4,4)*a(5,2)))-a(1,4)* &
(a(3,2)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(3,3)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(3,5)*(a(4,2)*a(5,3)-a(4,3)*a(5,2)))+a(1,5)* &
(a(3,2)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(3,3)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))+a(3,4)*(a(4,2)*a(5,3)-a(4,3)*a(5,2))))
b(2,2) = &
(a(1,1)*(a(3,3)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))+a(3,5)*(a(4,3)*a(5,4)-a(4,4)*a(5,3)))-a(1,3)* &
(a(3,1)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,4)-a(4,4)*a(5,1)))+a(1,4)* &
(a(3,1)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(3,3)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,3)-a(4,3)*a(5,1)))-a(1,5)* &
(a(3,1)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(3,3)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(3,4)*(a(4,1)*a(5,3)-a(4,3)*a(5,1))))
b(3,2) = &
(-a(1,1)*(a(3,2)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(3,5)*(a(4,2)*a(5,4)-a(4,4)*a(5,2)))+a(1,2)* &
(a(3,1)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(3,4)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,4)-a(4,4)*a(5,1)))-a(1,4)* &
(a(3,1)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))-a(3,2)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,2)-a(4,2)*a(5,1)))+a(1,5)* &
(a(3,1)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))-a(3,2)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(3,4)*(a(4,1)*a(5,2)-a(4,2)*a(5,1))))
b(4,2) = &
(a(1,1)*(a(3,2)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(3,3)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(3,5)*(a(4,2)*a(5,3)-a(4,3)*a(5,2)))-a(1,2)* &
(a(3,1)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(3,3)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,3)-a(4,3)*a(5,1)))+a(1,3)* &
(a(3,1)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))-a(3,2)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(3,5)*(a(4,1)*a(5,2)-a(4,2)*a(5,1)))-a(1,5)* &
(a(3,1)*(a(4,2)*a(5,3)-a(4,3)*a(5,2))-a(3,2)*(a(4,1)*a(5,3)-a(4,3)*a(5,1))+a(3,3)*(a(4,1)*a(5,2)-a(4,2)*a(5,1))))
b(5,2) = &
(-a(1,1)*(a(3,2)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(3,3)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))+a(3,4)*(a(4,2)*a(5,3)-a(4,3)*a(5,2)))+a(1,2)* &
(a(3,1)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(3,3)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(3,4)*(a(4,1)*a(5,3)-a(4,3)*a(5,1)))-a(1,3)* &
(a(3,1)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))-a(3,2)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(3,4)*(a(4,1)*a(5,2)-a(4,2)*a(5,1)))+a(1,4)* &
(a(3,1)*(a(4,2)*a(5,3)-a(4,3)*a(5,2))-a(3,2)*(a(4,1)*a(5,3)-a(4,3)*a(5,1))+a(3,3)*(a(4,1)*a(5,2)-a(4,2)*a(5,1))))
b(1,3) = &
(a(1,2)*(a(2,3)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(2,4)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))+a(2,5)*(a(4,3)*a(5,4)-a(4,4)*a(5,3)))-a(1,3)* &
(a(2,2)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(2,4)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(2,5)*(a(4,2)*a(5,4)-a(4,4)*a(5,2)))+a(1,4)* &
(a(2,2)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(2,3)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(2,5)*(a(4,2)*a(5,3)-a(4,3)*a(5,2)))-a(1,5)* &
(a(2,2)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(2,3)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))+a(2,4)*(a(4,2)*a(5,3)-a(4,3)*a(5,2))))
b(2,3) = &
(-a(1,1)*(a(2,3)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(2,4)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))+a(2,5)*(a(4,3)*a(5,4)-a(4,4)*a(5,3)))+a(1,3)* &
(a(2,1)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(2,4)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(2,5)*(a(4,1)*a(5,4)-a(4,4)*a(5,1)))-a(1,4)* &
(a(2,1)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(2,3)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(2,5)*(a(4,1)*a(5,3)-a(4,3)*a(5,1)))+a(1,5)* &
(a(2,1)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(2,3)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(2,4)*(a(4,1)*a(5,3)-a(4,3)*a(5,1))))
b(3,3) = &
(a(1,1)*(a(2,2)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(2,4)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(2,5)*(a(4,2)*a(5,4)-a(4,4)*a(5,2)))-a(1,2)* &
(a(2,1)*(a(4,4)*a(5,5)-a(4,5)*a(5,4))-a(2,4)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(2,5)*(a(4,1)*a(5,4)-a(4,4)*a(5,1)))+a(1,4)* &
(a(2,1)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))-a(2,2)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(2,5)*(a(4,1)*a(5,2)-a(4,2)*a(5,1)))-a(1,5)* &
(a(2,1)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))-a(2,2)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(2,4)*(a(4,1)*a(5,2)-a(4,2)*a(5,1))))
b(4,3) = &
(-a(1,1)*(a(2,2)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(2,3)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))+a(2,5)*(a(4,2)*a(5,3)-a(4,3)*a(5,2)))+a(1,2)* &
(a(2,1)*(a(4,3)*a(5,5)-a(4,5)*a(5,3))-a(2,3)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(2,5)*(a(4,1)*a(5,3)-a(4,3)*a(5,1)))-a(1,3)* &
(a(2,1)*(a(4,2)*a(5,5)-a(4,5)*a(5,2))-a(2,2)*(a(4,1)*a(5,5)-a(4,5)*a(5,1))+a(2,5)*(a(4,1)*a(5,2)-a(4,2)*a(5,1)))+a(1,5)* &
(a(2,1)*(a(4,2)*a(5,3)-a(4,3)*a(5,2))-a(2,2)*(a(4,1)*a(5,3)-a(4,3)*a(5,1))+a(2,3)*(a(4,1)*a(5,2)-a(4,2)*a(5,1))))
b(5,3) = &
(a(1,1)*(a(2,2)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(2,3)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))+a(2,4)*(a(4,2)*a(5,3)-a(4,3)*a(5,2)))-a(1,2)* &
(a(2,1)*(a(4,3)*a(5,4)-a(4,4)*a(5,3))-a(2,3)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(2,4)*(a(4,1)*a(5,3)-a(4,3)*a(5,1)))+a(1,3)* &
(a(2,1)*(a(4,2)*a(5,4)-a(4,4)*a(5,2))-a(2,2)*(a(4,1)*a(5,4)-a(4,4)*a(5,1))+a(2,4)*(a(4,1)*a(5,2)-a(4,2)*a(5,1)))-a(1,4)* &
(a(2,1)*(a(4,2)*a(5,3)-a(4,3)*a(5,2))-a(2,2)*(a(4,1)*a(5,3)-a(4,3)*a(5,1))+a(2,3)*(a(4,1)*a(5,2)-a(4,2)*a(5,1))))
b(1,4) = &
(-a(1,2)*(a(2,3)*(a(3,4)*a(5,5)-a(3,5)*a(5,4))-a(2,4)*(a(3,3)*a(5,5)-a(3,5)*a(5,3))+a(2,5)*(a(3,3)*a(5,4)-a(3,4)*a(5,3)))+a(1,3)* &
(a(2,2)*(a(3,4)*a(5,5)-a(3,5)*a(5,4))-a(2,4)*(a(3,2)*a(5,5)-a(3,5)*a(5,2))+a(2,5)*(a(3,2)*a(5,4)-a(3,4)*a(5,2)))-a(1,4)* &
(a(2,2)*(a(3,3)*a(5,5)-a(3,5)*a(5,3))-a(2,3)*(a(3,2)*a(5,5)-a(3,5)*a(5,2))+a(2,5)*(a(3,2)*a(5,3)-a(3,3)*a(5,2)))+a(1,5)* &
(a(2,2)*(a(3,3)*a(5,4)-a(3,4)*a(5,3))-a(2,3)*(a(3,2)*a(5,4)-a(3,4)*a(5,2))+a(2,4)*(a(3,2)*a(5,3)-a(3,3)*a(5,2))))
b(2,4) = &
(a(1,1)*(a(2,3)*(a(3,4)*a(5,5)-a(3,5)*a(5,4))-a(2,4)*(a(3,3)*a(5,5)-a(3,5)*a(5,3))+a(2,5)*(a(3,3)*a(5,4)-a(3,4)*a(5,3)))-a(1,3)* &
(a(2,1)*(a(3,4)*a(5,5)-a(3,5)*a(5,4))-a(2,4)*(a(3,1)*a(5,5)-a(3,5)*a(5,1))+a(2,5)*(a(3,1)*a(5,4)-a(3,4)*a(5,1)))+a(1,4)* &
(a(2,1)*(a(3,3)*a(5,5)-a(3,5)*a(5,3))-a(2,3)*(a(3,1)*a(5,5)-a(3,5)*a(5,1))+a(2,5)*(a(3,1)*a(5,3)-a(3,3)*a(5,1)))-a(1,5)* &
(a(2,1)*(a(3,3)*a(5,4)-a(3,4)*a(5,3))-a(2,3)*(a(3,1)*a(5,4)-a(3,4)*a(5,1))+a(2,4)*(a(3,1)*a(5,3)-a(3,3)*a(5,1))))
b(3,4) = &
(-a(1,1)*(a(2,2)*(a(3,4)*a(5,5)-a(3,5)*a(5,4))-a(2,4)*(a(3,2)*a(5,5)-a(3,5)*a(5,2))+a(2,5)*(a(3,2)*a(5,4)-a(3,4)*a(5,2)))+a(1,2)* &
(a(2,1)*(a(3,4)*a(5,5)-a(3,5)*a(5,4))-a(2,4)*(a(3,1)*a(5,5)-a(3,5)*a(5,1))+a(2,5)*(a(3,1)*a(5,4)-a(3,4)*a(5,1)))-a(1,4)* &
(a(2,1)*(a(3,2)*a(5,5)-a(3,5)*a(5,2))-a(2,2)*(a(3,1)*a(5,5)-a(3,5)*a(5,1))+a(2,5)*(a(3,1)*a(5,2)-a(3,2)*a(5,1)))+a(1,5)* &
(a(2,1)*(a(3,2)*a(5,4)-a(3,4)*a(5,2))-a(2,2)*(a(3,1)*a(5,4)-a(3,4)*a(5,1))+a(2,4)*(a(3,1)*a(5,2)-a(3,2)*a(5,1))))
b(4,4) = &
(a(1,1)*(a(2,2)*(a(3,3)*a(5,5)-a(3,5)*a(5,3))-a(2,3)*(a(3,2)*a(5,5)-a(3,5)*a(5,2))+a(2,5)*(a(3,2)*a(5,3)-a(3,3)*a(5,2)))-a(1,2)* &
(a(2,1)*(a(3,3)*a(5,5)-a(3,5)*a(5,3))-a(2,3)*(a(3,1)*a(5,5)-a(3,5)*a(5,1))+a(2,5)*(a(3,1)*a(5,3)-a(3,3)*a(5,1)))+a(1,3)* &
(a(2,1)*(a(3,2)*a(5,5)-a(3,5)*a(5,2))-a(2,2)*(a(3,1)*a(5,5)-a(3,5)*a(5,1))+a(2,5)*(a(3,1)*a(5,2)-a(3,2)*a(5,1)))-a(1,5)* &
(a(2,1)*(a(3,2)*a(5,3)-a(3,3)*a(5,2))-a(2,2)*(a(3,1)*a(5,3)-a(3,3)*a(5,1))+a(2,3)*(a(3,1)*a(5,2)-a(3,2)*a(5,1))))
b(5,4) = &
(-a(1,1)*(a(2,2)*(a(3,3)*a(5,4)-a(3,4)*a(5,3))-a(2,3)*(a(3,2)*a(5,4)-a(3,4)*a(5,2))+a(2,4)*(a(3,2)*a(5,3)-a(3,3)*a(5,2)))+a(1,2)* &
(a(2,1)*(a(3,3)*a(5,4)-a(3,4)*a(5,3))-a(2,3)*(a(3,1)*a(5,4)-a(3,4)*a(5,1))+a(2,4)*(a(3,1)*a(5,3)-a(3,3)*a(5,1)))-a(1,3)* &
(a(2,1)*(a(3,2)*a(5,4)-a(3,4)*a(5,2))-a(2,2)*(a(3,1)*a(5,4)-a(3,4)*a(5,1))+a(2,4)*(a(3,1)*a(5,2)-a(3,2)*a(5,1)))+a(1,4)* &
(a(2,1)*(a(3,2)*a(5,3)-a(3,3)*a(5,2))-a(2,2)*(a(3,1)*a(5,3)-a(3,3)*a(5,1))+a(2,3)*(a(3,1)*a(5,2)-a(3,2)*a(5,1))))
b(1,5) = &
(a(1,2)*(a(2,3)*(a(3,4)*a(4,5)-a(3,5)*a(4,4))-a(2,4)*(a(3,3)*a(4,5)-a(3,5)*a(4,3))+a(2,5)*(a(3,3)*a(4,4)-a(3,4)*a(4,3)))-a(1,3)* &
(a(2,2)*(a(3,4)*a(4,5)-a(3,5)*a(4,4))-a(2,4)*(a(3,2)*a(4,5)-a(3,5)*a(4,2))+a(2,5)*(a(3,2)*a(4,4)-a(3,4)*a(4,2)))+a(1,4)* &
(a(2,2)*(a(3,3)*a(4,5)-a(3,5)*a(4,3))-a(2,3)*(a(3,2)*a(4,5)-a(3,5)*a(4,2))+a(2,5)*(a(3,2)*a(4,3)-a(3,3)*a(4,2)))-a(1,5)* &
(a(2,2)*(a(3,3)*a(4,4)-a(3,4)*a(4,3))-a(2,3)*(a(3,2)*a(4,4)-a(3,4)*a(4,2))+a(2,4)*(a(3,2)*a(4,3)-a(3,3)*a(4,2))))
b(2,5) = &
(-a(1,1)*(a(2,3)*(a(3,4)*a(4,5)-a(3,5)*a(4,4))-a(2,4)*(a(3,3)*a(4,5)-a(3,5)*a(4,3))+a(2,5)*(a(3,3)*a(4,4)-a(3,4)*a(4,3)))+a(1,3)* &
(a(2,1)*(a(3,4)*a(4,5)-a(3,5)*a(4,4))-a(2,4)*(a(3,1)*a(4,5)-a(3,5)*a(4,1))+a(2,5)*(a(3,1)*a(4,4)-a(3,4)*a(4,1)))-a(1,4)* &
(a(2,1)*(a(3,3)*a(4,5)-a(3,5)*a(4,3))-a(2,3)*(a(3,1)*a(4,5)-a(3,5)*a(4,1))+a(2,5)*(a(3,1)*a(4,3)-a(3,3)*a(4,1)))+a(1,5)* &
(a(2,1)*(a(3,3)*a(4,4)-a(3,4)*a(4,3))-a(2,3)*(a(3,1)*a(4,4)-a(3,4)*a(4,1))+a(2,4)*(a(3,1)*a(4,3)-a(3,3)*a(4,1))))
b(3,5) = &
(a(1,1)*(a(2,2)*(a(3,4)*a(4,5)-a(3,5)*a(4,4))-a(2,4)*(a(3,2)*a(4,5)-a(3,5)*a(4,2))+a(2,5)*(a(3,2)*a(4,4)-a(3,4)*a(4,2)))-a(1,2)* &
(a(2,1)*(a(3,4)*a(4,5)-a(3,5)*a(4,4))-a(2,4)*(a(3,1)*a(4,5)-a(3,5)*a(4,1))+a(2,5)*(a(3,1)*a(4,4)-a(3,4)*a(4,1)))+a(1,4)* &
(a(2,1)*(a(3,2)*a(4,5)-a(3,5)*a(4,2))-a(2,2)*(a(3,1)*a(4,5)-a(3,5)*a(4,1))+a(2,5)*(a(3,1)*a(4,2)-a(3,2)*a(4,1)))-a(1,5)* &
(a(2,1)*(a(3,2)*a(4,4)-a(3,4)*a(4,2))-a(2,2)*(a(3,1)*a(4,4)-a(3,4)*a(4,1))+a(2,4)*(a(3,1)*a(4,2)-a(3,2)*a(4,1))))
b(4,5) = &
(-a(1,1)*(a(2,2)*(a(3,3)*a(4,5)-a(3,5)*a(4,3))-a(2,3)*(a(3,2)*a(4,5)-a(3,5)*a(4,2))+a(2,5)*(a(3,2)*a(4,3)-a(3,3)*a(4,2)))+a(1,2)* &
(a(2,1)*(a(3,3)*a(4,5)-a(3,5)*a(4,3))-a(2,3)*(a(3,1)*a(4,5)-a(3,5)*a(4,1))+a(2,5)*(a(3,1)*a(4,3)-a(3,3)*a(4,1)))-a(1,3)* &
(a(2,1)*(a(3,2)*a(4,5)-a(3,5)*a(4,2))-a(2,2)*(a(3,1)*a(4,5)-a(3,5)*a(4,1))+a(2,5)*(a(3,1)*a(4,2)-a(3,2)*a(4,1)))+a(1,5)* &
(a(2,1)*(a(3,2)*a(4,3)-a(3,3)*a(4,2))-a(2,2)*(a(3,1)*a(4,3)-a(3,3)*a(4,1))+a(2,3)*(a(3,1)*a(4,2)-a(3,2)*a(4,1))))
b(5,5) = &
(a(1,1)*(a(2,2)*(a(3,3)*a(4,4)-a(3,4)*a(4,3))-a(2,3)*(a(3,2)*a(4,4)-a(3,4)*a(4,2))+a(2,4)*(a(3,2)*a(4,3)-a(3,3)*a(4,2)))-a(1,2)* &
(a(2,1)*(a(3,3)*a(4,4)-a(3,4)*a(4,3))-a(2,3)*(a(3,1)*a(4,4)-a(3,4)*a(4,1))+a(2,4)*(a(3,1)*a(4,3)-a(3,3)*a(4,1)))+a(1,3)* &
(a(2,1)*(a(3,2)*a(4,4)-a(3,4)*a(4,2))-a(2,2)*(a(3,1)*a(4,4)-a(3,4)*a(4,1))+a(2,4)*(a(3,1)*a(4,2)-a(3,2)*a(4,1)))-a(1,4)* &
(a(2,1)*(a(3,2)*a(4,3)-a(3,3)*a(4,2))-a(2,2)*(a(3,1)*a(4,3)-a(3,3)*a(4,1))+a(2,3)*(a(3,1)*a(4,2)-a(3,2)*a(4,1))))
2021-10-04 22:45:44 +02:00
end
#+end_src
2022-01-06 00:51:42 +01:00
#+CALL: generate_f_interface(table=qmckl_adjugate_args,rettyp="qmckl_exit_code",fname="qmckl_adjugate")
#+RESULTS:
#+begin_src f90 :tangle (eval fh_func) :comments org :exports none
interface
2023-09-22 16:56:48 +02:00
integer(qmckl_exit_code) function qmckl_adjugate &
2022-01-06 00:51:42 +01:00
(context, n, A, lda, B, ldb, det_l) &
bind(C)
use, intrinsic :: iso_c_binding
import
implicit none
2023-09-22 16:56:48 +02:00
integer (qmckl_context), intent(in) , value :: context
2022-01-06 00:51:42 +01:00
integer (c_int64_t) , intent(in) , value :: n
real (c_double ) , intent(in) :: A(lda,*)
integer (c_int64_t) , intent(in) , value :: lda
real (c_double ) , intent(out) :: B(ldb,*)
integer (c_int64_t) , intent(in) , value :: ldb
real (c_double ) , intent(inout) :: det_l
end function qmckl_adjugate
end interface
#+end_src
2022-01-08 15:36:07 +01:00
2022-01-06 00:51:42 +01:00
2021-12-12 20:02:43 +01:00
#+begin_src f90 :tangle (eval f)
2022-01-06 02:28:13 +01:00
subroutine adjugate_general(context, na, A, LDA, B, LDB, det_l)
2021-12-12 20:02:43 +01:00
use qmckl
implicit none
2022-01-06 02:28:13 +01:00
integer(qmckl_context), intent(in) :: context
2022-01-06 00:51:42 +01:00
double precision, intent(in) :: A (LDA,na)
integer*8, intent(in) :: LDA
double precision, intent(out) :: B (LDB,na)
integer*8, intent(in) :: LDB
integer*8, intent(in) :: na
double precision, intent(inout) :: det_l
2021-12-12 20:02:43 +01:00
double precision :: work(LDA*max(na,64))
integer :: inf
integer :: ipiv(LDA)
integer :: lwork
2022-01-08 15:36:07 +01:00
integer(8) :: i, j
2021-12-12 20:02:43 +01:00
#+end_src
2022-01-06 00:51:42 +01:00
We first copy the array ~A~ into array ~B~.
#+begin_src f90 :tangle (eval f)
B(1:na,1:na) = A(1:na,1:na)
#+end_src
Then, we compute the LU factorization $LU=A$
2021-12-12 20:02:43 +01:00
using the ~dgetrf~ routine.
#+begin_src f90 :tangle (eval f)
2022-01-06 00:51:42 +01:00
call dgetrf(na, na, B, LDB, ipiv, inf )
2021-12-12 20:02:43 +01:00
#+end_src
By convention, the determinant of $L$ is equal to one, so the
determinant of $A$ is equal to the determinant of $U$, which is
simply computed as the product of its diagonal elements.
#+begin_src f90 :tangle (eval f)
det_l = 1.d0
2022-01-08 15:36:07 +01:00
j=0_8
2021-12-12 20:02:43 +01:00
do i=1,na
j = j+min(abs(ipiv(i)-i),1)
2022-01-06 00:51:42 +01:00
det_l = det_l*B(i,i)
2021-12-12 20:02:43 +01:00
enddo
#+end_src
As ~dgetrf~ returns $PLU=A$ where $P$ is a permutation matrix, the
sign of the determinant is computed as $-1^m$ where $m$ is the
number of permutations.
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
#+begin_src f90 :tangle (eval f)
2022-01-08 15:36:07 +01:00
if (iand(j,1_8) /= 0_8) then
2021-12-12 20:02:43 +01:00
det_l = -det_l
endif
#+end_src
Then, the inverse of $A$ is computed using ~dgetri~:
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
#+begin_src f90 :tangle (eval f)
lwork = SIZE(work)
2022-01-06 00:51:42 +01:00
call dgetri(na, B, LDB, ipiv, work, lwork, inf )
2021-12-12 20:02:43 +01:00
#+end_src
and the adjugate matrix is computed as the product of the
determinant with the inverse:
#+begin_src f90 :tangle (eval f)
2022-01-06 00:51:42 +01:00
B(:,:) = B(:,:)*det_l
2021-12-12 20:02:43 +01:00
end subroutine adjugate_general
#+end_src
2021-10-04 22:45:44 +02:00
*** Test :noexport:
2021-12-12 20:02:43 +01:00
2021-10-07 14:01:40 +02:00
#+begin_src f90 :tangle (eval f_test)
2021-12-12 20:02:43 +01:00
integer(qmckl_exit_code) function test_qmckl_adjugate(context) bind(C)
2023-09-22 16:56:48 +02:00
use qmckl_constants
2021-10-07 14:01:40 +02:00
implicit none
integer(qmckl_context), intent(in), value :: context
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
double precision, allocatable :: A(:,:), B(:,:)
integer*8 :: m, n, k, LDA, LDB
2021-10-07 14:01:40 +02:00
integer*8 :: i,j,l
double precision :: x, det_l, det_l_ref
2022-01-08 15:36:07 +01:00
LDA = 6_8
LDB = 6_8
2021-12-12 20:02:43 +01:00
allocate( A(LDA,6), B(LDB,6))
2021-10-07 14:01:40 +02:00
2021-12-12 20:02:43 +01:00
A = 0.1d0
2021-10-07 14:01:40 +02:00
A(1,1) = 1.0d0;
A(2,2) = 2.0d0;
A(3,3) = 3.0d0;
A(4,4) = 4.0d0;
2021-12-12 20:02:43 +01:00
A(5,5) = 5.0d0;
A(6,6) = 6.0d0;
2021-10-07 14:01:40 +02:00
2021-12-12 20:02:43 +01:00
test_qmckl_adjugate = QMCKL_SUCCESS
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
#+end_src
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
#+begin_src python :results output :output drawer
import numpy as np
import numpy.linalg as la
N=6
A = np.zeros( (N,N) )
A += 0.1
for i in range(N):
A[i][i] = i+1
def adj(A):
return la.det(A) * la.inv(A)
print ("#+begin_src f90 :tangle (eval f_test)")
for i in range(N):
print ("! N = ", i+1)
2022-01-06 00:51:42 +01:00
print (f" test_qmckl_adjugate = qmckl_adjugate(context, {i+1}_8, A, LDA, B, LDB, det_l)")
2021-12-12 20:02:43 +01:00
print (f" if (test_qmckl_adjugate /= QMCKL_SUCCESS) return")
print (f" if (dabs((det_l - ({la.det(A[0:i+1,0:i+1])}d0))/det_l) > 1.d-13) then")
print (f" print *, 'N = {i+1}: det = ', det_l, {la.det(A[0:i+1,0:i+1])}d0")
print (f" test_qmckl_adjugate = {i+1}")
print (f" return")
print (f" end if")
print (f"")
print (f" x = 0.d0")
for j in range(i+1):
C = adj(A[0:i+1,0:i+1])
for k in range(i+1):
print (f" x = x + (B({j+1},{k+1}) - ({C[j,k]}) )**2")
print (f" if (dabs(x / det_l) > 1.d-12) then")
print (f" print *, 'N = {i+1}: x = ', x")
print (f" test_qmckl_adjugate = {i+1}")
print (f" return")
print (f" end if")
print (f"")
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
print ("#+end_src")
# print(adj(A[0:i+1,0:i+1]))
#+end_src
2021-10-07 14:01:40 +02:00
2021-12-12 20:02:43 +01:00
#+RESULTS:
2022-01-06 00:51:42 +01:00
#+begin_example
,#+begin_src f90 :tangle (eval f_test)
2021-12-12 20:02:43 +01:00
! N = 1
2022-01-06 00:51:42 +01:00
test_qmckl_adjugate = qmckl_adjugate(context, 1_8, A, LDA, B, LDB, det_l)
2021-12-12 20:02:43 +01:00
if (test_qmckl_adjugate /= QMCKL_SUCCESS) return
if (dabs((det_l - (1.0d0))/det_l) > 1.d-13) then
print *, 'N = 1: det = ', det_l, 1.0d0
test_qmckl_adjugate = 1
return
end if
x = 0.d0
x = x + (B(1,1) - (1.0) )**2
if (dabs(x / det_l) > 1.d-12) then
print *, 'N = 1: x = ', x
test_qmckl_adjugate = 1
return
end if
! N = 2
2022-01-06 00:51:42 +01:00
test_qmckl_adjugate = qmckl_adjugate(context, 2_8, A, LDA, B, LDB, det_l)
2021-12-12 20:02:43 +01:00
if (test_qmckl_adjugate /= QMCKL_SUCCESS) return
if (dabs((det_l - (1.99d0))/det_l) > 1.d-13) then
print *, 'N = 2: det = ', det_l, 1.99d0
test_qmckl_adjugate = 2
return
end if
x = 0.d0
x = x + (B(1,1) - (1.9999999999999998) )**2
x = x + (B(1,2) - (-0.09999999999999999) )**2
x = x + (B(2,1) - (-0.09999999999999999) )**2
x = x + (B(2,2) - (0.9999999999999999) )**2
if (dabs(x / det_l) > 1.d-12) then
print *, 'N = 2: x = ', x
test_qmckl_adjugate = 2
return
end if
! N = 3
2022-01-06 00:51:42 +01:00
test_qmckl_adjugate = qmckl_adjugate(context, 3_8, A, LDA, B, LDB, det_l)
2021-12-12 20:02:43 +01:00
if (test_qmckl_adjugate /= QMCKL_SUCCESS) return
if (dabs((det_l - (5.942000000000001d0))/det_l) > 1.d-13) then
print *, 'N = 3: det = ', det_l, 5.942000000000001d0
test_qmckl_adjugate = 3
return
end if
x = 0.d0
x = x + (B(1,1) - (5.990000000000001) )**2
x = x + (B(1,2) - (-0.29000000000000004) )**2
x = x + (B(1,3) - (-0.19000000000000003) )**2
x = x + (B(2,1) - (-0.29000000000000004) )**2
x = x + (B(2,2) - (2.9900000000000007) )**2
x = x + (B(2,3) - (-0.09000000000000001) )**2
x = x + (B(3,1) - (-0.19000000000000003) )**2
x = x + (B(3,2) - (-0.09) )**2
x = x + (B(3,3) - (1.9900000000000002) )**2
if (dabs(x / det_l) > 1.d-12) then
print *, 'N = 3: x = ', x
test_qmckl_adjugate = 3
return
end if
! N = 4
2022-01-06 00:51:42 +01:00
test_qmckl_adjugate = qmckl_adjugate(context, 4_8, A, LDA, B, LDB, det_l)
2021-12-12 20:02:43 +01:00
if (test_qmckl_adjugate /= QMCKL_SUCCESS) return
if (dabs((det_l - (23.669700000000006d0))/det_l) > 1.d-13) then
print *, 'N = 4: det = ', det_l, 23.669700000000006d0
test_qmckl_adjugate = 4
return
end if
x = 0.d0
x = x + (B(1,1) - (23.91200000000001) )**2
x = x + (B(1,2) - (-1.1310000000000004) )**2
x = x + (B(1,3) - (-0.7410000000000001) )**2
x = x + (B(1,4) - (-0.5510000000000002) )**2
x = x + (B(2,1) - (-1.1310000000000002) )**2
x = x + (B(2,2) - (11.922000000000002) )**2
x = x + (B(2,3) - (-0.351) )**2
x = x + (B(2,4) - (-0.261) )**2
x = x + (B(3,1) - (-0.7410000000000002) )**2
x = x + (B(3,2) - (-0.351) )**2
x = x + (B(3,3) - (7.932000000000001) )**2
x = x + (B(3,4) - (-0.17100000000000004) )**2
x = x + (B(4,1) - (-0.5510000000000002) )**2
x = x + (B(4,2) - (-0.261) )**2
x = x + (B(4,3) - (-0.17100000000000004) )**2
x = x + (B(4,4) - (5.942000000000001) )**2
if (dabs(x / det_l) > 1.d-12) then
print *, 'N = 4: x = ', x
test_qmckl_adjugate = 4
return
end if
! N = 5
2022-01-06 00:51:42 +01:00
test_qmckl_adjugate = qmckl_adjugate(context, 5_8, A, LDA, B, LDB, det_l)
2021-12-12 20:02:43 +01:00
if (test_qmckl_adjugate /= QMCKL_SUCCESS) return
if (dabs((det_l - (117.91554000000008d0))/det_l) > 1.d-13) then
print *, 'N = 5: det = ', det_l, 117.91554000000008d0
test_qmckl_adjugate = 5
return
end if
x = 0.d0
x = x + (B(1,1) - (119.31770000000006) )**2
x = x + (B(1,2) - (-5.541900000000004) )**2
x = x + (B(1,3) - (-3.6309000000000022) )**2
x = x + (B(1,4) - (-2.6999000000000017) )**2
x = x + (B(1,5) - (-2.1489000000000016) )**2
x = x + (B(2,1) - (-5.541900000000004) )**2
x = x + (B(2,2) - (59.435700000000026) )**2
x = x + (B(2,3) - (-1.7199000000000007) )**2
x = x + (B(2,4) - (-1.2789000000000006) )**2
x = x + (B(2,5) - (-1.0179000000000005) )**2
x = x + (B(3,1) - (-3.6309000000000027) )**2
x = x + (B(3,2) - (-1.7199000000000007) )**2
x = x + (B(3,3) - (39.53370000000002) )**2
x = x + (B(3,4) - (-0.8379000000000005) )**2
x = x + (B(3,5) - (-0.6669000000000004) )**2
x = x + (B(4,1) - (-2.699900000000002) )**2
x = x + (B(4,2) - (-1.2789000000000006) )**2
x = x + (B(4,3) - (-0.8379000000000004) )**2
x = x + (B(4,4) - (29.611700000000017) )**2
x = x + (B(4,5) - (-0.4959000000000003) )**2
x = x + (B(5,1) - (-2.1489000000000016) )**2
x = x + (B(5,2) - (-1.0179000000000005) )**2
x = x + (B(5,3) - (-0.6669000000000004) )**2
x = x + (B(5,4) - (-0.4959000000000003) )**2
x = x + (B(5,5) - (23.669700000000013) )**2
if (dabs(x / det_l) > 1.d-12) then
print *, 'N = 5: x = ', x
test_qmckl_adjugate = 5
return
end if
! N = 6
2022-01-06 00:51:42 +01:00
test_qmckl_adjugate = qmckl_adjugate(context, 6_8, A, LDA, B, LDB, det_l)
2021-12-12 20:02:43 +01:00
if (test_qmckl_adjugate /= QMCKL_SUCCESS) return
if (dabs((det_l - (705.1783350000001d0))/det_l) > 1.d-13) then
print *, 'N = 6: det = ', det_l, 705.1783350000001d0
test_qmckl_adjugate = 6
return
end if
x = 0.d0
x = x + (B(1,1) - (714.5040400000001) )**2
x = x + (B(1,2) - (-32.697210000000005) )**2
x = x + (B(1,3) - (-21.422310000000003) )**2
x = x + (B(1,4) - (-15.929410000000006) )**2
x = x + (B(1,5) - (-12.678510000000003) )**2
x = x + (B(1,6) - (-10.529610000000003) )**2
x = x + (B(2,1) - (-32.69721) )**2
x = x + (B(2,2) - (355.65834) )**2
x = x + (B(2,3) - (-10.147409999999997) )**2
x = x + (B(2,4) - (-7.54551) )**2
x = x + (B(2,5) - (-6.005610000000001) )**2
x = x + (B(2,6) - (-4.987709999999999) )**2
x = x + (B(3,1) - (-21.422310000000003) )**2
x = x + (B(3,2) - (-10.147409999999999) )**2
x = x + (B(3,3) - (236.51663999999997) )**2
x = x + (B(3,4) - (-4.943610000000001) )**2
x = x + (B(3,5) - (-3.93471) )**2
x = x + (B(3,6) - (-3.267810000000001) )**2
x = x + (B(4,1) - (-15.929410000000003) )**2
x = x + (B(4,2) - (-7.54551) )**2
x = x + (B(4,3) - (-4.9436100000000005) )**2
x = x + (B(4,4) - (177.13894000000002) )**2
x = x + (B(4,5) - (-2.92581) )**2
x = x + (B(4,6) - (-2.42991) )**2
x = x + (B(5,1) - (-12.678510000000001) )**2
x = x + (B(5,2) - (-6.005609999999999) )**2
x = x + (B(5,3) - (-3.9347100000000004) )**2
x = x + (B(5,4) - (-2.92581) )**2
x = x + (B(5,5) - (141.58524) )**2
x = x + (B(5,6) - (-1.93401) )**2
x = x + (B(6,1) - (-10.529610000000003) )**2
x = x + (B(6,2) - (-4.98771) )**2
x = x + (B(6,3) - (-3.2678100000000003) )**2
x = x + (B(6,4) - (-2.42991) )**2
x = x + (B(6,5) - (-1.9340100000000005) )**2
x = x + (B(6,6) - (117.91554000000001) )**2
if (dabs(x / det_l) > 1.d-12) then
print *, 'N = 6: x = ', x
test_qmckl_adjugate = 6
return
end if
2021-10-07 14:01:40 +02:00
2022-01-06 00:51:42 +01:00
,#+end_src
#+end_example
2021-12-12 20:02:43 +01:00
#+begin_src f90 :tangle (eval f_test)
2022-01-08 15:36:07 +01:00
2021-12-12 20:02:43 +01:00
deallocate(A,B)
2021-10-07 14:01:40 +02:00
2021-12-12 20:02:43 +01:00
end function test_qmckl_adjugate
2021-10-07 14:01:40 +02:00
#+end_src
2022-01-08 15:36:07 +01:00
2021-10-07 14:01:40 +02:00
#+begin_src c :comments link :tangle (eval c_test)
2021-12-12 20:02:43 +01:00
qmckl_exit_code test_qmckl_adjugate(qmckl_context context);
assert(QMCKL_SUCCESS == test_qmckl_adjugate(context));
2023-03-16 16:52:01 +01:00
printf("qmckl_adjugate ok\n");
2021-10-07 14:01:40 +02:00
#+end_src
2022-01-08 15:36:07 +01:00
2022-08-22 17:31:15 +02:00
** ~qmckl_adjugate_safe~
"Size-safe" proxy function with the same functionality as ~qmckl_adjugate~
but with 2 additional arguments. These arguments ~size_max_M~ (where ~M~ is a matix)
are required primarily for the Python API, where compatibility with
NumPy arrays implies that sizes of the input and output arrays are provided.
#+NAME: qmckl_adjugate_safe_args
| Variable | Type | In/Out | Description |
|--------------+-----------------+--------+------------------------------------------------|
| ~context~ | ~qmckl_context~ | in | Global state |
| ~n~ | ~int64_t~ | in | Number of rows and columns of the input matrix |
| ~A~ | ~double[][lda]~ | in | Array containing the $n \times n$ matrix $A$ |
| ~size_max_A~ | ~int64_t~ | in | Size of the matrix $A$ |
| ~lda~ | ~int64_t~ | in | Leading dimension of array ~A~ |
| ~B~ | ~double[][ldb]~ | out | Adjugate of $A$ |
| ~size_max_B~ | ~int64_t~ | in | Size of the matrix $B$ |
| ~ldb~ | ~int64_t~ | in | Leading dimension of array ~B~ |
| ~det_l~ | ~double~ | inout | determinant of $A$ |
Requirements:
- ~context~ is not ~QMCKL_NULL_CONTEXT~
- ~n > 0~
- ~lda >= m~
- ~A~ is allocated with at least $m \times m \times 8$ bytes
- ~ldb >= m~
- ~B~ is allocated with at least $m \times m \times 8$ bytes
- ~size_max_A >= m * m~
- ~size_max_B >= m * m~
#+CALL: generate_c_header(table=qmckl_adjugate_safe_args,rettyp="qmckl_exit_code",fname="qmckl_adjugate_safe")
#+RESULTS:
#+BEGIN_src c :tangle (eval h_func) :comments org
qmckl_exit_code qmckl_adjugate_safe (
const qmckl_context context,
const int64_t n,
const double* A,
const int64_t size_max_A,
const int64_t lda,
double* const B,
const int64_t size_max_B,
const int64_t ldb,
double* det_l );
#+END_src
For small matrices (\le 5\times 5), we use specialized routines
for performance motivations. For larger sizes, we rely on the
LAPACK library.
#+begin_src f90 :tangle (eval f) :exports none
2023-09-22 16:56:48 +02:00
function qmckl_adjugate_safe(context, &
2022-08-22 17:31:15 +02:00
na, A, size_A, LDA, B, size_B, LDB, det_l) &
2023-09-22 16:56:48 +02:00
result(info) bind(C)
use, intrinsic :: iso_c_binding
use qmckl_constants
use qmckl, only: qmckl_adjugate
2022-08-22 17:31:15 +02:00
implicit none
2023-09-22 16:56:48 +02:00
integer (qmckl_context), intent(in) , value :: context
integer (c_int64_t) , intent(in) , value :: na
real (c_double ) , intent(in) :: A(lda,*)
integer (c_int64_t) , intent(in) , value :: size_A
integer (c_int64_t) , intent(in) , value :: lda
real (c_double ) , intent(out) :: B(ldb,*)
integer (c_int64_t) , intent(in) , value :: size_B
integer (c_int64_t) , intent(in) , value :: ldb
real (c_double ) , intent(inout) :: det_l
integer(qmckl_exit_code) :: info
2022-08-22 17:31:15 +02:00
info = QMCKL_SUCCESS
if (size_A < na) then
info = QMCKL_INVALID_ARG_4
return
endif
if (size_B <= 0_8) then
info = QMCKL_INVALID_ARG_7
return
endif
2023-09-22 16:56:48 +02:00
info = qmckl_adjugate(context, na, A, LDA, B, LDB, det_l)
2022-08-22 17:31:15 +02:00
if (info == QMCKL_INVALID_ARG_4) then
info = QMCKL_INVALID_ARG_5
return
endif
if (info == QMCKL_INVALID_ARG_6) then
info = QMCKL_INVALID_ARG_8
return
endif
2023-09-22 16:56:48 +02:00
end function qmckl_adjugate_safe
2022-08-22 17:31:15 +02:00
#+end_src
*** C interface
#+CALL: generate_f_interface(table=qmckl_adjugate_safe_args,rettyp="qmckl_exit_code",fname="qmckl_adjugate_safe")
#+RESULTS:
#+begin_src f90 :tangle (eval fh_func) :comments org :exports none
interface
2023-09-22 16:56:48 +02:00
integer(qmckl_exit_code) function qmckl_adjugate_safe &
(context, n, A, size_max_A, lda, B, size_max_B, ldb, det_l) &
2022-08-22 17:31:15 +02:00
bind(C)
use, intrinsic :: iso_c_binding
import
implicit none
2023-09-22 16:56:48 +02:00
integer (qmckl_context), intent(in) , value :: context
2022-08-22 17:31:15 +02:00
integer (c_int64_t) , intent(in) , value :: n
real (c_double ) , intent(in) :: A(lda,*)
2023-09-22 16:56:48 +02:00
integer (c_int64_t) , intent(in) , value :: size_max_A
2022-08-22 17:31:15 +02:00
integer (c_int64_t) , intent(in) , value :: lda
real (c_double ) , intent(out) :: B(ldb,*)
2023-09-22 16:56:48 +02:00
integer (c_int64_t) , intent(in) , value :: size_max_B
2022-08-22 17:31:15 +02:00
integer (c_int64_t) , intent(in) , value :: ldb
real (c_double ) , intent(inout) :: det_l
end function qmckl_adjugate_safe
end interface
#+end_src
2022-01-23 16:18:46 +01:00
** ~qmckl_transpose~
Transposes a matrix: $A^\dagger_{ji} = A_{ij}$.
2022-02-24 19:06:19 +01:00
| Variable | Type | In/Out | Description |
|-----------+-----------------+--------+-------------------|
| ~context~ | ~qmckl_context~ | in | Global state |
| ~A~ | ~qmckl_matrix~ | in | Input matrix |
| ~At~ | ~qmckl_matrix~ | out | Transposed matrix |
2022-07-07 18:25:49 +02:00
2022-01-23 16:18:46 +01:00
#+begin_src c :tangle (eval h_private_func) :comments org
qmckl_exit_code
qmckl_transpose (qmckl_context context,
const qmckl_matrix A,
2022-07-07 18:25:49 +02:00
qmckl_matrix At );
2022-01-23 16:18:46 +01:00
#+end_src
2022-02-24 19:06:19 +01:00
#+begin_src c :tangle (eval c) :comments org :exports none
2022-01-23 16:18:46 +01:00
qmckl_exit_code
qmckl_transpose (qmckl_context context,
const qmckl_matrix A,
qmckl_matrix At )
{
if (qmckl_context_check(context) == QMCKL_NULL_CONTEXT) {
return QMCKL_INVALID_CONTEXT;
}
if (A.size[0] < 1) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_2,
"qmckl_transpose",
"Invalid size for A");
}
if (At.data == NULL) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_3,
"qmckl_transpose",
"Output matrix not allocated");
}
if (At.size[0] != A.size[1] || At.size[1] != A.size[0]) {
return qmckl_failwith( context,
QMCKL_INVALID_ARG_3,
"qmckl_transpose",
"Invalid size for At");
}
2022-07-07 18:25:49 +02:00
for (int64_t j=0 ; j<At.size[1] ; ++j)
for (int64_t i=0 ; i<At.size[0] ; ++i)
2022-01-23 16:18:46 +01:00
qmckl_mat(At, i, j) = qmckl_mat(A, j, i);
2022-07-07 18:25:49 +02:00
2022-01-23 16:18:46 +01:00
return QMCKL_SUCCESS;
}
#+end_src
2022-02-24 19:06:19 +01:00
*** Test :noexport:
2022-01-23 16:18:46 +01:00
#+begin_src c :comments link :tangle (eval c_test)
{
qmckl_matrix A;
qmckl_matrix At;
A = qmckl_matrix_alloc(context, 2, 3);
At = qmckl_matrix_alloc(context, 3, 2);
for (int j=0 ; j<3 ; ++j)
for (int i=0 ; i<2 ; ++i)
qmckl_mat(A, i, j) = (double) 10*i+j;
qmckl_exit_code rc = qmckl_transpose(context, A, At);
assert(rc == QMCKL_SUCCESS);
assert(A.size[0] == At.size[1]);
assert(A.size[1] == At.size[0]);
for (int j=0 ; j<3 ; ++j)
for (int i=0 ; i<2 ; ++i)
assert (qmckl_mat(A, i, j) == qmckl_mat(At, j, i));
2023-03-16 16:52:01 +01:00
printf("qmckl_transpose ok\n");
2022-02-16 15:14:41 +01:00
qmckl_matrix_free(context, &A);
qmckl_matrix_free(context, &At);
2022-01-23 16:18:46 +01:00
}
#+end_src
2023-06-14 09:11:58 +02:00
* Utilities
Trick to make MKL efficient on AMD
2023-06-14 11:44:00 +02:00
#+begin_src c :tangle (eval c)
2023-06-14 09:11:58 +02:00
int mkl_serv_intel_cpu_true() {
return 1;
}
2023-06-14 11:45:39 +02:00
2023-06-14 09:11:58 +02:00
#+end_src
2021-09-07 16:36:26 +02:00
* End of files :noexport:
2023-06-14 09:11:58 +02:00
#+begin_src c :tangle (eval h_private_type)
#endif
#+end_src
#+begin_src c :tangle (eval h_private_func)
#endif
#+end_src
2021-09-07 16:36:26 +02:00
#+begin_src c :comments link :tangle (eval c_test)
assert (qmckl_context_destroy(context) == QMCKL_SUCCESS);
return 0;
}
#+end_src
# -*- mode: org -*-
# vim: syntax=c