1
0
mirror of https://github.com/TREX-CoE/qmckl.git synced 2024-11-19 20:42:50 +01:00
qmckl/src/qmckl_distance.org

379 lines
11 KiB
Org Mode
Raw Normal View History

2020-10-22 00:50:07 +02:00
# -*- mode: org -*-
# vim: syntax=c
#+TITLE: Computation of distances
2020-10-22 01:24:14 +02:00
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="http://www.pirilampo.org/styles/readtheorg/css/htmlize.css"/>
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="http://www.pirilampo.org/styles/readtheorg/css/readtheorg.css"/>
#+HTML_HEAD: <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
#+HTML_HEAD: <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
#+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/lib/js/jquery.stickytableheaders.js"></script>
#+HTML_HEAD: <script type="text/javascript" src="http://www.pirilampo.org/styles/readtheorg/js/readtheorg.js"></script>
2020-10-22 00:50:07 +02:00
Function for the computation of distances between particles.
2020-10-30 16:22:29 +01:00
4 files are produced:
2020-10-22 01:24:14 +02:00
- a header file : =qmckl_distance.h=
- a source file : =qmckl_distance.f90=
2020-10-26 19:30:50 +01:00
- a C test file : =test_qmckl_distance.c=
- a Fortran test file : =test_qmckl_distance_f.f90=
2020-10-22 00:50:07 +02:00
2020-10-25 15:16:02 +01:00
*** Header :noexport:
2020-10-22 00:50:07 +02:00
#+BEGIN_SRC C :comments link :tangle qmckl_distance.h
#ifndef QMCKL_DISTANCE_H
#define QMCKL_DISTANCE_H
#include "qmckl_context.h"
#+END_SRC
2020-10-25 15:16:02 +01:00
*** Test :noexport:
2020-10-22 00:50:07 +02:00
#+BEGIN_SRC C :comments link :tangle test_qmckl_distance.c
#include <math.h>
#include "qmckl.h"
#include "munit.h"
MunitResult test_qmckl_distance() {
qmckl_context context;
context = qmckl_context_create();
#+END_SRC
* Squared distance
** =qmckl_distance_sq=
2020-10-22 01:24:14 +02:00
2020-10-22 00:50:07 +02:00
Computes the matrix of the squared distances between all pairs of
points in two sets, one point within each set:
\[
2020-10-28 20:15:36 +01:00
C_{ij} = \sum_{k=1}^3 (A_{k,i}-B_{k,j})^2
2020-10-22 00:50:07 +02:00
\]
2020-10-22 01:24:14 +02:00
2020-10-22 00:50:07 +02:00
*** Arguments
2020-10-25 15:02:37 +01:00
| =context= | input | Global state |
2020-10-28 20:15:36 +01:00
| =transa= | input | Array =A= is =N=: Normal, =T=: Transposed |
| =transb= | input | Array =B= is =N=: Normal, =T=: Transposed |
2020-10-25 15:02:37 +01:00
| =m= | input | Number of points in the first set |
| =n= | input | Number of points in the second set |
| =A(lda,3)= | input | Array containing the $m \times 3$ matrix $A$ |
| =lda= | input | Leading dimension of array =A= |
| =B(ldb,3)= | input | Array containing the $n \times 3$ matrix $B$ |
| =ldb= | input | Leading dimension of array =B= |
| =C(ldc,n)= | output | Array containing the $m \times n$ matrix $C$ |
| =ldc= | input | Leading dimension of array =C= |
2020-10-22 00:50:07 +02:00
*** Requirements
- =context= is not 0
- =m= > 0
- =n= > 0
2020-10-28 20:15:36 +01:00
- =lda= >= 3 if =transa= is =N=
- =lda= >= m if =transa= is =T=
- =ldb= >= 3 if =transb= is =N=
- =ldb= >= n if =transb= is =T=
- =ldc= >= m if =transa= is =
2020-10-22 00:50:07 +02:00
- =A= is allocated with at least $3 \times m \times 8$ bytes
- =B= is allocated with at least $3 \times n \times 8$ bytes
- =C= is allocated with at least $m \times n \times 8$ bytes
2020-10-28 20:15:36 +01:00
*** Performance
This function might be more efficient when =A= and =B= are
transposed.
2020-10-22 00:50:07 +02:00
*** Header
#+BEGIN_SRC C :comments link :tangle qmckl_distance.h
2020-10-31 19:07:57 +01:00
qmckl_exit_code qmckl_distance_sq(const qmckl_context context,
const char transa, const char transb,
const int64_t m, const int64_t n,
const double *A, const int64_t lda,
const double *B, const int64_t ldb,
const double *C, const int64_t ldc);
2020-10-22 00:50:07 +02:00
#+END_SRC
*** Source
#+BEGIN_SRC f90 :comments link :tangle qmckl_distance.f90
2020-10-28 20:15:36 +01:00
integer function qmckl_distance_sq_f(context, transa, transb, m, n, A, LDA, B, LDB, C, LDC) result(info)
2020-10-22 00:50:07 +02:00
implicit none
2020-10-25 15:02:37 +01:00
integer*8 , intent(in) :: context
2020-10-28 20:15:36 +01:00
character , intent(in) :: transa, transb
2020-10-25 15:02:37 +01:00
integer*8 , intent(in) :: m, n
integer*8 , intent(in) :: lda
2020-10-28 20:15:36 +01:00
real*8 , intent(in) :: A(lda,*)
2020-10-25 15:02:37 +01:00
integer*8 , intent(in) :: ldb
2020-10-28 20:15:36 +01:00
real*8 , intent(in) :: B(ldb,*)
2020-10-25 15:02:37 +01:00
integer*8 , intent(in) :: ldc
2020-10-28 20:15:36 +01:00
real*8 , intent(out) :: C(ldc,*)
2020-10-25 15:02:37 +01:00
integer*8 :: i,j
real*8 :: x, y, z
2020-10-28 20:15:36 +01:00
integer :: transab
2020-10-22 01:24:14 +02:00
2020-10-22 00:50:07 +02:00
info = 0
2020-10-22 01:24:14 +02:00
2020-10-22 00:50:07 +02:00
if (context == 0_8) then
info = -1
return
endif
2020-10-22 01:24:14 +02:00
2020-10-22 00:50:07 +02:00
if (m <= 0_8) then
info = -2
return
endif
2020-10-22 01:24:14 +02:00
2020-10-22 00:50:07 +02:00
if (n <= 0_8) then
info = -3
return
endif
2020-10-22 01:24:14 +02:00
2020-10-28 20:15:36 +01:00
if (transa == 'N' .or. transa == 'n') then
transab = 0
else if (transa == 'T' .or. transa == 't') then
transab = 1
else
transab = -100
endif
if (transb == 'N' .or. transb == 'n') then
continue
else if (transa == 'T' .or. transa == 't') then
transab = transab + 2
else
transab = -100
endif
if (transab < 0) then
2020-10-22 00:50:07 +02:00
info = -4
2020-10-28 20:15:36 +01:00
return
2020-10-22 00:50:07 +02:00
endif
2020-10-22 01:24:14 +02:00
2020-10-28 20:15:36 +01:00
if (iand(transab,1) == 0 .and. LDA < 3) then
2020-10-22 00:50:07 +02:00
info = -5
return
endif
2020-10-22 01:24:14 +02:00
2020-10-28 20:15:36 +01:00
if (iand(transab,1) == 1 .and. LDA < m) then
2020-10-22 00:50:07 +02:00
info = -6
return
endif
2020-10-22 01:24:14 +02:00
2020-10-28 20:15:36 +01:00
if (iand(transab,2) == 0 .and. LDA < 3) then
info = -6
return
endif
if (iand(transab,2) == 2 .and. LDA < m) then
info = -7
return
endif
select case (transab)
case(0)
do j=1,n
do i=1,m
x = A(1,i) - B(1,j)
y = A(2,i) - B(2,j)
z = A(3,i) - B(3,j)
C(i,j) = x*x + y*y + z*z
end do
end do
case(1)
do j=1,n
do i=1,m
x = A(i,1) - B(1,j)
y = A(i,2) - B(2,j)
z = A(i,3) - B(3,j)
C(i,j) = x*x + y*y + z*z
end do
end do
case(2)
do j=1,n
do i=1,m
x = A(1,i) - B(j,1)
y = A(2,i) - B(j,2)
z = A(3,i) - B(j,3)
C(i,j) = x*x + y*y + z*z
end do
2020-10-22 00:50:07 +02:00
end do
2020-10-22 01:24:14 +02:00
2020-10-28 20:15:36 +01:00
case(3)
do j=1,n
do i=1,m
x = A(i,1) - B(j,1)
y = A(i,2) - B(j,2)
z = A(i,3) - B(j,3)
C(i,j) = x*x + y*y + z*z
end do
end do
end select
2020-10-25 15:02:37 +01:00
end function qmckl_distance_sq_f
2020-10-25 15:25:15 +01:00
#+END_SRC
2020-10-25 15:02:37 +01:00
2020-10-26 18:24:23 +01:00
*** C interface :noexport:
2020-10-25 15:25:15 +01:00
#+BEGIN_SRC f90 :comments link :tangle qmckl_distance.f90
2020-10-28 20:15:36 +01:00
integer(c_int32_t) function qmckl_distance_sq(context, transa, transb, m, n, A, LDA, B, LDB, C, LDC) &
2020-10-25 15:02:37 +01:00
bind(C) result(info)
use, intrinsic :: iso_c_binding
implicit none
integer (c_int64_t) , intent(in) , value :: context
2020-10-28 20:15:36 +01:00
character (c_char) , intent(in) , value :: transa, transb
2020-10-25 15:02:37 +01:00
integer (c_int64_t) , intent(in) , value :: m, n
integer (c_int64_t) , intent(in) , value :: lda
real (c_double) , intent(in) :: A(lda,3)
integer (c_int64_t) , intent(in) , value :: ldb
real (c_double) , intent(in) :: B(ldb,3)
integer (c_int64_t) , intent(in) , value :: ldc
real (c_double) , intent(out) :: C(ldc,n)
integer, external :: qmckl_distance_sq_f
2020-10-28 20:15:36 +01:00
info = qmckl_distance_sq_f(context, transa, transb, m, n, A, LDA, B, LDB, C, LDC)
2020-10-22 00:50:07 +02:00
end function qmckl_distance_sq
#+END_SRC
2020-10-26 19:30:50 +01:00
#+BEGIN_SRC f90 :comments link :tangle qmckl_distance.fh
interface
2020-10-28 20:15:36 +01:00
integer(c_int32_t) function qmckl_distance_sq(context, transa, transb, m, n, A, LDA, B, LDB, C, LDC) &
2020-10-26 19:30:50 +01:00
bind(C)
use, intrinsic :: iso_c_binding
implicit none
integer (c_int64_t) , intent(in) , value :: context
2020-10-28 20:15:36 +01:00
character (c_char) , intent(in) , value :: transa, transb
2020-10-26 19:30:50 +01:00
integer (c_int64_t) , intent(in) , value :: m, n
integer (c_int64_t) , intent(in) , value :: lda
integer (c_int64_t) , intent(in) , value :: ldb
integer (c_int64_t) , intent(in) , value :: ldc
real (c_double) , intent(in) :: A(lda,3)
real (c_double) , intent(in) :: B(ldb,3)
real (c_double) , intent(out) :: C(ldc,n)
end function qmckl_distance_sq
end interface
#+END_SRC
2020-10-25 15:16:02 +01:00
*** Test :noexport:
2020-10-26 19:30:50 +01:00
#+BEGIN_SRC f90 :comments link :tangle test_qmckl_distance_f.f90
integer(c_int32_t) function test_qmckl_distance_sq(context) bind(C)
use, intrinsic :: iso_c_binding
implicit none
include 'qmckl_distance.fh'
integer(c_int64_t), intent(in), value :: context
2020-10-22 00:50:07 +02:00
2020-10-26 19:30:50 +01:00
double precision, allocatable :: A(:,:), B(:,:), C(:,:)
integer*8 :: m, n, LDA, LDB, LDC
double precision :: x
integer*8 :: i,j
m = 5
n = 6
2020-10-28 20:15:36 +01:00
LDA = m
LDB = n
2020-10-26 19:30:50 +01:00
LDC = 5
2020-10-28 20:15:36 +01:00
allocate( A(LDA,m), B(LDB,n), C(LDC,n) )
2020-10-26 19:30:50 +01:00
2020-10-28 20:15:36 +01:00
do j=1,m
2020-10-26 19:30:50 +01:00
do i=1,m
2020-10-30 16:22:29 +01:00
A(i,j) = -10.d0 + dble(i+j)
2020-10-26 19:30:50 +01:00
end do
2020-10-28 20:15:36 +01:00
end do
do j=1,n
2020-10-26 19:30:50 +01:00
do i=1,n
2020-10-30 16:22:29 +01:00
B(i,j) = -1.d0 + dble(i*j)
2020-10-26 19:30:50 +01:00
end do
end do
2020-10-28 20:15:36 +01:00
test_qmckl_distance_sq = qmckl_distance_sq(context, 'X', 't', m, n, A, LDA, B, LDB, C, LDC)
if (test_qmckl_distance_sq == 0) return
test_qmckl_distance_sq = qmckl_distance_sq(context, 't', 'X', m, n, A, LDA, B, LDB, C, LDC)
if (test_qmckl_distance_sq == 0) return
test_qmckl_distance_sq = qmckl_distance_sq(context, 'T', 't', m, n, A, LDA, B, LDB, C, LDC)
2020-10-26 19:30:50 +01:00
if (test_qmckl_distance_sq /= 0) return
test_qmckl_distance_sq = -1
do j=1,n
do i=1,m
2020-10-30 16:22:29 +01:00
x = (A(i,1)-B(j,1))**2 + &
(A(i,2)-B(j,2))**2 + &
(A(i,3)-B(j,3))**2
if ( dabs(1.d0 - C(i,j)/x) > 1.d-14 ) return
2020-10-26 19:30:50 +01:00
end do
end do
2020-10-28 20:15:36 +01:00
test_qmckl_distance_sq = qmckl_distance_sq(context, 'n', 'T', m, n, A, LDA, B, LDB, C, LDC)
if (test_qmckl_distance_sq /= 0) return
test_qmckl_distance_sq = -1
do j=1,n
do i=1,m
2020-10-30 16:22:29 +01:00
x = (A(1,i)-B(j,1))**2 + &
(A(2,i)-B(j,2))**2 + &
(A(3,i)-B(j,3))**2
if ( dabs(1.d0 - C(i,j)/x) > 1.d-14 ) return
2020-10-28 20:15:36 +01:00
end do
end do
test_qmckl_distance_sq = qmckl_distance_sq(context, 'T', 'n', m, n, A, LDA, B, LDB, C, LDC)
if (test_qmckl_distance_sq /= 0) return
test_qmckl_distance_sq = -1
do j=1,n
do i=1,m
2020-10-30 16:22:29 +01:00
x = (A(i,1)-B(1,j))**2 + &
(A(i,2)-B(2,j))**2 + &
(A(i,3)-B(3,j))**2
if ( dabs(1.d0 - C(i,j)/x) > 1.d-14 ) return
2020-10-28 20:15:36 +01:00
end do
end do
test_qmckl_distance_sq = qmckl_distance_sq(context, 'n', 'N', m, n, A, LDA, B, LDB, C, LDC)
if (test_qmckl_distance_sq /= 0) return
test_qmckl_distance_sq = -1
do j=1,n
do i=1,m
2020-10-30 16:22:29 +01:00
x = (A(1,i)-B(1,j))**2 + &
(A(2,i)-B(2,j))**2 + &
(A(3,i)-B(3,j))**2
if ( dabs(1.d0 - C(i,j)/x) > 1.d-14 ) return
2020-10-28 20:15:36 +01:00
end do
end do
2020-10-30 16:22:29 +01:00
2020-10-26 19:30:50 +01:00
test_qmckl_distance_sq = 0
2020-10-30 16:22:29 +01:00
2020-10-26 19:30:50 +01:00
deallocate(A,B,C)
end function test_qmckl_distance_sq
#+END_SRC
2020-10-30 16:22:29 +01:00
2020-10-26 19:30:50 +01:00
#+BEGIN_SRC C :comments link :tangle test_qmckl_distance.c
int test_qmckl_distance_sq(qmckl_context context);
munit_assert_int(0, ==, test_qmckl_distance_sq(context));
#+END_SRC
2020-10-28 20:15:36 +01:00
* End of files :noexport:
2020-10-22 00:50:07 +02:00
2020-10-28 20:15:36 +01:00
*** Header
2020-10-22 00:50:07 +02:00
#+BEGIN_SRC C :comments link :tangle qmckl_distance.h
#endif
#+END_SRC
2020-10-28 20:15:36 +01:00
*** Test
2020-10-22 00:50:07 +02:00
#+BEGIN_SRC C :comments link :tangle test_qmckl_distance.c
2020-10-22 01:24:14 +02:00
if (qmckl_context_destroy(context) != QMCKL_SUCCESS)
2020-10-22 00:50:07 +02:00
return QMCKL_FAILURE;
return MUNIT_OK;
2020-10-22 01:24:14 +02:00
}
2020-10-22 00:50:07 +02:00
#+END_SRC