Changes between Version 20 and Version 21 of Examples


Ignore:
Timestamp:
08/04/24 09:51:27 (22 months ago)
Author:
siegel
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Examples

    v20 v21  
    1 {{{
    2 #!comment
    3 https://vsl.cis.udel.edu/civl/demo.html
    4 }}}
     1
     2== Sparse Matrix-Vector Multiplication ==
     3
     4File `csr.h`:
     5{{{
     6#ifndef _CSR_H
     7#define _CSR_H
     8/* Compressed Sparse Row (CSR) sparse matrix representation. */
     9
     10struct csr_matrix {
     11  double *val; // length NZ (number of non-0s)
     12  int *col_ind; // length NZ
     13  int *row_ptr; // length N+1.  row_ptr[N]=NZ.
     14  int rows, cols; // number of rows (N), number of columns
     15};
     16
     17/* Multiplies matrix m and (dense) vector v, storing result in already
     18   allocated vector p.  If m has dimensions NxM then v has length M
     19   and p has length N. */
     20void csr_matrix_vector_multiply(struct csr_matrix *m, double *v, double *p);
     21
     22#endif
     23}}}
     24
     25File `csr.c`:
     26{{{
     27/* Implementation of CSR matrix-vector multiplication from "LAProof: A
     28   Library of Formal Proofs of Accuracy and Correctness for Linear
     29   Algebra Programs" by Kellison, Appel, Tekriwal, and Bindel, IEEE
     30   30th Symposium on Computer Arithmetic, 2023.  That paper cites
     31   Barrett et al., "Templates for the Solution of Linear Systems:
     32   Building Blocks for Iterative Methods", SIAM, 1994, as the source
     33   of the algorithm. */
     34#include "csr.h"
     35
     36#define fma(x,y,s) (x*y+s)
     37
     38void csr_matrix_vector_multiply(struct csr_matrix *m, double *v, double *p) {
     39  int i, rows=m->rows;
     40  double *val = m->val;
     41  int *col_ind = m->col_ind;
     42  int *row_ptr = m->row_ptr;
     43  int next=row_ptr[0];
     44  for (i=0; i<rows; i++) {
     45    double s=0.0;
     46    int h=next;
     47    next=row_ptr[i+1];
     48    for (; h<next; h++) {
     49      double x = val[h];
     50      int j = col_ind[h];
     51      double y = v[j];
     52      s = fma(x,y,s);
     53    }
     54    p[i]=s;
     55  }
     56}
     57}}}
     58
     59File `csr_driver.cvl`:
     60{{{
     61/* Filename : csr.cvl
     62   Author   : Stephen F. Siegel
     63   Created  : 2023-09-03
     64   Modified : 2023-09-04
     65
     66   Verification of matrix-vector multiplication routine using
     67   Compressed Sparse Row representation for the matrix.  Start with an
     68   arbitrary CSR matrix with N and M under specified bounds.  Take an
     69   arbitrary vector v of length M.  Call sparse matrix-vector
     70   multiplication routine to compute "actual" resulting vector.
     71   Convert the sparse matrix to a dense matrix and compute dense
     72   matrix-vector product to get "expected" result.  Check the actual
     73   and expected agree.
     74*/
     75#include <stdio.h>
     76#include <stdlib.h>
     77#include <pointer.cvh>
     78#include "csr.h"
     79
     80// N,M=number of rows,columns.  N_B,M_B=upper bounds on N,M
     81$input int N_B = 3, M_B = 3, N, M;
     82$assume (1<=N && N<=N_B && 1<=M && M<=M_B);
     83// the non-0 entries for the matrix and the (dense) vector
     84$input double A[N*M], V[M];
     85
     86/* Fills in p[0],...,p[len-1] with a strictly increasing sequence
     87   of integers in [0,max].  Precondition: 0 <= len <= max+1 */
     88void strict_inc(int * p, int len, int max) {
     89  $assert(0<=len && len <= max+1);
     90  for (int i=0; i<len; i++) {
     91    int a = (i == 0 ? 0 : p[i-1]+1), b = max - len + i + 1;
     92    p[i] = a + $choose_int(b-a+1); // choose in a..b
     93  }
     94}
     95
     96/* Nondeterministically create a CSR matrix with n rows and
     97   m columns */
     98struct csr_matrix make_csr(int n, int m) {
     99  int * row_ptr = malloc((n+1)*sizeof(int));
     100  row_ptr[0] = 0;
     101  for (int i=1; i<=n; i++)
     102    row_ptr[i] = row_ptr[i-1]+$choose_int(m+1);
     103  int NZ = row_ptr[n];
     104  $assert(0<=NZ && NZ<=n*m);
     105  int * col_ind = malloc(NZ*sizeof(int));
     106  for (int i=0; i<n; i++)
     107    strict_inc(col_ind+row_ptr[i], row_ptr[i+1]-row_ptr[i], m-1);
     108  double * val = malloc(NZ*sizeof(double));
     109  for (int i=0; i<NZ; i++) val[i] = A[i];
     110  return (struct csr_matrix){ val, col_ind, row_ptr, n, m };
     111}
     112
     113void print_int_array(int * p, int n) {
     114  printf("{ ");
     115  for (int i=0; i<n; i++) printf("%d ", p[i]);
     116  printf("}");
     117}
     118
     119void print_dbl_array(double * p, int n) {
     120  printf("{ ");
     121  for (int i=0; i<n; i++) printf("%lf ", p[i]);
     122  printf("}");
     123}
     124
     125void print_csr(struct csr_matrix mat) {
     126  int nz = mat.row_ptr[mat.rows];
     127  printf("begin CSR[nrow=%d, ncol=%d, nz=%d]",
     128         mat.rows, mat.cols, nz);
     129  printf("\n  row_ptr = ");
     130  print_int_array(mat.row_ptr, mat.rows+1);
     131  printf("\n  col_ind = ");
     132  print_int_array(mat.col_ind, nz);
     133  printf("\n  val     = ");
     134  print_dbl_array(mat.val, nz);
     135  printf("\nend CSR\n");
     136}
     137
     138void destroy_csr(struct csr_matrix mat) {
     139  free(mat.row_ptr);
     140  free(mat.col_ind);
     141  free(mat.val);
     142}
     143
     144/* Gets the (i,j)-th entry from the CSR matrix mat */
     145double get_i_j(struct csr_matrix mat, int i, int j) {
     146  int r = mat.row_ptr[i], rnxt = mat.row_ptr[i+1], col;
     147  for (int k=r; k<rnxt; k++) {
     148    col = mat.col_ind[k];
     149    if (col == j) return mat.val[k];
     150    if (col > j) break;
     151  }
     152  return 0.0;
     153}
     154
     155/* Makes a dense matrix from the given CSR matrix */
     156double ** make_dense(struct csr_matrix mat) {
     157  int n = mat.rows, m = mat.cols;
     158  double ** dense = malloc(n*sizeof(double*));
     159  for (int i=0; i<n; i++) {
     160    dense[i] = malloc(m*sizeof(double));
     161    for (int j=0; j<m; j++)
     162      dense[i][j] = get_i_j(mat, i, j);
     163  }
     164  return dense;
     165}
     166
     167void destroy_dense(double ** dense, int nrow) {
     168  for (int i=0; i<nrow; i++) free(dense[i]);
     169  free(dense);
     170}
     171
     172void dense_matrix_vector_multiply(int nrow, int ncol, double ** dense,
     173                                  double * v, double *p) {
     174  for (int i=0; i<nrow; i++) {
     175    double s = 0.0;
     176    for (int j=0; j<ncol; j++) s += dense[i][j]*v[j];
     177    p[i] = s;
     178  }
     179}
     180
     181int main(void) {
     182  double v[M], actual[N], expected[N];
     183  for (int i=0; i<M; i++) v[i] = V[i];
     184  struct csr_matrix mat = make_csr(N, M);
     185  csr_matrix_vector_multiply(&mat, v, actual);
     186  double ** dense = make_dense(mat);
     187  dense_matrix_vector_multiply(N, M, dense, v, expected);
     188#ifdef VERBOSE
     189  printf("\n");
     190  print_csr(mat);
     191  printf("v         = ");
     192  print_dbl_array(v, M);
     193  printf("\nactual    = ");
     194  print_dbl_array(actual, N);
     195  printf("\nexpected  = ");
     196  print_dbl_array(expected, N);
     197  printf("\n");
     198#endif
     199  destroy_csr(mat);
     200  destroy_dense(dense, N);
     201  $assert($equals(actual, expected));
     202}
     203}}}
     204
     205File `Makefile`:
     206{{{
     207
     208small: csr.h csr.c csr_driver.cvl
     209        civl verify -DVERBOSE csr.c csr_driver.cvl
     210
     211medium: csr.h csr.c csr_driver.cvl
     212        civl verify -inputN_B=3 -inputM_B=4 csr.c csr_driver.cvl
     213
     214medium2: csr.h csr.c csr_driver.cvl
     215        civl verify -inputN_B=4 -inputM_B=3 csr.c csr_driver.cvl
     216
     217large: csr.h csr.c csr_driver.cvl
     218        civl verify -inputN_B=4 -inputM_B=4 csr.c csr_driver.cvl
     219
     220clean:
     221        rm -rf CIVLREP *~ *.out *.tmp
     222}}}
     223
     224Output from `make` (excerpted):
     225{{{
     226civl verify -DVERBOSE csr.c csr_driver.cvl
     227CIVL v1.22+ of 2023-10-09 -- http://vsl.cis.udel.edu/civl
     228
     229begin CSR[nrow=3, ncol=3, nz=0]
     230  row_ptr = { 0 0 0 0 }
     231  col_ind = { }
     232  val     = { }
     233end CSR
     234v         = { X_V[0] X_V[1] X_V[2] }
     235actual    = { 0 0 0 }
     236expected  = { 0 0 0 }
     237
     238begin CSR[nrow=3, ncol=3, nz=1]
     239  row_ptr = { 0 0 0 1 }
     240  col_ind = { 0 }
     241  val     = { X_A[0] }
     242end CSR
     243v         = { X_V[0] X_V[1] X_V[2] }
     244actual    = { 0 0 X_V[0]*X_A[0] }
     245expected  = { 0 0 X_V[0]*X_A[0] }
     246
     247begin CSR[nrow=3, ncol=3, nz=1]
     248  row_ptr = { 0 0 0 1 }
     249  col_ind = { 1 }
     250  val     = { X_A[0] }
     251end CSR
     252v         = { X_V[0] X_V[1] X_V[2] }
     253actual    = { 0 0 X_V[1]*X_A[0] }
     254expected  = { 0 0 X_V[1]*X_A[0] }
     255
     256begin CSR[nrow=3, ncol=3, nz=1]
     257  row_ptr = { 0 0 0 1 }
     258  col_ind = { 2 }
     259  val     = { X_A[0] }
     260end CSR
     261v         = { X_V[0] X_V[1] X_V[2] }
     262actual    = { 0 0 X_V[2]*X_A[0] }
     263expected  = { 0 0 X_V[2]*X_A[0] }
     264
     265begin CSR[nrow=3, ncol=3, nz=2]
     266  row_ptr = { 0 0 0 2 }
     267  col_ind = { 0 1 }
     268  val     = { X_A[0] X_A[1] }
     269end CSR
     270v         = { X_V[0] X_V[1] X_V[2] }
     271actual    = { 0 0 (X_V[1]*X_A[1])+(X_V[0]*X_A[0]) }
     272expected  = { 0 0 (X_V[1]*X_A[1])+(X_V[0]*X_A[0]) }
     273
     274begin CSR[nrow=3, ncol=3, nz=2]
     275  row_ptr = { 0 0 0 2 }
     276  col_ind = { 0 2 }
     277  val     = { X_A[0] X_A[1] }
     278end CSR
     279v         = { X_V[0] X_V[1] X_V[2] }
     280actual    = { 0 0 (X_V[2]*X_A[1])+(X_V[0]*X_A[0]) }
     281expected  = { 0 0 (X_V[2]*X_A[1])+(X_V[0]*X_A[0]) }
     282.
     283.
     284.
     285begin CSR[nrow=3, ncol=2, nz=6]
     286  row_ptr = { 0 2 4 6 }
     287  col_ind = { 0 1 0 1 0 1 }
     288  val     = { X_A[0] X_A[1] X_A[2] X_A[3] X_A[4] X_A[5] }
     289end CSR
     290v         = { X_V[0] X_V[1] }
     291actual    = { (X_V[1]*X_A[1])+(X_V[0]*X_A[0]) (X_V[1]*X_A[3])+(X_V[0]*X_A[2]) (X_V[1]*X_A[5])+(X_V[0]*X_A[4]) }
     292expected  = { (X_V[1]*X_A[1])+(X_V[0]*X_A[0]) (X_V[1]*X_A[3])+(X_V[0]*X_A[2]) (X_V[1]*X_A[5])+(X_V[0]*X_A[4]) }
     293.
     294.
     295.
     296begin CSR[nrow=1, ncol=1, nz=1]
     297  row_ptr = { 0 1 }
     298  col_ind = { 0 }
     299  val     = { X_A[0] }
     300end CSR
     301v         = { X_V[0] }
     302actual    = { X_A[0]*X_V[0] }
     303expected  = { X_A[0]*X_V[0] }
     304
     305=== Source files ===
     306csr.c  (csr.c)
     307csr.h  (csr.h)
     308csr_driver.cvl  (csr_driver.cvl)
     309
     310=== Command ===
     311civl verify -DVERBOSE csr.c csr_driver.cvl
     312
     313=== Stats ===
     314   time (s)          : 9.22          transitions  : 215091 
     315   memory (bytes)    : 6.62700032E8  trace steps  : 175869 
     316   max process count : 1             valid calls  : 661988 
     317   states            : 175197        provers      : cvc4, z3
     318   states saved      : 246990        prover calls : 19     
     319   state matches     : 673           
     320
     321=== Result ===
     322All errors marked with '+' are absent on all executions.
     323 + Dereference errors                  + Functional equivalence violations
     324 + Internal errors                     + Library loading errors
     325 + Other errors                        + Assertion violations
     326 + Communication errors                + Writes to constant variables
     327 + Absolute deadlocks                  + Division by zero
     328 + Writes to $input variables          + Invalid casts
     329 + Malloc errors                       + Memory leaks
     330 + Memory management errors            + MPI usage errors
     331 + Out of bounds errors                + Reads from $output variables
     332 + Pointer errors                      + Process leaks
     333 + Sequence errors                     - Non-termination
     334 + Use of undefined values             + Union errors
     335}}}
     336