source: CIVL/examples/focus/vss_example.cvl

main
Last change on this file was 6d5b8a3, checked in by Alex Wilton <awilton@…>, 8 months ago

Cleaned up focus examples. Enhanced focus window performance. Fixed a pretty print bug

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@5993 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 5.7 KB
Line 
1#include<assert.h>
2#include<mem.cvh>
3
4#pragma CIVL ACSL
5/* Filename : vss_example.cvl
6 Author : Stephen F. Siegel
7 Created : 2023-08-03
8 Modified : 2023-08-07
9
10 Verification of matrix-vector multiplication routine using
11 Compressed Sparse Row representation for the matrix. Start with an
12 arbitrary CSR matrix with N and M under specified bounds. Take an
13 arbitrary vector v of length M. Call sparse matrix-vector
14 multiplication routine to compute "actual" resulting vector.
15 Convert the sparse matrix to a dense matrix and compute dense
16 matrix-vector product to get "expected" result. Check the actual
17 and expected agree.
18*/
19#include <stdio.h>
20#include <stdlib.h>
21#include <pointer.cvh>
22
23/* Compressed Sparse Row (CSR) sparse matrix representation. */
24
25struct csr_matrix {
26 double *val; // length NZ (number of non-0s)
27 int *col_ind; // length NZ
28 int *row_ptr; // length N+1. row_ptr[N]=NZ.
29 int rows, cols; // number of rows (N), number of columns
30};
31
32/* Multiplies matrix m and (dense) vector v, storing result in already
33 allocated vector p. If m has dimensions NxM then v has length M
34 and p has length N. */
35/* Implementation of CSR matrix-vector multiplication from "LAProof: A
36 Library of Formal Proofs of Accuracy and Correctness for Linear
37 Algebra Programs" by Kellison, Appel, Tekriwal, and Bindel, IEEE
38 30th Symposium on Computer Arithmetic, 2023. That paper cites
39 Barrett et al., "Templates for the Solution of Linear Systems:
40 Building Blocks for Iterative Methods", SIAM, 1994, as the source
41 of the algorithm. */
42void csr_matrix_vector_multiply(struct csr_matrix *m, double *v, double *p) {
43 int i, rows=m->rows;
44 double *val = m->val;
45 int *col_ind = m->col_ind;
46 int *row_ptr = m->row_ptr;
47 int next=row_ptr[0];
48 /*@ loop invariant next == row_ptr[i];
49 @ loop assigns p[0..rows-1], next;
50 @ focus F | p[F];
51 @*/
52 for (i=0; i<rows; i++) {
53 double s=0.0;
54 int h=next;
55 next=row_ptr[i+1];
56 for (; h<next; h++) {
57 double x = val[h];
58 int j = col_ind[h];
59 double y = v[j];
60 s = x*y+s;
61 }
62 p[i]=s;
63 }
64}
65
66typedef struct $mat {
67 int n, m; // num rows, columns;
68 double data[][];
69} $mat;
70
71void $mat_vec_mul($mat mat, double * v, double *p) {
72 int n = mat.n, m = mat.m;
73 /*@ loop assigns p[0..n-1];
74 @ focus F | p[F];
75 @*/
76 for (int i=0; i<n; i++) {
77 double s = 0.0;
78 for (int j=0; j<m; j++) s += mat.data[i][j]*v[j];
79 p[i] = s;
80 }
81}
82
83$mat $mat_csr(struct csr_matrix csr) {
84 int n = csr.rows, m = csr.cols;
85 $mat mat;
86 mat.n = n;
87 mat.m = m;
88 mat.data = (double[n][m])$lambda(int i,j) 0.0;
89 /*@ loop assigns mat.data[0..n-1][0..m-1];
90 @ focus F | mat.data[F][0..m-1];
91 @*/
92 for (int i=0; i<n; i++) {
93 int r = csr.row_ptr[i], rnxt = csr.row_ptr[i+1];
94 for (int k=r; k<rnxt; k++)
95 mat.data[i][csr.col_ind[k]] = csr.val[k];
96 }
97 return mat;
98}
99
100// N,M=number of rows,columns. N_B,M_B=upper bounds on N,M
101$input int N_B, M_B = 3, N, M;
102$assume (1<=N && N<=N_B && 1<=M && M<=M_B);
103// the non-0 entries for the matrix and the (dense) vector
104$input double A[N*M], V[M];
105
106/* Fills in p[0],...,p[len-1] with a strictly increasing sequence
107 of integers in [0,max]. Precondition: 0 <= len <= max+1 */
108void strict_inc(int * p, int len, int max) {
109 for (int i=0; i<len; i++) {
110 int a = (i == 0 ? 0 : p[i-1]+1), b = max - len + i + 1;
111 p[i] = a + $choose_int(b-a+1); // choose in a..b
112 }
113}
114
115/* Nondeterministically create a CSR matrix with n rows and
116 m columns */
117struct csr_matrix make_csr(int n, int m) {
118 int * row_ptr = malloc((n+1)*sizeof(int));
119 row_ptr[0] = 0;
120 /*@ loop invariant 0 <= row_ptr[i-1] && row_ptr[i-1] <= (i-1)*m;
121 @ loop assigns row_ptr[1..n];
122 @ focus F+{0..1} | row_ptr[F..F+1];
123 @*/
124 for (int i=1; i<=n; i++) {
125 row_ptr[i] = row_ptr[i-1]+$choose_int(m+1);
126 }
127 //@ focus ordered(<=, F : 0..n | row_ptr[F]);
128 int NZ = row_ptr[n];
129 $assert(0<=NZ && NZ<=n*m);
130 int * col_ind = malloc(NZ*sizeof(int));
131 /*@ loop assigns col_ind[0..NZ-1];
132 @ focus F | col_ind[row_ptr[F]..row_ptr[F+1]-1];
133 @*/
134 for (int i=0; i<n; i++) {
135 strict_inc(col_ind+row_ptr[i], row_ptr[i+1]-row_ptr[i], m-1);
136 }
137 double * val = malloc(NZ*sizeof(double));
138 /*@ loop assigns val[0..NZ-1];
139 @ focus Z | val[Z];
140 @*/
141 for (int i=0; i<NZ; i++) val[i] = A[i];
142 //@ focus Z;
143 $assert($forall(int i:0..NZ-1) val[i] == A[i]);
144 return (struct csr_matrix){ val, col_ind, row_ptr, n, m };
145}
146
147void print_int_array(int * p, int n) {
148 printf("{ ");
149 for (int i=0; i<n; i++) printf("%d ", p[i]);
150 printf("}");
151}
152
153void print_dbl_array(double * p, int n) {
154 printf("{ ");
155 for (int i=0; i<n; i++) printf("%lf ", p[i]);
156 printf("}");
157}
158
159void print_csr(struct csr_matrix mat) {
160 int nz = mat.row_ptr[mat.rows];
161 printf("begin CSR[nrow=%d, ncol=%d, nz=%d]",
162 mat.rows, mat.cols, nz);
163 printf("\n row_ptr = ");
164 print_int_array(mat.row_ptr, mat.rows+1);
165 printf("\n col_ind = ");
166 print_int_array(mat.col_ind, nz);
167 printf("\n val = ");
168 print_dbl_array(mat.val, nz);
169 printf("\nend CSR\n");
170}
171
172void destroy_csr(struct csr_matrix mat) {
173 free(mat.row_ptr);
174 free(mat.col_ind);
175 free(mat.val);
176}
177
178int main(void) {
179 double v[M], actual[N], expected[N];
180 for (int i=0; i<M; i++) v[i] = V[i];
181 struct csr_matrix mat = make_csr(N, M);
182 csr_matrix_vector_multiply(&mat, v, actual);
183 $mat dense = $mat_csr(mat);
184 $mat_vec_mul(dense, v, expected);
185#ifdef VERBOSE
186 printf("\n");
187 print_csr(mat);
188 printf("v = ");
189 print_dbl_array(v, M);
190 printf("\nactual = ");
191 print_dbl_array(actual, N);
192 printf("\nexpected = ");
193 print_dbl_array(expected, N);
194 printf("\n");
195#endif
196 destroy_csr(mat);
197
198 //@ focus F;
199 $assert($forall(int i:0..N-1) actual[i] == expected[i]);
200}
Note: See TracBrowser for help on using the repository browser.