PIPS
smith.c
Go to the documentation of this file.
1 /*
2 
3  $Id: smith.c 1669 2019-06-26 17:24:57Z coelho $
4 
5  Copyright 1989-2016 MINES ParisTech
6 
7  This file is part of Linear/C3 Library.
8 
9  Linear/C3 Library is free software: you can redistribute it and/or modify it
10  under the terms of the GNU Lesser General Public License as published by
11  the Free Software Foundation, either version 3 of the License, or
12  any later version.
13 
14  Linear/C3 Library is distributed in the hope that it will be useful, but WITHOUT ANY
15  WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  FITNESS FOR A PARTICULAR PURPOSE.
17 
18  See the GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with Linear/C3 Library. If not, see <http://www.gnu.org/licenses/>.
22 
23 */
24 
25  /* package matrix */
26 
27 #ifdef HAVE_CONFIG_H
28  #include "config.h"
29 #endif
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stdlib.h>
34 
35 #include "linear_assert.h"
36 
37 #include "boolean.h"
38 #include "arithmetique.h"
39 
40 #include "matrix.h"
41 
42 #define MALLOC(s,t,f) malloc((unsigned)(s))
43 #define FREE(s,t,f) free((char *)(s))
44 
45 /* void matrix_smith(matrice MAT, matrix P, matrix D,
46  * matrix Q):
47  * Calcul de la forme reduite de Smith D d'une matrice entiere MAT et des deux
48  * matrices de changement de base unimodulaires associees, P et Q.
49  *
50  * D est la forme reduite de Smith, P et Q sont des matrices unimodulaires;
51  * telles que D == P x MAT x Q
52  *
53  * (c.f. Programmation Lineaire. M.MINOUX. (83))
54  *
55  * int MAT[n,m] : matrice
56  * int n : nombre de lignes de la matrice MAT
57  * int m : nombre de colonnes de la matrice MAT
58  * int P[n,n] : matrice
59  * int D[n,m] : matrice (quasi-diagonale) reduite de Smith
60  * int Q[m,m] : matrice
61  *
62  * Les 3 matrices P(nxn), Q(mxm) et D(nxm) doivent etre allouees avant le
63  * calcul.
64  *
65  * Note: les determinants des matrices MAT, P, Q et D ne sont pas utilises.
66  *
67  */
68 void matrix_smith(MAT,P,D,Q)
69 Pmatrix MAT;
70 Pmatrix P;
71 Pmatrix D;
72 Pmatrix Q;
73 {
74  int n_min,m_min;
75  int level = 0;
76  Value ALL; /* le plus petit element sur la diagonale */
77  Value x=VALUE_ZERO; /* le rest de la division par ALL */
78  int i;
79 
80  bool stop = false;
81  bool next = true;
82 
83  /* precondition sur les parametres */
84  int n = MATRIX_NB_LINES(MAT);
85  int m = MATRIX_NB_COLUMNS(MAT);
86  assert(m > 0 && n >0);
87  matrix_assign(MAT,D);
89 
90  matrix_identity(P,0);
91  matrix_identity(Q,0);
92 
93  while (!stop) {
94  matrix_min(D,&n_min,&m_min,level);
95 
96  if ((n_min == 0) && (m_min == 0))
97  stop = true;
98  else {
99  /* le transformation n'est pas fini. */
100  if (n_min > level +1) {
101  matrix_swap_rows(D,level+1,n_min);
102  matrix_swap_rows(P,level+1,n_min);
103  }
104 #ifdef TRACE
105  (void) printf (" apres alignement du plus petit element a la premiere ligne \n");
106  matrix_print(D);
107 #endif
108  if (m_min >1+level) {
109  matrix_swap_columns(D,level+1,m_min);
110  matrix_swap_columns(Q,level+1,m_min);
111  }
112 #ifdef TRACE
113  (void) printf (" apres alignement du plus petit element a la premiere colonne\n");
114  matrix_print(D);
115 #endif
116 
117  ALL = SUB_MATRIX_ELEM(D,1,1,level);
118  if (matrix_line_el(D,level) != 0)
119  for (i=level+2; i<=m; i++) {
120  x = value_div(MATRIX_ELEM(D,level+1,i),ALL);
123  next = false;
124  }
125  if (matrix_col_el(D,level) != 0)
126  for(i=level+2;i<=n;i++) {
127  x = value_div(MATRIX_ELEM(D,i,level+1),ALL);
130  next = false;
131  }
132 #ifdef TRACE
133  (void) printf("apres division par A(%d,%d) des termes de la %d-ieme ligne et de la %d-em colonne \n",level+1,level+1,level+1,level+1);
134  matrix_print(D);
135 #endif
136  if (next) level++;
137  next = true;
138  }
139  }
140 
141 #ifdef TRACE
142  (void) printf (" la matrice D apres transformation est la suivante :");
143  matrix_print(D);
144 
145  (void) printf (" la matrice P est \n");
146  matrix_print(P);
147 
148  (void) printf (" la matrice Q est \n");
149  matrix_print(Q);
150 #endif
151 }
152 
153 /* Under the assumption A x = B, A[n,m] and B[n], compute the 1-D
154  * lattice for x_i of x[m] as
155  *
156  * x_i = gcd_i lambda + c_i
157  *
158  * derived from the parametric solution of the system :
159  *
160  * x_i = sum_{k<j<=m} q_{i,j} lambda_j + sum_{1<=j,=k} q_{i,j} y_c_{j}
161  *
162  * where k is the rank of matrix A (0<=k<=n, k<=m), lambda_j are the
163  * free variables and y_c is the solution of the equations. This leads
164  * to:
165  *
166  * gcd_i = sum_{k<j<=m} q_{i,j} and c_i = sum_{1<=j,=k} q_{i,j} y_c_{j}
167  *
168  * when the system has a least one solution.
169  *
170  * To compute Q and y_c, We use D[n,m], the Smith form of A, with D =
171  * P A Q and P[n,n] and Q[m,m] unimodular
172  *
173  * inv(P) D inv(Q) x = b
174  *
175  * inv(P) D y = b => D y = P b => some components of y[m] are constants, y_c[m]
176  *
177  * y_c = D'{-1} P b, where D'[min(n,m),min(n,m)] is the top left
178  * submatrix of D[n,m]
179  *
180  * y = inv(Q) x => x = Q (y_c[1..k],y[k+1..m])
181  *
182  * where (a,b) represents s the concatenation of vectors a and b, and
183  * k<=min(n,m) the .
184  *
185  * c_i = sum_j Q_{i,j} y_c_{j}
186  *
187  * gcd = gcd_{j s.t. yc_j = 0} Q_{i,j}
188  *
189  * Return false if the system Ax=b has no solution
190  *
191  * This implements a partial parametric resolution of A x = B. It
192  * might be better from an engineering viewpoint to solve the system
193  * fully and then to exploit the equation for x_i.
194  */
195 int matrices_to_1D_lattice(Pmatrix A, Pmatrix B, int n, int m, int i, Value * gcd_p, Value * c_p)
196 {
197  // The number of equations is smaller than the number of variables
198  // Not necessarily because you may have redundant equations
199  // assert(n<=m);
200  int success = 1;
201  Pmatrix P, D, Q;
202  P = matrix_new(n,n);
203  D = matrix_new(n,m);
204  Q = matrix_new(m,m);
205  matrix_smith(A,P,D,Q);
206 
207  // Compute P b
208 
209  Pmatrix Pb = matrix_new(n, 1);
210  matrix_multiply(P, B, Pb);
211 
212  // Compute yc by solving D yc = P b
213 
214  Pmatrix yc = matrix_new(m, 1);
215  int j;
216  for(j=1; j <= m; j++)
217  MATRIX_ELEM(yc, j, 1) = VALUE_ZERO;
218  // FI: it might be sufficient to check the pseudo-diagonal element Dii
219  int k = 0;
220  for(j=1; j <= n && j <= m; j++) {
221  Value Pbj = MATRIX_ELEM(Pb, j, 1);
222  if(!value_zero_p(Pbj)) {
223  Value Djj = MATRIX_ELEM(D, j, j);
224  if(!value_zero_p(Djj)) {
225  Value r = modulo(Pbj, Djj);
226  if(value_zero_p(r))
227  MATRIX_ELEM(yc, j, 1) = DIVIDE(Pbj, Djj), k=j;
228  else
229  success = false;
230  }
231  }
232  }
233  for(j=k+1; j <= n; j++) {
234  Value Pbj = MATRIX_ELEM(Pb, j, 1);
235  if(!value_zero_p(Pbj)) {
236  success = false;
237  }
238  }
239 
240  // If the system has parametric solutions
241 
242  if(success) {
243  // k = MIN(n,m);
244  // Compute the constant term "c_i"
245  *c_p = VALUE_ZERO;
246  for(j=1; j <= k; j++) {
247  *c_p += value_mult(MATRIX_ELEM(Q, i, j), MATRIX_ELEM(yc, j, 1));
248  }
249 
250  // and the gcd "gcd_i" with x = Q yc
251  *gcd_p = VALUE_ZERO;
252  for(j=k+1; j <= m; j++) {
253  if(value_zero_p(*gcd_p))
254  *gcd_p = MATRIX_ELEM(Q, i, j);
255  else if(!value_zero_p(MATRIX_ELEM(Q, i, j)))
256  *gcd_p = pgcd(*gcd_p, MATRIX_ELEM(Q, i, j));
257  }
258 
259  // With no information at all, the gcd default value is one
260  if(value_zero_p(*gcd_p))
261  *gcd_p = VALUE_ONE;
262  *c_p = modulo(*c_p, *gcd_p);
263  }
264  free(P);
265  free(Pb);
266  free(D);
267  free(Q);
268  free(yc);
269  return success;
270 }
#define VALUE_ZERO
#define modulo(a, b)
#define DIVIDE(x, y)
division avec reste toujours positif basee sur les equations: a/(-b) = - (a/b) (-a)/b = - ((a+b-1)/b)...
#define pgcd(a, b)
Pour la recherche de performance, selection d'une implementation particuliere des fonctions.
#define value_one_p(val)
#define value_zero_p(val)
int Value
#define VALUE_ONE
#define value_mult(v, w)
whether the default is protected or not this define makes no sense any more...
#define value_div(v1, v2)
void free(void *)
bool success
Definition: gpips-local.h:59
#define B(A)
Definition: iabrev.h:61
#define D(A)
Definition: iabrev.h:56
#define SUB_MATRIX_ELEM(matrix, i, j, level)
MATRIX_RIGHT_INF_ELEM Permet d'acceder des sous-matrices dont le coin infe'rieur droit (i....
Definition: matrix-local.h:106
#define MATRIX_NB_LINES(matrix)
Definition: matrix-local.h:87
#define MATRIX_NB_COLUMNS(matrix)
Definition: matrix-local.h:88
#define MATRIX_DENOMINATOR(matrix)
int MATRIX_DENONIMATOR(matrix): acces au denominateur global d'une matrice matrix
Definition: matrix-local.h:86
#define MATRIX_ELEM(matrix, i, j)
Macros d'acces aux elements d'une matrice.
Definition: matrix-local.h:80
Pmatrix matrix_new(int m, int n)
package matrix
Definition: alloc.c:41
int matrices_to_1D_lattice(Pmatrix A, Pmatrix B, int n, int m, int i, Value *gcd_p, Value *c_p)
Under the assumption A x = B, A[n,m] and B[n], compute the 1-D lattice for x_i of x[m] as.
Definition: smith.c:195
void matrix_smith(Pmatrix MAT, Pmatrix P, Pmatrix D, Pmatrix Q)
void matrix_smith(matrice MAT, matrix P, matrix D, matrix Q): Calcul de la forme reduite de Smith D d...
Definition: smith.c:68
void matrix_swap_rows(Pmatrix A, int r1, int r2)
void matrix_swap_rows(Pmatrix a, int r1, int r2): exchange rows r1 and r2 of an (nxm) rational matrix...
Definition: matrix.c:230
void matrix_swap_columns(Pmatrix A, int c1, int c2)
void matrix_swap_columns(Pmatrix a, int c1, int c2): exchange columns c1,c2 of an (nxm) rational matr...
Definition: matrix.c:209
void matrix_subtraction_column(Pmatrix MAT, int c1, int c2, Value x)
void matrix_subtraction_column(Pmatrix MAT,int c1,int c2,int x): Soustrait x fois la colonne c2 de la...
Definition: matrix.c:518
void matrix_multiply(const Pmatrix a, const Pmatrix b, Pmatrix c)
void matrix_multiply(Pmatrix a, Pmatrix b, Pmatrix c): multiply rational matrix a by rational matrix ...
Definition: matrix.c:95
void matrix_assign(Pmatrix A, Pmatrix B)
void matrix_assign(Pmatrix A, Pmatrix B) Copie de la matrice A dans la matrice B
Definition: matrix.c:259
void matrix_subtraction_line(Pmatrix MAT, int r1, int r2, Value x)
void matrix_subtraction_line(Pmatrix MAT,int r1,int r2,int x): Soustrait x fois la ligne r2 de la lig...
Definition: matrix.c:541
void matrix_print(Pmatrix)
void matrix_print(matrice a): print an (nxm) rational matrix
Definition: matrix_io.c:70
int matrix_line_el(Pmatrix, int)
int matrix_line_el(Pmatrix MAT, int level) renvoie le numero de colonne absolu du premier element non...
Definition: sub-matrix.c:379
void matrix_identity(Pmatrix, int)
void matrix_identity(Pmatrix ID, int level) Construction d'une sous-matrice identity dans ID(level+1....
Definition: sub-matrix.c:322
int matrix_col_el(Pmatrix, int)
int matrix_col_el(Pmatrix MAT, int level) renvoie le numero de ligne absolu du premier element non nu...
Definition: sub-matrix.c:401
void matrix_min(Pmatrix, int *, int *, int)
void matrix_min(Pmatrix MAT, int * i_min, int * j_min, int level): Recherche des coordonnees (*i_min,...
Definition: sub-matrix.c:196
#define assert(ex)
Definition: newgen_assert.h:41
#define Q
Definition: pip__type.h:39
#define ALL
Definition: readmakefile.c:178
#define level
int printf()
static char * x
Definition: split_file.c:159
Definition: pip__tab.h:25
package matrice
Definition: matrix-local.h:63