/* ** * \brief * Create the following from the given components: * | M Y | * | X X.Minv.Y + Pinv.A.Qinv | */ static gf2matrix *extend_by_blocks(const gf2matrix *m, const gf2matrix *x, const gf2matrix *y, const gf2matrix *xminvy, const gf2matrix *pinv, const gf2matrix *a, const gf2matrix *qinv) { gf2matrix *result = NULL; gf2matrix *addterm = NULL; /* print_matrix(xminvy, "X.Minv.Y: "); */ { gf2matrix *aqinv = NULL, *pinvaqinv = NULL; aqinv = mul_matrices(NULL, a, qinv); assert(aqinv); pinvaqinv = mul_matrices(NULL, pinv, aqinv); assert(pinvaqinv); /* print_matrix(pinvaqinv, "Pinv.A.Qinv: "); */ addterm = add_matrices(NULL, xminvy, pinvaqinv); free_matrix(aqinv); free_matrix(pinvaqinv); } assert(addterm); /* print_matrix(addterm, "X.Minv.Y + Pinv.A.Qinv: "); */ assert(is_invertible(addterm)); result = combine_matrices(m, y, x, addterm); assert(result); if (!is_invertible(result)) { /* printf("extended matrix was not invertible. incorrect calculations\n"); */ /* print_matrix(result, "result: "); */ free_matrix(result); result = NULL; } free_matrix(addterm); return result; }
/* solve generalized linear set of equations using LU-decomposition * INPUT * n1, n2 : dimension * A [n1 * n1] : * B [n1 * n2] : * C [n2 * n1] : * D [n2 * n2] : * * E [n1 * n1] : * F [n1 * n2] : * G [n2 * n1] : * H [n2 * n2] : * where the generalized linear set of equations is * [A B](x) = [E F](b) * [C D](y) [G H](c) * OUTPUT * I [n1 * n1] : * J [n1 * n2] : * K [n2 * n1] : * L [n2 * n2] : * where the generalized linear set of equations is * (x) = [I J](b) * (c) [K L](y) * note that A-D, E-H are destroyed! */ void solve_gen_linear (int n1, int n2, double * A, double * B, double * C, double * D, double * E, double * F, double * G, double * H, double * I, double * J, double * K, double * L) { /* H := H^-1 */ lapack_inv_ (n2, H); /* C := (H^-1) . C */ mul_left_sq (C, n2, n1, H); /* G := (H^-1) . G */ mul_left_sq (G, n2, n1, H); /* D := (H^-1) . D */ mul_left_sq (D, n2, n2, H); double *a = (double *)malloc (sizeof (double) * n1 * n1); double *e = (double *)malloc (sizeof (double) * n1 * n1); double *b = (double *)malloc (sizeof (double) * n1 * n2); CHECK_MALLOC (a, "solve_gen_linear"); CHECK_MALLOC (e, "solve_gen_linear"); CHECK_MALLOC (b, "solve_gen_linear"); /* a [n1, n1] := A - F.(H^-1).C */ add_and_mul (A, n1, n1, F, n1, n2, C, n2, n1, 1.0, -1.0, a); // e [n1, n1] := E - F.(H^-1).G add_and_mul (E, n1, n1, F, n1, n2, G, n2, n1, 1.0, -1.0, e); // b [n1, n2] := - B + F.(H^-1).D add_and_mul (B, n1, n2, F, n1, n2, D, n2, n2, -1.0, 1.0, b); /* a := (A-F.(H^-1).C)^-1 */ lapack_inv_ (n1, a); /* I := a.e */ mul_matrices (a, n1, n1, e, n1, n1, I); /* J := a.b */ mul_matrices (a, n1, n1, b, n1, n2, J); free (a); free (e); free (b); // K := - G + C.I add_and_mul (G, n2, n1, C, n2, n1, I, n1, n1, -1.0, 1.0, K); // L := D + C.J add_and_mul (D, n2, n2, C, n2, n1, J, n1, n2, 1.0, 1.0, L); }
gf2matrix *invert_matrix(gf2matrix *dest, const gf2matrix *m) { if (!m) return NULL; mzd_t *temp = mzd_inv_m4ri(NULL, (mzd_t*) m, 0); if(!temp) { dest = NULL; } else { mzd_t *I = make_identity_matrix(m->nrows); mzd_t *prod = mul_matrices(NULL, m, temp); if(comp_matrices(prod, I) == 0) { // inversion was successful if (dest) { mzd_copy(dest, temp); mzd_free(temp); } else { dest = temp; } } else { dest = NULL; } mzd_free(prod); mzd_free(I); } return dest; }
/* D = a * A + b * B . C * INPUT * A [na1, na2] * B [nb1, nb2] * C [nc1, nc2] * a * b * where (nb2 == nc1) && (na1 = nb1) && (na2 == nc2) * OUTPUT * D [na1, na2] = a * A [na1, na2] + b * B [nb1, nb2] . C [nc1, nc2] */ void add_and_mul (const double *A, int na1, int na2, const double *B, int nb1, int nb2, const double *C, int nc1, int nc2, double a, double b, double *D) { if (nb2 != nc1 || na1 != nb1 || na2 != nc2) { fprintf (stderr, "illeagal multiplication in add_and_mul().\n"); exit (1); } if (A == D) { fprintf (stderr, "illeagal pointer D in add_and_mul().\n"); exit (1); } mul_matrices (B, nb1, nb2, C, nc1, nc2, D); int i; for (i = 0; i < na1*na2; i ++) { D[i] = a * A[i] + b * D[i]; } }
void main(int argc, char *argv[]) { if (argc!=1) { printf("Sorry, I don't take command line arguments.\n"); exit(-1); } else { get_first(); get_matrices(); mul_matrices(); print_out(); } }
/* solve linear set of equations using LU-decomposition * INPUT * n1, n2 : dimension * A [n1 * n1] : * B [n1 * n2] : * C [n2 * n1] : * D [n2 * n2] : * where the generalized linear set of equations is * (b) = [A B](x) * (c) [C D](y) * OUTPUT * I [n1 * n1] : * J [n1 * n2] : * K [n2 * n1] : * L [n2 * n2] : * where the generalized linear set of equations is * (x) = [I J](b) * (c) [K L](y) * note that A-D are destroyed! */ void solve_linear (int n1, int n2, double * A, double * B, double * C, double * D, double * I, double * J, double * K, double * L) { int i; /* type 1 */ /* A := A^-1 */ lapack_inv_ (n1, A); /* B := (A^-1).B */ double *tmp = (double *) malloc (sizeof (double) * n1 * n2); CHECK_MALLOC (tmp, "solve_linear"); mul_matrices (A, n1, n1, B, n1, n2, tmp); for (i = 0; i < n1 * n2; i ++) { B[i] = tmp[i]; } free (tmp); // L [n2, n2] := D - C.(A^-1).B add_and_mul (D, n2, n2, C, n2, n1, B, n1, n2, 1.0, -1.0, L); // K := C.A mul_matrices (C, n2, n1, A, n1, n1, K); for (i = 0; i < n1 * n1; ++i) { I [i] = A [i]; } for (i = 0; i < n1 * n2; ++i) { J [i] = - B [i]; } }
int mul_byte_by_matrix(uint8_t *result, const gf2matrix *m, uint8_t byte) { /** * 1. convert byte to a matrix (vector) * 2. multiply vector by m; obtain result matrix * 3. convert result matrix into byte array */ int i; int octets = get_rows(m) / 8; gf2matrix *vec = new_matrix(8, 1); byte2vector(vec, byte); gf2matrix *prod = mul_matrices(NULL, (gf2matrix *) m, vec); for (i = 0; i < octets; ++i) { vector2byte_offset(&result[i], prod, i * 8); } free_matrix(vec); free_matrix(prod); return 0; }
/* return B . A in A, where B is square matrix * Remark!! this is not A.B!! * INPUT * A [na1, na2] * B [nb, nb] : square matrix! * where (nb == na1) * OUTPUT * A [na1, na2] = B [nb, nb] . A [na1, na2] */ static void mul_left_sq (double * A, int na1, int na2, const double * B) { int i; int nb = na1; double *tmp = (double *) malloc (sizeof (double) * na1 * na2); CHECK_MALLOC (tmp, "mul_left_sq"); mul_matrices (B, nb, nb, A, na1, na2, tmp); for (i = 0; i < na1 * na2; ++i) { A [i] = tmp [i]; } free (tmp); }
int mul_array_by_matrix(uint8_t *result, const gf2matrix *m, const uint8_t *bytes) { /** * 1. convert the input byte array to a matrix (vector) * 2. multiply vector by m; obtain result matrix * 3. convert result matrix into byte array */ int i; int octets = get_rows(m) / 8; gf2matrix *prod; gf2matrix *vec = new_matrix(get_rows(m), 1); for (i = 0; i < octets; ++i) { byte2vector_offset(vec, bytes[i], i * 8); } prod = mul_matrices(NULL, m, vec); for (i = 0; i < octets; ++i) { vector2byte_offset(&result[i], prod, i * 8); } free_matrix(vec); free_matrix(prod); return 0; }
/* * INPUT * verbose : if non-zero, print results * OUTPUT * (returned value) : 0 => passed * otherwise => failed */ int check_lapack_inv_ (int n, int verbose, double tiny) { if (verbose != 0) { fprintf (stdout, "==================================================\n" "check_lapack_inv_(n=%d) : start\n", n); } int check = 0; double max = 0.0; double *a = (double *)malloc (sizeof (double) * n * n); double *a_ = (double *)malloc (sizeof (double) * n * n); double *b = (double *)malloc (sizeof (double) * n * n); CHECK_MALLOC (a, "check_lapack_inv_"); CHECK_MALLOC (a_, "check_lapack_inv_"); CHECK_MALLOC (b, "check_lapack_inv_"); int i; srand48 (0); for (i = 0; i < n * n; i ++) { a [i] = drand48(); a_[i] = a [i]; } // a = a^-1 lapack_inv_ (n, a); // b = a^-1 . a mul_matrices (a, n, n, a_, n, n, b); /* int j, k; for (i = 0; i < n; i ++) { for (j = 0; j < n; j ++) { b[i*n+j] = 0.0; for (k = 0; k < n; k ++) { b[i*n+j] += a[i*n+k] * a_[k*n+j]; } } } */ char label[80]; double d; for (i = 0; i < n; i ++) { int j; for (j = 0; j < n; j ++) { if (i == j) d = fabs (b [i*n+j] - 1.0); else d = fabs (b [i*n+j]); sprintf (label, "check_lapack_inv_ : [%d]", i); check += compare_max (d+1.0, 1.0, label, verbose, tiny, &max); } } free (a); free (a_); free (b); if (verbose != 0) { fprintf (stdout, " max error = %e vs tiny = %e\n", max, tiny); if (check == 0) fprintf (stdout, " => PASSED\n\n"); else fprintf (stdout, " => FAILED\n\n"); } return (check); }
/** * @detail * All variables are named as in the fore mentioned paper * 1. Use a row of blocks of Matrix M to create a matrix X * 2. Use a column of blocks of Matrix M to create a matrix Y * 3. Get invertible matrices P and Q such that P(X.Minv.Y)Q = [I 0] * (I is of r dimension; 0 is of 2-r dimension; 0 < r < 3) * 4. Define matrix A as follows: * a) if r = 0 then A = I * b) if r = 1 then A = [[1 1] [1 0]] * c) if r = 2 then A = [[0 1] [1 1]] * 5. Then the following is a (t+2, 2) block invertible matrix: * | M Y | * | X X.Minv.Y + Pinv.A.Qinv | */ static gf2matrix *extend_block_invertible_by2(const gf2matrix *m) { gf2matrix *result = NULL; gf2matrix *x = NULL, *y = NULL; int multiples = get_rows(m) / 2; int x_start = get_random(0, multiples - 1) * 2; int y_start = get_random(0, multiples - 1) * 2; if (!m) { gf2matrix *_2x2; get_2x2invertible_pair(get_random(0, MAX_2X2_INVERTIBLES - 1), &_2x2, NULL); result = dup_matrix(_2x2); return result; } /* print_matrix(m, "Extending m by 2:"); */ /* step 1 */ x = extract_block_row(NULL, x_start, m); assert(x); /* print_matrix(x, "X:"); */ /* step 2 */ y = extract_block_col(NULL, y_start, m); assert(y); /* print_matrix(y, "Y:"); */ { /* steps 3, 4, 5 */ int r; /* r is the rank of X.Minv.Y */ gf2matrix *i0mat = new_matrix(2, 2); gf2matrix *prod = new_matrix(2, 2); gf2matrix *temp = NULL; gf2matrix *mInv = invert_matrix(NULL, m); gf2matrix *xminvy = NULL; gf2matrix *a2 = NULL; { assert(mInv); /* calculate X.Minv.Y */ gf2matrix *minvy = mul_matrices(NULL, mInv, y); xminvy = mul_matrices(NULL, x, minvy); assert(xminvy); free_matrix(minvy); } /* print_matrix(xminvy, "xM-1y: "); */ r = calc_rank(xminvy); /* printf("rank of X.Minv.Y = %d\n", r); */ init_IO_matrix(i0mat, r); /* print_matrix(i0mat, "I0:"); */ a2 = make_A2_matrix(r); temp = new_matrix(2, 2); while (!result) { int i, j, i_tries, j_tries; for (i = get_random(0, MAX_2X2_INVERTIBLES - 1), i_tries = 0; i_tries < MAX_2X2_INVERTIBLES && !result; i = (i + 1) % MAX_2X2_INVERTIBLES, ++i_tries) { gf2matrix *q, *qinv; get_2x2invertible_pair(i, &q, &qinv); /* print_matrix(q, "Q:"); */ mul_matrices(temp, xminvy, q); assert(temp); for (j = get_random(0, MAX_2X2_INVERTIBLES - 1), j_tries = 0; j_tries < MAX_2X2_INVERTIBLES && !result; j = (j + 1) % MAX_2X2_INVERTIBLES, ++j_tries) { gf2matrix *p, *pinv; get_2x2invertible_pair(j, &p, &pinv); mul_matrices(prod, p, temp); assert(prod); /* print_matrix(p, "P:"); */ /* print_matrix(prod, "P.X.Minv.Y.Q:"); */ if (comp_matrices(prod, i0mat) == 0) { /* step 5 */ result = extend_by_blocks(m, x, y, xminvy, pinv, a2, qinv); assert(result); break; } } } } free_matrix(a2); free_matrix(xminvy); free_matrix(mInv); free_matrix(prod); free_matrix(temp); free_matrix(i0mat); if (!result) printf("incorrect matrix expansion algorithm"); } cleanup: free_matrix(y); free_matrix(x); return result; }
/* solve natural mobility problem with lubrication * with fixed particles in FT version * for both periodic and non-periodic boundary conditions * INPUT * sys : system parameters * f [nm * 3] : * t [nm * 3] : * uf [nf * 3] : * of [nf * 3] : * OUTPUT * u [nm * 3] : * o [nm * 3] : * ff [nf * 3] : * tf [nf * 3] : */ void solve_mix_lub_3ft_matrix (struct stokes * sys, const double *f, const double *t, const double *uf, const double *of, double *u, double *o, double *ff, double *tf) { if (sys->version != 1) { fprintf (stderr, "libstokes solve_mix_lub_3ft_matrix :" " the version is wrong. reset to FT\n"); sys->version = 1; } int np = sys->np; int nm = sys->nm; if (np == nm) { solve_mob_lub_3ft_matrix (sys, f, t, u, o); return; } int n6 = np * 6; int nf = np - nm; int nm6 = nm * 6; int nl = nm * 6; int nh = n6 - nl; double *uf0 = (double *) malloc (sizeof (double) * nf * 3); double *of0 = (double *) malloc (sizeof (double) * nf * 3); double *mat = (double *) malloc (sizeof (double) * n6 * n6); double *lub = (double *) malloc (sizeof (double) * n6 * n6); double *tmp = (double *) malloc (sizeof (double) * n6 * n6); double *mat_ll = (double *) malloc (sizeof (double) * nl * nl); double *mat_lh = (double *) malloc (sizeof (double) * nl * nh); double *mat_hl = (double *) malloc (sizeof (double) * nh * nl); double *mat_hh = (double *) malloc (sizeof (double) * nh * nh); double *mob_ll = (double *) malloc (sizeof (double) * nl * nl); double *mob_lh = (double *) malloc (sizeof (double) * nl * nh); double *mob_hl = (double *) malloc (sizeof (double) * nh * nl); double *mob_hh = (double *) malloc (sizeof (double) * nh * nh); double *b = (double *) malloc (sizeof (double) * n6); double *x = (double *) malloc (sizeof (double) * n6); CHECK_MALLOC (uf0, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (of0, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (mat, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (lub, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (tmp, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (mat_ll, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (mat_lh, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (mat_hl, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (mat_hh, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (mob_ll, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (mob_lh, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (mob_hl, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (mob_hh, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (b, "solve_mix_lub_3ft_matrix"); CHECK_MALLOC (x, "solve_mix_lub_3ft_matrix"); shift_labo_to_rest_U (sys, nf, uf, uf0); shift_labo_to_rest_O (sys, nf, of, of0); /* the main calculation is done in the the fluid-rest frame; * u(x)=0 as |x|-> infty */ /* b := (FT,UfOf) */ set_ft_by_FT (nm, b, f, t); set_ft_by_FT (nf, b + nm6, uf0, of0); free (uf0); free (of0); /* mob */ make_matrix_mob_3all (sys, mat); // sys->version is 1 (FT) split_matrix_fix_3ft (np, nm, mat, mat_ll, mat_lh, mat_hl, mat_hh); /* lub */ make_matrix_lub_3ft (sys, lub); /* tmp := M.L */ mul_matrices (mat, n6, n6, lub, n6, n6, tmp); /* note: at this point, lub[] is free to use. * so that I_?? use lub [] */ double *I_ll = lub; double *I_lh = I_ll + nl * nl; double *I_hl = I_lh + nl * nh; double *I_hh = I_hl + nh * nl; /* tmp := I + (M.T).(L.T) */ int i; for (i = 0; i < n6; ++i) { tmp [i * n6 + i] += 1.0; } split_matrix_fix_3ft (np, nm, tmp, I_ll, I_lh, I_hl, I_hh); free (tmp); solve_gen_linear (nl, nh, I_ll, I_lh, I_hl, I_hh, mat_ll, mat_lh, mat_hl, mat_hh, mob_ll, mob_lh, mob_hl, mob_hh); /* note: at this point, I_??, therefore lub[], is free to use. */ free (lub); merge_matrix_fix_3ft (np, nm, mob_ll, mob_lh, mob_hl, mob_hh, mat); dot_prod_matrix (mat, n6, n6, b, x); set_FT_by_ft (nm, u, o, x); set_FT_by_ft (nf, ff, tf, x + nm6); free (mat); free (mat_ll); free (mat_lh); free (mat_hl); free (mat_hh); free (mob_ll); free (mob_lh); free (mob_hl); free (mob_hh); free (b); free (x); /* for the interface, we are in the labo frame, that is * u(x) is given by the imposed flow field as |x|-> infty */ shift_rest_to_labo_U (sys, nm, u); shift_rest_to_labo_O (sys, nm, o); }
/* solve natural mobility problem in FT version * for both periodic and non-periodic boundary conditions * INPUT * sys : system parameters * f [np * 3] : * t [np * 3] : * OUTPUT * u [np * 3] : * o [np * 3] : */ void solve_mob_lub_3ft_matrix (struct stokes * sys, const double *f, const double *t, double *u, double *o) { if (sys->version != 1) { fprintf (stderr, "libstokes solve_mob_lub_3ft_matrix :" " the version is wrong. reset to FT\n"); sys->version = 1; } int np = sys->np; int n6 = np * 6; double *mat = (double *) malloc (sizeof (double) * n6 * n6); double *lub = (double *) malloc (sizeof (double) * n6 * n6); double *iml = (double *) malloc (sizeof (double) * n6 * n6); double *b = (double *) malloc (sizeof (double) * n6); double *x = (double *) malloc (sizeof (double) * n6); CHECK_MALLOC (mat, "solve_mob_lub_3ft_matrix"); CHECK_MALLOC (lub, "solve_mob_lub_3ft_matrix"); CHECK_MALLOC (iml, "solve_mob_lub_3ft_matrix"); CHECK_MALLOC (b, "solve_mob_lub_3ft_matrix"); CHECK_MALLOC (x, "solve_mob_lub_3ft_matrix"); /* the main calculation is done in the the fluid-rest frame; * u(x)=0 as |x|-> infty */ // M make_matrix_mob_3all (sys, mat); // sys->version is 1 (FT) // L make_matrix_lub_3ft (sys, lub); // IML := M.L mul_matrices (mat, n6, n6, lub, n6, n6, iml); free (lub); /* b := (FT) */ set_ft_by_FT (np, b, f, t); // x := M.(FT) dot_prod_matrix (mat, n6, n6, b, x); // IML = I + M.L int i; for (i = 0; i < n6; ++i) { iml [i * n6 + i] += 1.0; } // b := (I+M.L)^-1.M.(FT) /* // IML^-1 lapack_inv_ (n6, iml); dot_prod_matrix (iml, n6, n6, x, b); */ lapack_solve_lin (n6, iml, x, b); set_FT_by_ft (np, u, o, b); free (mat); free (iml); free (b); free (x); /* for the interface, we are in the labo frame, that is * u(x) is given by the imposed flow field as |x|-> infty */ shift_rest_to_labo_U (sys, sys->np, u); shift_rest_to_labo_O (sys, sys->np, o); }