xref: /petsc/src/dm/dt/tests/ex7.c (revision c4762a1b19cd2af06abeed90e8f9d34fb975dd94)
1*c4762a1bSJed Brown static char help[] = "Test the PetscDTAltV interface for k-forms (alternating k-linear maps).\n\n";
2*c4762a1bSJed Brown 
3*c4762a1bSJed Brown #include <petscviewer.h>
4*c4762a1bSJed Brown #include <petscdt.h>
5*c4762a1bSJed Brown 
6*c4762a1bSJed Brown static PetscErrorCode CheckPullback(PetscInt N, PetscInt M, const PetscReal *L, PetscInt k,
7*c4762a1bSJed Brown                                     const PetscReal *w, PetscReal *x, PetscBool verbose, PetscViewer viewer)
8*c4762a1bSJed Brown {
9*c4762a1bSJed Brown   PetscInt        Nk, Mk, i, j, l;
10*c4762a1bSJed Brown   PetscReal       *Lstarw, *Lx, *Lstar, *Lstarwcheck, wLx, Lstarwx;
11*c4762a1bSJed Brown   PetscReal       diff, diffMat, normMat;
12*c4762a1bSJed Brown   PetscReal       *walloc = NULL;
13*c4762a1bSJed Brown   const PetscReal *ww = NULL;
14*c4762a1bSJed Brown   PetscBool       negative = (PetscBool) (k < 0);
15*c4762a1bSJed Brown   PetscErrorCode  ierr;
16*c4762a1bSJed Brown 
17*c4762a1bSJed Brown   PetscFunctionBegin;
18*c4762a1bSJed Brown   k = PetscAbsInt(k);
19*c4762a1bSJed Brown   ierr = PetscDTBinomialInt(N, k, &Nk);CHKERRQ(ierr);
20*c4762a1bSJed Brown   ierr = PetscDTBinomialInt(M, k, &Mk);CHKERRQ(ierr);
21*c4762a1bSJed Brown   if (negative) {
22*c4762a1bSJed Brown     ierr = PetscMalloc1(Mk, &walloc);CHKERRQ(ierr);
23*c4762a1bSJed Brown     ierr = PetscDTAltVStar(M, M - k, 1, w, walloc);CHKERRQ(ierr);
24*c4762a1bSJed Brown     ww = walloc;
25*c4762a1bSJed Brown   } else {
26*c4762a1bSJed Brown     ww = w;
27*c4762a1bSJed Brown   }
28*c4762a1bSJed Brown   ierr = PetscMalloc2(Nk, &Lstarw, (M*k), &Lx);CHKERRQ(ierr);
29*c4762a1bSJed Brown   ierr = PetscMalloc2(Nk * Mk, &Lstar, Nk, &Lstarwcheck);CHKERRQ(ierr);
30*c4762a1bSJed Brown   ierr = PetscDTAltVPullback(N, M, L, negative ? -k : k, w, Lstarw);CHKERRQ(ierr);
31*c4762a1bSJed Brown   ierr = PetscDTAltVPullbackMatrix(N, M, L, negative ? -k : k, Lstar);CHKERRQ(ierr);
32*c4762a1bSJed Brown   if (negative) {
33*c4762a1bSJed Brown     PetscReal *sLsw;
34*c4762a1bSJed Brown 
35*c4762a1bSJed Brown     ierr = PetscMalloc1(Nk, &sLsw);CHKERRQ(ierr);
36*c4762a1bSJed Brown     ierr = PetscDTAltVStar(N, N - k, 1, Lstarw, sLsw);CHKERRQ(ierr);
37*c4762a1bSJed Brown     ierr = PetscDTAltVApply(N, k, sLsw, x, &Lstarwx);CHKERRQ(ierr);
38*c4762a1bSJed Brown     ierr = PetscFree(sLsw);CHKERRQ(ierr);
39*c4762a1bSJed Brown   } else {
40*c4762a1bSJed Brown     ierr = PetscDTAltVApply(N, k, Lstarw, x, &Lstarwx);CHKERRQ(ierr);
41*c4762a1bSJed Brown   }
42*c4762a1bSJed Brown   for (l = 0; l < k; l++) {
43*c4762a1bSJed Brown     for (i = 0; i < M; i++) {
44*c4762a1bSJed Brown       PetscReal sum = 0.;
45*c4762a1bSJed Brown 
46*c4762a1bSJed Brown       for (j = 0; j < N; j++) sum += L[i * N + j] * x[l * N + j];
47*c4762a1bSJed Brown       Lx[l * M + i] = sum;
48*c4762a1bSJed Brown     }
49*c4762a1bSJed Brown   }
50*c4762a1bSJed Brown   diffMat = 0.;
51*c4762a1bSJed Brown   normMat = 0.;
52*c4762a1bSJed Brown   for (i = 0; i < Nk; i++) {
53*c4762a1bSJed Brown     PetscReal sum = 0.;
54*c4762a1bSJed Brown     for (j = 0; j < Mk; j++) {
55*c4762a1bSJed Brown       sum += Lstar[i * Mk + j] * w[j];
56*c4762a1bSJed Brown     }
57*c4762a1bSJed Brown     Lstarwcheck[i] = sum;
58*c4762a1bSJed Brown     diffMat += PetscSqr(PetscAbsReal(Lstarwcheck[i] - Lstarw[i]));
59*c4762a1bSJed Brown     normMat += PetscSqr(Lstarwcheck[i]) +  PetscSqr(Lstarw[i]);
60*c4762a1bSJed Brown   }
61*c4762a1bSJed Brown   diffMat = PetscSqrtReal(diffMat);
62*c4762a1bSJed Brown   normMat = PetscSqrtReal(normMat);
63*c4762a1bSJed Brown   if (verbose) {
64*c4762a1bSJed Brown     ierr = PetscViewerASCIIPrintf(viewer, "L:\n");CHKERRQ(ierr);
65*c4762a1bSJed Brown     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
66*c4762a1bSJed Brown     if (M*N > 0) {ierr = PetscRealView(M*N, L, viewer);CHKERRQ(ierr);}
67*c4762a1bSJed Brown     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
68*c4762a1bSJed Brown 
69*c4762a1bSJed Brown     ierr = PetscViewerASCIIPrintf(viewer, "L*:\n");CHKERRQ(ierr);
70*c4762a1bSJed Brown     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
71*c4762a1bSJed Brown     if (Nk * Mk > 0) {ierr = PetscRealView(Nk * Mk, Lstar, viewer);CHKERRQ(ierr);}
72*c4762a1bSJed Brown     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
73*c4762a1bSJed Brown 
74*c4762a1bSJed Brown     ierr = PetscViewerASCIIPrintf(viewer, "L*w:\n");CHKERRQ(ierr);
75*c4762a1bSJed Brown     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
76*c4762a1bSJed Brown     if (Nk > 0) {ierr = PetscRealView(Nk, Lstarw, viewer);CHKERRQ(ierr);}
77*c4762a1bSJed Brown     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
78*c4762a1bSJed Brown   }
79*c4762a1bSJed Brown   ierr = PetscDTAltVApply(M, k, ww, Lx, &wLx);CHKERRQ(ierr);
80*c4762a1bSJed Brown   diff = PetscAbsReal(wLx - Lstarwx);
81*c4762a1bSJed Brown   if (diff > 10. * PETSC_SMALL * (PetscAbsReal(wLx) + PetscAbsReal(Lstarwx))) SETERRQ2(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "pullback check: pullback does not commute with application: w(Lx)(%g) != (L* w)(x)(%g)", wLx, Lstarwx);
82*c4762a1bSJed Brown   if (diffMat > PETSC_SMALL * normMat) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "pullback check: pullback matrix does match matrix free result");
83*c4762a1bSJed Brown   ierr = PetscFree2(Lstar, Lstarwcheck);CHKERRQ(ierr);
84*c4762a1bSJed Brown   ierr = PetscFree2(Lstarw, Lx);CHKERRQ(ierr);
85*c4762a1bSJed Brown   ierr = PetscFree(walloc);CHKERRQ(ierr);
86*c4762a1bSJed Brown   PetscFunctionReturn(0);
87*c4762a1bSJed Brown }
88*c4762a1bSJed Brown 
89*c4762a1bSJed Brown int main(int argc, char **argv)
90*c4762a1bSJed Brown {
91*c4762a1bSJed Brown   PetscInt       i, numTests = 5, n[5] = {0, 1, 2, 3, 4};
92*c4762a1bSJed Brown   PetscBool      verbose = PETSC_FALSE;
93*c4762a1bSJed Brown   PetscRandom    rand;
94*c4762a1bSJed Brown   PetscViewer    viewer;
95*c4762a1bSJed Brown   PetscErrorCode ierr;
96*c4762a1bSJed Brown 
97*c4762a1bSJed Brown   ierr = PetscInitialize(&argc,&argv,NULL,help);if (ierr) return ierr;
98*c4762a1bSJed Brown   ierr = PetscOptionsBegin(PETSC_COMM_WORLD,"","Options for exterior algebra tests","none");CHKERRQ(ierr);
99*c4762a1bSJed Brown   ierr = PetscOptionsIntArray("-N", "Up to 5 vector space dimensions to test","ex6.c",n,&numTests,NULL);CHKERRQ(ierr);
100*c4762a1bSJed Brown   ierr = PetscOptionsBool("-verbose", "Verbose test output","ex6.c",verbose,&verbose,NULL);CHKERRQ(ierr);
101*c4762a1bSJed Brown   ierr = PetscOptionsEnd();
102*c4762a1bSJed Brown   ierr = PetscRandomCreate(PETSC_COMM_SELF, &rand);CHKERRQ(ierr);
103*c4762a1bSJed Brown   ierr = PetscRandomSetInterval(rand, -1., 1.);CHKERRQ(ierr);
104*c4762a1bSJed Brown   ierr = PetscRandomSetFromOptions(rand);CHKERRQ(ierr);
105*c4762a1bSJed Brown   if (!numTests) numTests = 5;
106*c4762a1bSJed Brown   viewer = PETSC_VIEWER_STDOUT_(PETSC_COMM_WORLD);
107*c4762a1bSJed Brown   for (i = 0; i < numTests; i++) {
108*c4762a1bSJed Brown     PetscInt       k, N = n[i];
109*c4762a1bSJed Brown 
110*c4762a1bSJed Brown     if (verbose) {ierr = PetscViewerASCIIPrintf(viewer, "N = %D:\n", N);CHKERRQ(ierr);}
111*c4762a1bSJed Brown     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
112*c4762a1bSJed Brown 
113*c4762a1bSJed Brown     if (verbose) {
114*c4762a1bSJed Brown       PetscInt *perm;
115*c4762a1bSJed Brown       PetscInt fac = 1;
116*c4762a1bSJed Brown 
117*c4762a1bSJed Brown       ierr = PetscMalloc1(N, &perm);CHKERRQ(ierr);
118*c4762a1bSJed Brown 
119*c4762a1bSJed Brown       for (k = 1; k <= N; k++) fac *= k;
120*c4762a1bSJed Brown       ierr = PetscViewerASCIIPrintf(viewer, "Permutations of %D:\n", N);CHKERRQ(ierr);
121*c4762a1bSJed Brown       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
122*c4762a1bSJed Brown       for (k = 0; k < fac; k++) {
123*c4762a1bSJed Brown         PetscBool isOdd, isOddCheck;
124*c4762a1bSJed Brown         PetscInt  j, kCheck;
125*c4762a1bSJed Brown 
126*c4762a1bSJed Brown         ierr = PetscDTEnumPerm(N, k, perm, &isOdd);CHKERRQ(ierr);
127*c4762a1bSJed Brown         ierr = PetscViewerASCIIPrintf(viewer, "%D:", k);CHKERRQ(ierr);
128*c4762a1bSJed Brown         for (j = 0; j < N; j++) {
129*c4762a1bSJed Brown           ierr = PetscPrintf(PETSC_COMM_WORLD, " %D", perm[j]);CHKERRQ(ierr);
130*c4762a1bSJed Brown         }
131*c4762a1bSJed Brown         ierr = PetscPrintf(PETSC_COMM_WORLD, ", %s\n", isOdd ? "odd" : "even");CHKERRQ(ierr);
132*c4762a1bSJed Brown         ierr = PetscDTPermIndex(N, perm, &kCheck, &isOddCheck);CHKERRQ(ierr);
133*c4762a1bSJed Brown         if (kCheck != k || isOddCheck != isOdd) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscDTEnumPerm / PetscDTPermIndex mismatch for (%D, %D)\n", N, k);
134*c4762a1bSJed Brown       }
135*c4762a1bSJed Brown       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
136*c4762a1bSJed Brown       ierr = PetscFree(perm);CHKERRQ(ierr);
137*c4762a1bSJed Brown     }
138*c4762a1bSJed Brown     for (k = 0; k <= N; k++) {
139*c4762a1bSJed Brown       PetscInt   j, Nk, M;
140*c4762a1bSJed Brown       PetscReal *w, *v, wv;
141*c4762a1bSJed Brown       PetscInt  *subset;
142*c4762a1bSJed Brown 
143*c4762a1bSJed Brown       ierr = PetscDTBinomialInt(N, k, &Nk);CHKERRQ(ierr);
144*c4762a1bSJed Brown       if (verbose) {ierr = PetscViewerASCIIPrintf(viewer, "k = %D:\n", k);CHKERRQ(ierr);}
145*c4762a1bSJed Brown       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
146*c4762a1bSJed Brown       if (verbose) {ierr = PetscViewerASCIIPrintf(viewer, "(%D choose %D): %D\n", N, k, Nk);CHKERRQ(ierr);}
147*c4762a1bSJed Brown 
148*c4762a1bSJed Brown       /* Test subset and complement enumeration */
149*c4762a1bSJed Brown       ierr = PetscMalloc1(N, &subset);CHKERRQ(ierr);
150*c4762a1bSJed Brown       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
151*c4762a1bSJed Brown       for (j = 0; j < Nk; j++) {
152*c4762a1bSJed Brown         PetscBool isOdd, isOddCheck;
153*c4762a1bSJed Brown         PetscInt  jCheck, kCheck;
154*c4762a1bSJed Brown 
155*c4762a1bSJed Brown         ierr = PetscDTEnumSplit(N, k, j, subset, &isOdd);CHKERRQ(ierr);
156*c4762a1bSJed Brown         ierr = PetscDTPermIndex(N, subset, &kCheck, &isOddCheck);CHKERRQ(ierr);
157*c4762a1bSJed Brown         if (isOddCheck != isOdd) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "PetscDTEnumSplit sign does not mmatch PetscDTPermIndex sign");
158*c4762a1bSJed Brown         if (verbose) {
159*c4762a1bSJed Brown           PetscInt l;
160*c4762a1bSJed Brown 
161*c4762a1bSJed Brown           ierr = PetscViewerASCIIPrintf(viewer, "subset %D:", j);CHKERRQ(ierr);
162*c4762a1bSJed Brown           for (l = 0; l < k; l++) {
163*c4762a1bSJed Brown             ierr = PetscPrintf(PETSC_COMM_WORLD, " %D", subset[l]);CHKERRQ(ierr);
164*c4762a1bSJed Brown           }
165*c4762a1bSJed Brown           ierr = PetscPrintf(PETSC_COMM_WORLD, " |");CHKERRQ(ierr);
166*c4762a1bSJed Brown           for (l = k; l < N; l++) {
167*c4762a1bSJed Brown             ierr = PetscPrintf(PETSC_COMM_WORLD, " %D", subset[l]);CHKERRQ(ierr);
168*c4762a1bSJed Brown           }
169*c4762a1bSJed Brown           ierr = PetscPrintf(PETSC_COMM_WORLD, ", %s\n", isOdd ? "odd" : "even");CHKERRQ(ierr);
170*c4762a1bSJed Brown         }
171*c4762a1bSJed Brown         ierr = PetscDTSubsetIndex(N, k, subset, &jCheck);CHKERRQ(ierr);
172*c4762a1bSJed Brown         if (jCheck != j) SETERRQ2(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "jCheck (%D) != j (%D)", jCheck, j);
173*c4762a1bSJed Brown       }
174*c4762a1bSJed Brown       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
175*c4762a1bSJed Brown       ierr = PetscFree(subset);CHKERRQ(ierr);
176*c4762a1bSJed Brown 
177*c4762a1bSJed Brown       /* Make a random k form */
178*c4762a1bSJed Brown       ierr = PetscMalloc1(Nk, &w);CHKERRQ(ierr);
179*c4762a1bSJed Brown       for (j = 0; j < Nk; j++) {ierr = PetscRandomGetValueReal(rand, &w[j]);CHKERRQ(ierr);}
180*c4762a1bSJed Brown       /* Make a set of random vectors */
181*c4762a1bSJed Brown       ierr = PetscMalloc1(N*k, &v);CHKERRQ(ierr);
182*c4762a1bSJed Brown       for (j = 0; j < N*k; j++) {ierr = PetscRandomGetValueReal(rand, &v[j]);CHKERRQ(ierr);}
183*c4762a1bSJed Brown 
184*c4762a1bSJed Brown       ierr = PetscDTAltVApply(N, k, w, v, &wv);CHKERRQ(ierr);
185*c4762a1bSJed Brown 
186*c4762a1bSJed Brown       if (verbose) {
187*c4762a1bSJed Brown         ierr = PetscViewerASCIIPrintf(viewer, "w:\n");CHKERRQ(ierr);
188*c4762a1bSJed Brown         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
189*c4762a1bSJed Brown         if (Nk) {ierr = PetscRealView(Nk, w, viewer);CHKERRQ(ierr);}
190*c4762a1bSJed Brown         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
191*c4762a1bSJed Brown         ierr = PetscViewerASCIIPrintf(viewer, "v:\n");CHKERRQ(ierr);
192*c4762a1bSJed Brown         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
193*c4762a1bSJed Brown         if (N*k > 0) {ierr = PetscRealView(N*k, v, viewer);CHKERRQ(ierr);}
194*c4762a1bSJed Brown         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
195*c4762a1bSJed Brown         ierr = PetscViewerASCIIPrintf(viewer, "w(v): %g\n", (double) wv);CHKERRQ(ierr);
196*c4762a1bSJed Brown       }
197*c4762a1bSJed Brown 
198*c4762a1bSJed Brown       /* sanity checks */
199*c4762a1bSJed Brown       if (k == 1) { /* 1-forms are functionals (dot products) */
200*c4762a1bSJed Brown         PetscInt  l;
201*c4762a1bSJed Brown         PetscReal wvcheck = 0.;
202*c4762a1bSJed Brown         PetscReal diff;
203*c4762a1bSJed Brown 
204*c4762a1bSJed Brown         for (l = 0; l < N; l++) wvcheck += w[l] * v[l];
205*c4762a1bSJed Brown         diff = PetscSqrtReal(PetscSqr(wvcheck - wv));
206*c4762a1bSJed Brown         if (diff >= PETSC_SMALL * (PetscAbsReal(wv) + PetscAbsReal(wvcheck))) SETERRQ2(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "1-form / dot product equivalence: wvcheck (%g) != wv (%g)", (double) wvcheck, (double) wv);
207*c4762a1bSJed Brown       }
208*c4762a1bSJed Brown       if (k == N && N < 5) { /* n-forms are scaled determinants */
209*c4762a1bSJed Brown         PetscReal det, wvcheck, diff;
210*c4762a1bSJed Brown 
211*c4762a1bSJed Brown         switch (k) {
212*c4762a1bSJed Brown         case 0:
213*c4762a1bSJed Brown           det = 1.;
214*c4762a1bSJed Brown           break;
215*c4762a1bSJed Brown         case 1:
216*c4762a1bSJed Brown           det = v[0];
217*c4762a1bSJed Brown           break;
218*c4762a1bSJed Brown         case 2:
219*c4762a1bSJed Brown           det = v[0] * v[3] - v[1] * v[2];
220*c4762a1bSJed Brown           break;
221*c4762a1bSJed Brown         case 3:
222*c4762a1bSJed Brown           det = v[0] * (v[4] * v[8] - v[5] * v[7]) +
223*c4762a1bSJed Brown                 v[1] * (v[5] * v[6] - v[3] * v[8]) +
224*c4762a1bSJed Brown                 v[2] * (v[3] * v[7] - v[4] * v[6]);
225*c4762a1bSJed Brown           break;
226*c4762a1bSJed Brown         case 4:
227*c4762a1bSJed Brown           det = v[0] * (v[5] * (v[10] * v[15] - v[11] * v[14]) +
228*c4762a1bSJed Brown                         v[6] * (v[11] * v[13] - v[ 9] * v[15]) +
229*c4762a1bSJed Brown                         v[7] * (v[ 9] * v[14] - v[10] * v[13])) -
230*c4762a1bSJed Brown                 v[1] * (v[4] * (v[10] * v[15] - v[11] * v[14]) +
231*c4762a1bSJed Brown                         v[6] * (v[11] * v[12] - v[ 8] * v[15]) +
232*c4762a1bSJed Brown                         v[7] * (v[ 8] * v[14] - v[10] * v[12])) +
233*c4762a1bSJed Brown                 v[2] * (v[4] * (v[ 9] * v[15] - v[11] * v[13]) +
234*c4762a1bSJed Brown                         v[5] * (v[11] * v[12] - v[ 8] * v[15]) +
235*c4762a1bSJed Brown                         v[7] * (v[ 8] * v[13] - v[ 9] * v[12])) -
236*c4762a1bSJed Brown                 v[3] * (v[4] * (v[ 9] * v[14] - v[10] * v[13]) +
237*c4762a1bSJed Brown                         v[5] * (v[10] * v[12] - v[ 8] * v[14]) +
238*c4762a1bSJed Brown                         v[6] * (v[ 8] * v[13] - v[ 9] * v[12]));
239*c4762a1bSJed Brown           break;
240*c4762a1bSJed Brown         default:
241*c4762a1bSJed Brown           SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "invalid k");
242*c4762a1bSJed Brown         }
243*c4762a1bSJed Brown         wvcheck = det * w[0];
244*c4762a1bSJed Brown         diff = PetscSqrtReal(PetscSqr(wvcheck - wv));
245*c4762a1bSJed Brown         if (diff >= PETSC_SMALL * (PetscAbsReal(wv) + PetscAbsReal(wvcheck))) SETERRQ3(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "n-form / determinant equivalence: wvcheck (%g) != wv (%g) %g", (double) wvcheck, (double) wv, (double) diff);
246*c4762a1bSJed Brown       }
247*c4762a1bSJed Brown       if (k > 0) { /* k-forms are linear in each component */
248*c4762a1bSJed Brown         PetscReal alpha;
249*c4762a1bSJed Brown         PetscReal *x, *axv, wx, waxv, waxvcheck;
250*c4762a1bSJed Brown         PetscReal diff;
251*c4762a1bSJed Brown         PetscReal rj;
252*c4762a1bSJed Brown         PetscInt  l;
253*c4762a1bSJed Brown 
254*c4762a1bSJed Brown         ierr = PetscMalloc2(N * k, &x, N * k, &axv);CHKERRQ(ierr);
255*c4762a1bSJed Brown         ierr = PetscRandomGetValueReal(rand, &alpha);CHKERRQ(ierr);
256*c4762a1bSJed Brown         ierr = PetscRandomSetInterval(rand, 0, k);CHKERRQ(ierr);
257*c4762a1bSJed Brown         ierr = PetscRandomGetValueReal(rand, &rj);CHKERRQ(ierr);
258*c4762a1bSJed Brown         j = (PetscInt) rj;
259*c4762a1bSJed Brown         ierr = PetscRandomSetInterval(rand, -1., 1.);CHKERRQ(ierr);
260*c4762a1bSJed Brown         for (l = 0; l < N*k; l++) x[l] = v[l];
261*c4762a1bSJed Brown         for (l = 0; l < N*k; l++) axv[l] = v[l];
262*c4762a1bSJed Brown         for (l = 0; l < N; l++) {
263*c4762a1bSJed Brown           PetscReal val;
264*c4762a1bSJed Brown 
265*c4762a1bSJed Brown           ierr = PetscRandomGetValueReal(rand, &val);CHKERRQ(ierr);
266*c4762a1bSJed Brown           x[j * N + l] = val;
267*c4762a1bSJed Brown           axv[j * N + l] += alpha * val;
268*c4762a1bSJed Brown         }
269*c4762a1bSJed Brown         ierr = PetscDTAltVApply(N, k, w, x, &wx);CHKERRQ(ierr);
270*c4762a1bSJed Brown         ierr = PetscDTAltVApply(N, k, w, axv, &waxv);CHKERRQ(ierr);
271*c4762a1bSJed Brown         waxvcheck = alpha * wx + wv;
272*c4762a1bSJed Brown         diff = waxv - waxvcheck;
273*c4762a1bSJed Brown         if (PetscAbsReal(diff) > 10. * PETSC_SMALL * (PetscAbsReal(waxv) + PetscAbsReal(waxvcheck))) SETERRQ3(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "linearity check: component %D, waxvcheck (%g) != waxv (%g)", j, (double) waxvcheck, (double) waxv);
274*c4762a1bSJed Brown         ierr = PetscFree2(x,axv);CHKERRQ(ierr);
275*c4762a1bSJed Brown       }
276*c4762a1bSJed Brown       if (k > 1) { /* k-forms are antisymmetric */
277*c4762a1bSJed Brown         PetscReal rj, rl, *swapv, wswapv, diff;
278*c4762a1bSJed Brown         PetscInt  l, m;
279*c4762a1bSJed Brown 
280*c4762a1bSJed Brown         ierr = PetscRandomSetInterval(rand, 0, k);CHKERRQ(ierr);
281*c4762a1bSJed Brown         ierr = PetscRandomGetValueReal(rand, &rj);CHKERRQ(ierr);
282*c4762a1bSJed Brown         j = (PetscInt) rj;
283*c4762a1bSJed Brown         l = j;
284*c4762a1bSJed Brown         while (l == j) {
285*c4762a1bSJed Brown           ierr = PetscRandomGetValueReal(rand, &rl);CHKERRQ(ierr);
286*c4762a1bSJed Brown           l = (PetscInt) rl;
287*c4762a1bSJed Brown         }
288*c4762a1bSJed Brown         ierr = PetscRandomSetInterval(rand, -1., 1.);CHKERRQ(ierr);
289*c4762a1bSJed Brown         ierr = PetscMalloc1(N * k, &swapv);CHKERRQ(ierr);
290*c4762a1bSJed Brown         for (m = 0; m < N * k; m++) swapv[m] = v[m];
291*c4762a1bSJed Brown         for (m = 0; m < N; m++) {
292*c4762a1bSJed Brown           swapv[j * N + m] = v[l * N + m];
293*c4762a1bSJed Brown           swapv[l * N + m] = v[j * N + m];
294*c4762a1bSJed Brown         }
295*c4762a1bSJed Brown         ierr = PetscDTAltVApply(N, k, w, swapv, &wswapv);CHKERRQ(ierr);
296*c4762a1bSJed Brown         diff = PetscAbsReal(wswapv + wv);
297*c4762a1bSJed Brown         if (diff > PETSC_SMALL * (PetscAbsReal(wswapv) + PetscAbsReal(wv))) SETERRQ4(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "antisymmetry check: components %D & %D, wswapv (%g) != -wv (%g)", j, l, (double) wswapv, (double) wv);
298*c4762a1bSJed Brown         ierr = PetscFree(swapv);CHKERRQ(ierr);
299*c4762a1bSJed Brown       }
300*c4762a1bSJed Brown       for (j = 0; j <= k && j + k <= N; j++) { /* wedge product */
301*c4762a1bSJed Brown         PetscInt   Nj, Njk, l, JKj;
302*c4762a1bSJed Brown         PetscReal *u, *uWw, *uWwcheck, *uWwmat, *x, *xsplit, uWwx, uWwxcheck, diff, norm;
303*c4762a1bSJed Brown         PetscInt  *split;
304*c4762a1bSJed Brown 
305*c4762a1bSJed Brown         if (verbose) {ierr = PetscViewerASCIIPrintf(viewer, "wedge j = %D:\n", j);CHKERRQ(ierr);}
306*c4762a1bSJed Brown         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
307*c4762a1bSJed Brown         ierr = PetscDTBinomialInt(N, j,   &Nj);CHKERRQ(ierr);
308*c4762a1bSJed Brown         ierr = PetscDTBinomialInt(N, j+k, &Njk);CHKERRQ(ierr);
309*c4762a1bSJed Brown         ierr = PetscMalloc4(Nj, &u, Njk, &uWw, N*(j+k), &x, N*(j+k), &xsplit);CHKERRQ(ierr);
310*c4762a1bSJed Brown         ierr = PetscMalloc1(j+k,&split);CHKERRQ(ierr);
311*c4762a1bSJed Brown         for (l = 0; l < Nj; l++) {ierr = PetscRandomGetValueReal(rand, &u[l]);CHKERRQ(ierr);}
312*c4762a1bSJed Brown         for (l = 0; l < N*(j+k); l++) {ierr = PetscRandomGetValueReal(rand, &x[l]);CHKERRQ(ierr);}
313*c4762a1bSJed Brown         ierr = PetscDTAltVWedge(N, j, k, u, w, uWw);CHKERRQ(ierr);
314*c4762a1bSJed Brown         ierr = PetscDTAltVApply(N, j+k, uWw, x, &uWwx);CHKERRQ(ierr);
315*c4762a1bSJed Brown         if (verbose) {
316*c4762a1bSJed Brown           ierr = PetscViewerASCIIPrintf(viewer, "u:\n");CHKERRQ(ierr);
317*c4762a1bSJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
318*c4762a1bSJed Brown           if (Nj) {ierr = PetscRealView(Nj, u, viewer);CHKERRQ(ierr);}
319*c4762a1bSJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
320*c4762a1bSJed Brown           ierr = PetscViewerASCIIPrintf(viewer, "u wedge w:\n");CHKERRQ(ierr);
321*c4762a1bSJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
322*c4762a1bSJed Brown           if (Njk) {ierr = PetscRealView(Njk, uWw, viewer);CHKERRQ(ierr);}
323*c4762a1bSJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
324*c4762a1bSJed Brown           ierr = PetscViewerASCIIPrintf(viewer, "x:\n");CHKERRQ(ierr);
325*c4762a1bSJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
326*c4762a1bSJed Brown           if (N*(j+k) > 0) {ierr = PetscRealView(N*(j+k), x, viewer);CHKERRQ(ierr);}
327*c4762a1bSJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
328*c4762a1bSJed Brown           ierr = PetscViewerASCIIPrintf(viewer, "u wedge w(x): %g\n", (double) uWwx);CHKERRQ(ierr);
329*c4762a1bSJed Brown         }
330*c4762a1bSJed Brown         /* verify wedge formula */
331*c4762a1bSJed Brown         uWwxcheck = 0.;
332*c4762a1bSJed Brown         ierr = PetscDTBinomialInt(j+k, j, &JKj);CHKERRQ(ierr);
333*c4762a1bSJed Brown         for (l = 0; l < JKj; l++) {
334*c4762a1bSJed Brown           PetscBool isOdd;
335*c4762a1bSJed Brown           PetscReal ux, wx;
336*c4762a1bSJed Brown           PetscInt  m, p;
337*c4762a1bSJed Brown 
338*c4762a1bSJed Brown           ierr = PetscDTEnumSplit(j+k, j, l, split, &isOdd);CHKERRQ(ierr);
339*c4762a1bSJed Brown           for (m = 0; m < j+k; m++) {for (p = 0; p < N; p++) {xsplit[m * N + p] = x[split[m] * N + p];}}
340*c4762a1bSJed Brown           ierr = PetscDTAltVApply(N, j, u, xsplit, &ux);CHKERRQ(ierr);
341*c4762a1bSJed Brown           ierr = PetscDTAltVApply(N, k, w, &xsplit[j*N], &wx);CHKERRQ(ierr);
342*c4762a1bSJed Brown           uWwxcheck += isOdd ? -(ux * wx) : (ux * wx);
343*c4762a1bSJed Brown         }
344*c4762a1bSJed Brown         diff = PetscAbsReal(uWwx - uWwxcheck);
345*c4762a1bSJed Brown         if (diff > 10. * PETSC_SMALL * (PetscAbsReal(uWwx) + PetscAbsReal(uWwxcheck))) SETERRQ4(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "wedge check: forms %D & %D, uWwxcheck (%g) != uWwx (%g)", j, k, (double) uWwxcheck, (double) uWwx);
346*c4762a1bSJed Brown         ierr = PetscFree(split);CHKERRQ(ierr);
347*c4762a1bSJed Brown         ierr = PetscMalloc2(Nk * Njk, &uWwmat, Njk, &uWwcheck);CHKERRQ(ierr);
348*c4762a1bSJed Brown         ierr = PetscDTAltVWedgeMatrix(N, j, k, u, uWwmat);CHKERRQ(ierr);
349*c4762a1bSJed Brown         if (verbose) {
350*c4762a1bSJed Brown           ierr = PetscViewerASCIIPrintf(viewer, "(u wedge):\n");CHKERRQ(ierr);
351*c4762a1bSJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
352*c4762a1bSJed Brown           if ((Nk * Njk) > 0) {ierr = PetscRealView(Nk * Njk, uWwmat, viewer);CHKERRQ(ierr);}
353*c4762a1bSJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
354*c4762a1bSJed Brown         }
355*c4762a1bSJed Brown         diff = 0.;
356*c4762a1bSJed Brown         norm = 0.;
357*c4762a1bSJed Brown         for (l = 0; l < Njk; l++) {
358*c4762a1bSJed Brown           PetscInt  m;
359*c4762a1bSJed Brown           PetscReal sum = 0.;
360*c4762a1bSJed Brown 
361*c4762a1bSJed Brown           for (m = 0; m < Nk; m++) sum += uWwmat[l * Nk + m] * w[m];
362*c4762a1bSJed Brown           uWwcheck[l] = sum;
363*c4762a1bSJed Brown           diff += PetscSqr(uWwcheck[l] - uWw[l]);
364*c4762a1bSJed Brown           norm += PetscSqr(uWwcheck[l]) + PetscSqr(uWw[l]);
365*c4762a1bSJed Brown         }
366*c4762a1bSJed Brown         diff = PetscSqrtReal(diff);
367*c4762a1bSJed Brown         norm = PetscSqrtReal(norm);
368*c4762a1bSJed Brown         if (diff > PETSC_SMALL * norm) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "wedge matrix check: wedge matrix application does not match wedge direct application");
369*c4762a1bSJed Brown         ierr = PetscFree2(uWwmat, uWwcheck);CHKERRQ(ierr);
370*c4762a1bSJed Brown         ierr = PetscFree4(u, uWw, x, xsplit);CHKERRQ(ierr);
371*c4762a1bSJed Brown         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
372*c4762a1bSJed Brown       }
373*c4762a1bSJed Brown       for (M = PetscMax(1,k); M <= N; M++) { /* pullback */
374*c4762a1bSJed Brown         PetscReal   *L, *u, *x;
375*c4762a1bSJed Brown         PetscInt     Mk, l;
376*c4762a1bSJed Brown 
377*c4762a1bSJed Brown         ierr = PetscDTBinomialInt(M, k, &Mk);CHKERRQ(ierr);
378*c4762a1bSJed Brown         ierr = PetscMalloc3(M*N, &L, Mk, &u, M*k, &x);CHKERRQ(ierr);
379*c4762a1bSJed Brown         for (l = 0; l < M*N; l++) {ierr = PetscRandomGetValueReal(rand, &L[l]);CHKERRQ(ierr);}
380*c4762a1bSJed Brown         for (l = 0; l < Mk; l++) {ierr = PetscRandomGetValueReal(rand, &u[l]);CHKERRQ(ierr);}
381*c4762a1bSJed Brown         for (l = 0; l < M*k; l++) {ierr = PetscRandomGetValueReal(rand, &x[l]);CHKERRQ(ierr);}
382*c4762a1bSJed Brown         if (verbose) {ierr = PetscViewerASCIIPrintf(viewer, "pullback M = %D:\n", M);CHKERRQ(ierr);}
383*c4762a1bSJed Brown         ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
384*c4762a1bSJed Brown         ierr = CheckPullback(M, N, L, k, w, x, verbose, viewer);CHKERRQ(ierr);
385*c4762a1bSJed Brown         if (M != N) {ierr = CheckPullback(N, M, L, k, u, v, PETSC_FALSE, viewer);CHKERRQ(ierr);}
386*c4762a1bSJed Brown         ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
387*c4762a1bSJed Brown         if ((k % N) && (N > 1)) {
388*c4762a1bSJed Brown           if (verbose) {ierr = PetscViewerASCIIPrintf(viewer, "negative pullback M = %D:\n", M);CHKERRQ(ierr);}
389*c4762a1bSJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
390*c4762a1bSJed Brown           ierr = CheckPullback(M, N, L, -k, w, x, verbose, viewer);CHKERRQ(ierr);
391*c4762a1bSJed Brown           if (M != N) {ierr = CheckPullback(N, M, L, -k, u, v, PETSC_FALSE, viewer);CHKERRQ(ierr);}
392*c4762a1bSJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
393*c4762a1bSJed Brown         }
394*c4762a1bSJed Brown         ierr = PetscFree3(L, u, x);CHKERRQ(ierr);
395*c4762a1bSJed Brown       }
396*c4762a1bSJed Brown       if (k > 0) { /* Interior */
397*c4762a1bSJed Brown         PetscInt    Nkm, l, m;
398*c4762a1bSJed Brown         PetscReal  *wIntv0, *wIntv0check, wvcheck, diff, diffMat, normMat;
399*c4762a1bSJed Brown         PetscReal  *intv0mat, *matcheck;
400*c4762a1bSJed Brown         PetscInt  (*indices)[3];
401*c4762a1bSJed Brown 
402*c4762a1bSJed Brown         ierr = PetscDTBinomialInt(N, k-1, &Nkm);CHKERRQ(ierr);
403*c4762a1bSJed Brown         ierr = PetscMalloc5(Nkm, &wIntv0, Nkm, &wIntv0check, Nk * Nkm, &intv0mat, Nk * Nkm, &matcheck, Nk * k, &indices);CHKERRQ(ierr);
404*c4762a1bSJed Brown         ierr = PetscDTAltVInterior(N, k, w, v, wIntv0);CHKERRQ(ierr);
405*c4762a1bSJed Brown         ierr = PetscDTAltVInteriorMatrix(N, k, v, intv0mat);CHKERRQ(ierr);
406*c4762a1bSJed Brown         ierr = PetscDTAltVInteriorPattern(N, k, indices);CHKERRQ(ierr);
407*c4762a1bSJed Brown         if (verbose) {
408*c4762a1bSJed Brown           ierr = PetscViewerASCIIPrintf(viewer, "interior product matrix pattern:\n");CHKERRQ(ierr);
409*c4762a1bSJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
410*c4762a1bSJed Brown           for (l = 0; l < Nk * k; l++) {
411*c4762a1bSJed Brown             PetscInt row = indices[l][0];
412*c4762a1bSJed Brown             PetscInt col = indices[l][1];
413*c4762a1bSJed Brown             PetscInt x   = indices[l][2];
414*c4762a1bSJed Brown 
415*c4762a1bSJed Brown             ierr = PetscViewerASCIIPrintf(viewer,"intV[%D,%D] = %sV[%D]\n", row, col, x < 0 ? "-" : " ", x < 0 ? -(x + 1) : x);CHKERRQ(ierr);
416*c4762a1bSJed Brown           }
417*c4762a1bSJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
418*c4762a1bSJed Brown         }
419*c4762a1bSJed Brown         for (l = 0; l < Nkm * Nk; l++) matcheck[l] = 0.;
420*c4762a1bSJed Brown         for (l = 0; l < Nk * k; l++) {
421*c4762a1bSJed Brown           PetscInt row = indices[l][0];
422*c4762a1bSJed Brown           PetscInt col = indices[l][1];
423*c4762a1bSJed Brown           PetscInt x   = indices[l][2];
424*c4762a1bSJed Brown 
425*c4762a1bSJed Brown           if (x < 0) {
426*c4762a1bSJed Brown             matcheck[row * Nk + col] = -v[-(x+1)];
427*c4762a1bSJed Brown           } else {
428*c4762a1bSJed Brown             matcheck[row * Nk + col] = v[x];
429*c4762a1bSJed Brown           }
430*c4762a1bSJed Brown         }
431*c4762a1bSJed Brown         diffMat = 0.;
432*c4762a1bSJed Brown         normMat = 0.;
433*c4762a1bSJed Brown         for (l = 0; l < Nkm * Nk; l++) {
434*c4762a1bSJed Brown           diffMat += PetscSqr(PetscAbsReal(matcheck[l] - intv0mat[l]));
435*c4762a1bSJed Brown           normMat += PetscSqr(matcheck[l]) + PetscSqr(intv0mat[l]);
436*c4762a1bSJed Brown         }
437*c4762a1bSJed Brown         diffMat = PetscSqrtReal(diffMat);
438*c4762a1bSJed Brown         normMat = PetscSqrtReal(normMat);
439*c4762a1bSJed Brown         if (diffMat > PETSC_SMALL * normMat) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Interior product check: matrix pattern does not match matrix");
440*c4762a1bSJed Brown         diffMat = 0.;
441*c4762a1bSJed Brown         normMat = 0.;
442*c4762a1bSJed Brown         for (l = 0; l < Nkm; l++) {
443*c4762a1bSJed Brown           PetscReal sum = 0.;
444*c4762a1bSJed Brown 
445*c4762a1bSJed Brown           for (m = 0; m < Nk; m++) sum += intv0mat[l * Nk + m] * w[m];
446*c4762a1bSJed Brown           wIntv0check[l] = sum;
447*c4762a1bSJed Brown 
448*c4762a1bSJed Brown           diffMat += PetscSqr(PetscAbsReal(wIntv0check[l] - wIntv0[l]));
449*c4762a1bSJed Brown           normMat += PetscSqr(wIntv0check[l]) + PetscSqr(wIntv0[l]);
450*c4762a1bSJed Brown         }
451*c4762a1bSJed Brown         diffMat = PetscSqrtReal(diffMat);
452*c4762a1bSJed Brown         normMat = PetscSqrtReal(normMat);
453*c4762a1bSJed Brown         if (diffMat > PETSC_SMALL * normMat) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Interior product check: application does not match matrix");
454*c4762a1bSJed Brown         if (verbose) {
455*c4762a1bSJed Brown           ierr = PetscViewerASCIIPrintf(viewer, "(w int v_0):\n");CHKERRQ(ierr);
456*c4762a1bSJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
457*c4762a1bSJed Brown           if (Nkm) {ierr = PetscRealView(Nkm, wIntv0, viewer);CHKERRQ(ierr);}
458*c4762a1bSJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
459*c4762a1bSJed Brown 
460*c4762a1bSJed Brown           ierr = PetscViewerASCIIPrintf(viewer, "(int v_0):\n");CHKERRQ(ierr);
461*c4762a1bSJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
462*c4762a1bSJed Brown           if (Nk * Nkm > 0) {ierr = PetscRealView(Nk * Nkm, intv0mat, viewer);CHKERRQ(ierr);}
463*c4762a1bSJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
464*c4762a1bSJed Brown         }
465*c4762a1bSJed Brown         ierr = PetscDTAltVApply(N, k - 1, wIntv0, &v[N], &wvcheck);CHKERRQ(ierr);
466*c4762a1bSJed Brown         diff = PetscSqrtReal(PetscSqr(wvcheck - wv));
467*c4762a1bSJed Brown         if (diff >= PETSC_SMALL * (PetscAbsReal(wv) + PetscAbsReal(wvcheck))) SETERRQ2(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Interior product check: (w Int v0)(v_rem) (%g) != w(v) (%g)", (double) wvcheck, (double) wv);
468*c4762a1bSJed Brown         ierr = PetscFree5(wIntv0,wIntv0check,intv0mat,matcheck,indices);CHKERRQ(ierr);
469*c4762a1bSJed Brown       }
470*c4762a1bSJed Brown       if (k >= N - k) { /* Hodge star */
471*c4762a1bSJed Brown         PetscReal *u, *starw, *starstarw, wu, starwdotu;
472*c4762a1bSJed Brown         PetscReal diff, norm;
473*c4762a1bSJed Brown         PetscBool isOdd;
474*c4762a1bSJed Brown         PetscInt l;
475*c4762a1bSJed Brown 
476*c4762a1bSJed Brown         isOdd = (PetscBool) ((k * (N - k)) & 1);
477*c4762a1bSJed Brown         ierr = PetscMalloc3(Nk, &u, Nk, &starw, Nk, &starstarw);CHKERRQ(ierr);
478*c4762a1bSJed Brown         ierr = PetscDTAltVStar(N, k, 1, w, starw);CHKERRQ(ierr);
479*c4762a1bSJed Brown         ierr = PetscDTAltVStar(N, N-k, 1, starw, starstarw);CHKERRQ(ierr);
480*c4762a1bSJed Brown         if (verbose) {
481*c4762a1bSJed Brown           ierr = PetscViewerASCIIPrintf(viewer, "star w:\n");CHKERRQ(ierr);
482*c4762a1bSJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
483*c4762a1bSJed Brown           if (Nk) {ierr = PetscRealView(Nk, starw, viewer);CHKERRQ(ierr);}
484*c4762a1bSJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
485*c4762a1bSJed Brown 
486*c4762a1bSJed Brown           ierr = PetscViewerASCIIPrintf(viewer, "star star w:\n");CHKERRQ(ierr);
487*c4762a1bSJed Brown           ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
488*c4762a1bSJed Brown           if (Nk) {ierr = PetscRealView(Nk, starstarw, viewer);CHKERRQ(ierr);}
489*c4762a1bSJed Brown           ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
490*c4762a1bSJed Brown         }
491*c4762a1bSJed Brown         for (l = 0; l < Nk; l++) {ierr = PetscRandomGetValueReal(rand,&u[l]);CHKERRQ(ierr);}
492*c4762a1bSJed Brown         ierr = PetscDTAltVWedge(N, k, N - k, w, u, &wu);CHKERRQ(ierr);
493*c4762a1bSJed Brown         starwdotu = 0.;
494*c4762a1bSJed Brown         for (l = 0; l < Nk; l++) starwdotu += starw[l] * u[l];
495*c4762a1bSJed Brown         diff = PetscAbsReal(wu - starwdotu);
496*c4762a1bSJed Brown         if (diff > PETSC_SMALL * (PetscAbsReal(wu) + PetscAbsReal(starwdotu))) SETERRQ2(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Hodge star check: (star w, u) (%g) != (w wedge u) (%g)", (double) starwdotu, (double) wu);
497*c4762a1bSJed Brown 
498*c4762a1bSJed Brown         diff = 0.;
499*c4762a1bSJed Brown         norm = 0.;
500*c4762a1bSJed Brown         for (l = 0; l < Nk; l++) {
501*c4762a1bSJed Brown           diff += PetscSqr(w[l] - (isOdd ? -starstarw[l] : starstarw[l]));
502*c4762a1bSJed Brown           norm += PetscSqr(w[l]) + PetscSqr(starstarw[l]);
503*c4762a1bSJed Brown         }
504*c4762a1bSJed Brown         diff = PetscSqrtReal(diff);
505*c4762a1bSJed Brown         norm = PetscSqrtReal(norm);
506*c4762a1bSJed Brown         if (diff > PETSC_SMALL * norm) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_PLIB, "Hodge star check: star(star(w)) != (-1)^(N*(N-k)) w");
507*c4762a1bSJed Brown         ierr = PetscFree3(u, starw, starstarw);CHKERRQ(ierr);
508*c4762a1bSJed Brown       }
509*c4762a1bSJed Brown       ierr = PetscFree(v);CHKERRQ(ierr);
510*c4762a1bSJed Brown       ierr = PetscFree(w);CHKERRQ(ierr);
511*c4762a1bSJed Brown       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
512*c4762a1bSJed Brown     }
513*c4762a1bSJed Brown     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
514*c4762a1bSJed Brown   }
515*c4762a1bSJed Brown   ierr = PetscRandomDestroy(&rand);CHKERRQ(ierr);
516*c4762a1bSJed Brown   ierr = PetscFinalize();
517*c4762a1bSJed Brown   return ierr;
518*c4762a1bSJed Brown }
519*c4762a1bSJed Brown 
520*c4762a1bSJed Brown /*TEST
521*c4762a1bSJed Brown   test:
522*c4762a1bSJed Brown     suffix: 1234
523*c4762a1bSJed Brown     args: -verbose
524*c4762a1bSJed Brown   test:
525*c4762a1bSJed Brown     suffix: 56
526*c4762a1bSJed Brown     args: -N 5,6
527*c4762a1bSJed Brown TEST*/
528