1 /* Tests matrix22_mul.
2
3 Copyright 2008 Free Software Foundation, Inc.
4
5 This file is part of the GNU MP Library test suite.
6
7 The GNU MP Library test suite is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 3 of the License,
10 or (at your option) any later version.
11
12 The GNU MP Library test suite is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 Public License for more details.
16
17 You should have received a copy of the GNU General Public License along with
18 the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22
23 #include "gmp-impl.h"
24 #include "tests.h"
25
26 struct matrix {
27 mp_size_t alloc;
28 mp_size_t n;
29 mp_ptr e00, e01, e10, e11;
30 };
31
32 static void
matrix_init(struct matrix * M,mp_size_t n)33 matrix_init (struct matrix *M, mp_size_t n)
34 {
35 mp_ptr p = refmpn_malloc_limbs (4*(n+1));
36 M->e00 = p; p += n+1;
37 M->e01 = p; p += n+1;
38 M->e10 = p; p += n+1;
39 M->e11 = p;
40 M->alloc = n + 1;
41 M->n = 0;
42 }
43
44 static void
matrix_clear(struct matrix * M)45 matrix_clear (struct matrix *M)
46 {
47 refmpn_free_limbs (M->e00);
48 }
49
50 static void
matrix_copy(struct matrix * R,const struct matrix * M)51 matrix_copy (struct matrix *R, const struct matrix *M)
52 {
53 R->n = M->n;
54 MPN_COPY (R->e00, M->e00, M->n);
55 MPN_COPY (R->e01, M->e01, M->n);
56 MPN_COPY (R->e10, M->e10, M->n);
57 MPN_COPY (R->e11, M->e11, M->n);
58 }
59
60 /* Used with same size, so no need for normalization. */
61 static int
matrix_equal_p(const struct matrix * A,const struct matrix * B)62 matrix_equal_p (const struct matrix *A, const struct matrix *B)
63 {
64 return (A->n == B->n
65 && mpn_cmp (A->e00, B->e00, A->n) == 0
66 && mpn_cmp (A->e01, B->e01, A->n) == 0
67 && mpn_cmp (A->e10, B->e10, A->n) == 0
68 && mpn_cmp (A->e11, B->e11, A->n) == 0);
69 }
70
71 static void
matrix_random(struct matrix * M,mp_size_t n,gmp_randstate_ptr rands)72 matrix_random(struct matrix *M, mp_size_t n, gmp_randstate_ptr rands)
73 {
74 M->n = n;
75 mpn_random (M->e00, n);
76 mpn_random (M->e01, n);
77 mpn_random (M->e10, n);
78 mpn_random (M->e11, n);
79 }
80
81 #define MUL(rp, ap, an, bp, bn) do { \
82 if (an > bn) \
83 mpn_mul (rp, ap, an, bp, bn); \
84 else \
85 mpn_mul (rp, bp, bn, ap, an); \
86 } while(0)
87
88 static void
ref_matrix22_mul(struct matrix * R,const struct matrix * A,const struct matrix * B,mp_ptr tp)89 ref_matrix22_mul (struct matrix *R,
90 const struct matrix *A,
91 const struct matrix *B, mp_ptr tp)
92 {
93 mp_size_t an, bn, n;
94 mp_ptr r00, r01, r10, r11, a00, a01, a10, a11, b00, b01, b10, b11;
95
96 if (A->n >= B->n)
97 {
98 r00 = R->e00; a00 = A->e00; b00 = B->e00;
99 r01 = R->e01; a01 = A->e01; b01 = B->e01;
100 r10 = R->e10; a10 = A->e10; b10 = B->e10;
101 r11 = R->e11; a11 = A->e11; b11 = B->e11;
102 an = A->n, bn = B->n;
103 }
104 else
105 {
106 /* Transpose */
107 r00 = R->e00; a00 = B->e00; b00 = A->e00;
108 r01 = R->e10; a01 = B->e10; b01 = A->e10;
109 r10 = R->e01; a10 = B->e01; b10 = A->e01;
110 r11 = R->e11; a11 = B->e11; b11 = A->e11;
111 an = B->n, bn = A->n;
112 }
113 n = an + bn;
114 R->n = n + 1;
115
116 mpn_mul (r00, a00, an, b00, bn);
117 mpn_mul (tp, a01, an, b10, bn);
118 r00[n] = mpn_add_n (r00, r00, tp, n);
119
120 mpn_mul (r01, a00, an, b01, bn);
121 mpn_mul (tp, a01, an, b11, bn);
122 r01[n] = mpn_add_n (r01, r01, tp, n);
123
124 mpn_mul (r10, a10, an, b00, bn);
125 mpn_mul (tp, a11, an, b10, bn);
126 r10[n] = mpn_add_n (r10, r10, tp, n);
127
128 mpn_mul (r11, a10, an, b01, bn);
129 mpn_mul (tp, a11, an, b11, bn);
130 r11[n] = mpn_add_n (r11, r11, tp, n);
131 }
132
133 static void
one_test(const struct matrix * A,const struct matrix * B,int i)134 one_test (const struct matrix *A, const struct matrix *B, int i)
135 {
136 struct matrix R;
137 struct matrix P;
138 mp_ptr tp;
139
140 matrix_init (&R, A->n + B->n + 1);
141 matrix_init (&P, A->n + B->n + 1);
142
143 tp = refmpn_malloc_limbs (mpn_matrix22_mul_itch (A->n, B->n));
144
145 ref_matrix22_mul (&R, A, B, tp);
146 matrix_copy (&P, A);
147 mpn_matrix22_mul (P.e00, P.e01, P.e10, P.e11, A->n,
148 B->e00, B->e01, B->e10, B->e11, B->n, tp);
149 P.n = A->n + B->n + 1;
150 if (!matrix_equal_p (&R, &P))
151 {
152 fprintf (stderr, "ERROR in test %d\n", i);
153 gmp_fprintf (stderr, "A = (%Nx, %Nx\n %Nx, %Nx)\n"
154 "B = (%Nx, %Nx\n %Nx, %Nx)\n"
155 "R = (%Nx, %Nx (expected)\n %Nx, %Nx)\n"
156 "P = (%Nx, %Nx (incorrect)\n %Nx, %Nx)\n",
157 A->e00, A->n, A->e01, A->n, A->e10, A->n, A->e11, A->n,
158 B->e00, B->n, B->e01, B->n, B->e10, B->n, B->e11, B->n,
159 R.e00, R.n, R.e01, R.n, R.e10, R.n, R.e11, R.n,
160 P.e00, P.n, P.e01, P.n, P.e10, P.n, P.e11, P.n);
161 abort();
162 }
163 refmpn_free_limbs (tp);
164 matrix_clear (&R);
165 matrix_clear (&P);
166 }
167
168 #define MAX_SIZE (2+2*MATRIX22_STRASSEN_THRESHOLD)
169
170 int
main(int argc,char ** argv)171 main (int argc, char **argv)
172 {
173 struct matrix A;
174 struct matrix B;
175
176 gmp_randstate_ptr rands;
177 mpz_t bs;
178 int i;
179
180 tests_start ();
181 rands = RANDS;
182
183 matrix_init (&A, MAX_SIZE);
184 matrix_init (&B, MAX_SIZE);
185 mpz_init (bs);
186
187 for (i = 0; i < 1000; i++)
188 {
189 mp_size_t an, bn;
190 mpz_urandomb (bs, rands, 32);
191 an = 1 + mpz_get_ui (bs) % MAX_SIZE;
192 mpz_urandomb (bs, rands, 32);
193 bn = 1 + mpz_get_ui (bs) % MAX_SIZE;
194
195 matrix_random (&A, an, rands);
196 matrix_random (&B, bn, rands);
197
198 one_test (&A, &B, i);
199 }
200 mpz_clear (bs);
201 matrix_clear (&A);
202 matrix_clear (&B);
203
204 tests_end ();
205 return 0;
206 }
207