1 /*
2  * This file is part of MPSolve 3.2.1
3  *
4  * Copyright (C) 2001-2020, Dipartimento di Matematica "L. Tonelli", Pisa.
5  * License: http://www.gnu.org/licenses/gpl.html GPL version 3 or higher
6  *
7  * Authors:
8  *   Leonardo Robol <leonardo.robol@unipi.it>
9  */
10 
11 #include <mps/mps.h>
12 #include <string.h>
13 
14 mps_monomial_matrix_poly*
mps_monomial_matrix_poly_new(mps_context * ctx,int degree,int m,mps_boolean monic)15 mps_monomial_matrix_poly_new (mps_context * ctx, int degree, int m, mps_boolean monic)
16 {
17   mps_monomial_matrix_poly * poly = mps_new (mps_monomial_matrix_poly);
18 
19   MPS_POLYNOMIAL (poly)->degree = degree * m;
20   mps_polynomial_init (ctx, MPS_POLYNOMIAL (poly));
21 
22   /* Matrix polynomial specific fields */
23   poly->monic = monic;
24   poly->m = m;
25   poly->degree = degree;
26 
27   /* Allocation of the necessary memory to hold all the matrices. */
28   poly->P = mps_newv (cplx_t, poly->m * poly->m * (degree + 1));
29   poly->mP = mps_newv (mpc_t, poly->m * poly->m * (degree + 1));
30   poly->mpqPr = mps_newv (mpq_t, poly->m * poly->m * (degree + 1));
31   poly->mpqPi = mps_newv (mpq_t, poly->m * poly->m * (degree + 1));
32 
33   mpc_vinit2 (poly->mP, poly->m * poly->m * (degree + 1), ctx->mpwp);
34   mpq_vinit (poly->mpqPr, poly->m * poly->m * (degree + 1));
35   mpq_vinit (poly->mpqPi, poly->m * poly->m * (degree + 1));
36 
37   MPS_POLYNOMIAL (poly)->type_name = "mps_monomial_matrix_poly";
38   MPS_POLYNOMIAL (poly)->thread_safe = false;
39 
40   MPS_POLYNOMIAL (poly)->structure = MPS_STRUCTURE_UNKNOWN;
41 
42   /* Setup the overloaded methods for our matrix polynomial */
43   MPS_POLYNOMIAL (poly)->free = mps_monomial_matrix_poly_free;
44   MPS_POLYNOMIAL (poly)->raise_data = mps_monomial_matrix_poly_raise_data;
45   MPS_POLYNOMIAL (poly)->meval = mps_monomial_matrix_poly_meval;
46 
47   return poly;
48 }
49 
50 void
mps_monomial_matrix_poly_free(mps_context * ctx,mps_polynomial * poly)51 mps_monomial_matrix_poly_free (mps_context * ctx, mps_polynomial * poly)
52 {
53   mps_monomial_matrix_poly * mpoly = MPS_MONOMIAL_MATRIX_POLY (poly);
54 
55   free (mpoly->P);
56 
57   mpc_vclear (mpoly->mP, mpoly->m * (poly->degree + mpoly->m));
58   free (mpoly->mP);
59 
60   mpq_vclear (mpoly->mpqPr, mpoly->m * (poly->degree + mpoly->m));
61   free (mpoly->mpqPr);
62 
63   mpq_vclear (mpoly->mpqPi, mpoly->m * (poly->degree + mpoly->m));
64   free (mpoly->mpqPi);
65 
66   free (poly);
67 }
68 
mps_monomial_matrix_poly_add_flags(mps_context * ctx,mps_monomial_matrix_poly * mpoly,int flags)69 void mps_monomial_matrix_poly_add_flags (mps_context * ctx,
70                                          mps_monomial_matrix_poly * mpoly,
71                                          int flags)
72 {
73   mpoly->flags |= flags;
74 }
75 
76 
mps_monomial_matrix_poly_clear_flags(mps_context * ctx,mps_monomial_matrix_poly * mpoly,int flags)77 void mps_monomial_matrix_poly_clear_flags (mps_context * ctx,
78                                            mps_monomial_matrix_poly * mpoly,
79                                            int flags)
80 {
81   mpoly->flags &= ~flags;
82 }
83 
84 
85 void
mps_monomial_matrix_poly_set_coefficient_d(mps_context * ctx,mps_monomial_matrix_poly * mpoly,int i,cplx_t * matrix)86 mps_monomial_matrix_poly_set_coefficient_d (mps_context * ctx,
87                                             mps_monomial_matrix_poly *mpoly,
88                                             int i,
89                                             cplx_t * matrix)
90 {
91   mps_polynomial *poly = MPS_POLYNOMIAL (mpoly);
92   int degree = poly->degree;
93   int j;
94 
95   if (i < 0 || i > degree)
96     {
97       mps_error (ctx, "Degree of the coefficient is out of bounds");
98       return;
99     }
100 
101   if (poly->structure == MPS_STRUCTURE_UNKNOWN)
102     {
103       poly->structure = MPS_STRUCTURE_REAL_FP;
104     }
105   else if (!MPS_STRUCTURE_IS_FP (poly->structure))
106     {
107       mps_error (ctx, "Cannot assign floating point coefficients to a non-floating-point polynomial.");
108       return;
109     }
110 
111   /* Copy the data in the coefficients. Please note that we are assuming
112    * row-major order in here. */
113   cplx_t *ptr = mpoly->P + (mpoly->m * mpoly->m) * i;
114   memmove (ptr, matrix, sizeof(cplx_t) * (mpoly->m * mpoly->m));
115 
116   for (j = 0; j < mpoly->m * mpoly->m; j++)
117     {
118       /* Adjust structure if needed */
119       if (cplx_Im (matrix[j]) != 0.0)
120         poly->structure = MPS_STRUCTURE_COMPLEX_FP;
121 
122       mpc_set_cplx (mpoly->mP[j], mpoly->P[j]);
123     }
124 }
125 
126 void
mps_monomial_matrix_poly_set_coefficient_q(mps_context * ctx,mps_monomial_matrix_poly * mpoly,int i,mpq_t * matrix_r,mpq_t * matrix_i)127 mps_monomial_matrix_poly_set_coefficient_q (mps_context * ctx,
128                                             mps_monomial_matrix_poly *mpoly,
129                                             int i,
130                                             mpq_t * matrix_r,
131                                             mpq_t * matrix_i)
132 {
133   mps_polynomial *poly = MPS_POLYNOMIAL (mpoly);
134   int degree = poly->degree;
135   int j;
136 
137   if (i < 0 || i > degree)
138     {
139       mps_error (ctx, "Degree of the coefficient is out of bounds");
140       return;
141     }
142 
143   if (poly->structure == MPS_STRUCTURE_UNKNOWN)
144     poly->structure = MPS_STRUCTURE_REAL_RATIONAL;
145 
146   if (MPS_STRUCTURE_IS_FP (poly->structure))
147     {
148       mps_error (ctx, "Cannot assign exact coefficients to a floating point polynomial.");
149       return;
150     }
151 
152   for (j = 0; j < mpoly->m * mpoly->m; j++)
153     {
154       mpq_set (mpoly->mpqPr[i], matrix_r[i]);
155       mpq_set (mpoly->mpqPi[i], matrix_i[i]);
156 
157       if (mpq_cmp_ui (matrix_i[i], 0U, 1U) != 0)
158         poly->structure = MPS_STRUCTURE_COMPLEX_RATIONAL;
159     }
160 }
161 
162 mps_boolean
mps_monomial_matrix_poly_meval(mps_context * ctx,mps_polynomial * poly,mpc_t x,mpc_t value,rdpe_t error)163 mps_monomial_matrix_poly_meval (mps_context * ctx, mps_polynomial * poly,
164                                 mpc_t x, mpc_t value, rdpe_t error)
165 {
166   mps_monomial_matrix_poly *mpoly = MPS_MONOMIAL_MATRIX_POLY (poly);
167 
168   if (!mpoly->flags & MPS_MONOMIAL_MATRIX_POLY_HESSENBERG)
169     {
170       /* TODO: Insert the necessary steps to make a Hessenberg matrix
171        * available in place of this non-Hessenberg matrix polynomial. */
172     }
173 
174   /* TODO: This is not thread safe - at all! Insert a double buffer strategy
175    * in here, as for the case of mps_monomial_poly. */
176   if (mpc_get_prec (mpoly->mP[0]) < mpc_get_prec (value))
177     mps_monomial_matrix_poly_raise_data (ctx, poly, mpc_get_prec (value));
178 
179   /* Otherwise just proceed with Horner and our recursive implementation. */
180   /* TODO: We are performing a floating point evaluation here, just for simplicity. */
181   mps_mhessenberg_shifted_determinant (ctx, mpoly->mP, x, mpoly->m, value, error);
182 
183   return true;
184 }
185 
186 long int
mps_monomial_matrix_poly_raise_data(mps_context * ctx,mps_polynomial * p,long int wp)187 mps_monomial_matrix_poly_raise_data (mps_context * ctx,
188                                      mps_polynomial * p,
189                                      long int wp)
190 {
191   int i;
192   mps_monomial_matrix_poly *mpoly = MPS_MONOMIAL_MATRIX_POLY (p);
193   size_t n_elems = (mpoly->degree + 1) * (mpoly->m * mpoly->m);
194 
195   for (i = 0; i < n_elems; i++)
196     {
197       mpc_set_prec (mpoly->mP[i], wp);
198     }
199 
200   if (MPS_STRUCTURE_IS_INTEGER (p->structure) ||
201       MPS_STRUCTURE_IS_RATIONAL (p->structure))
202     {
203       mpc_set_q (mpoly->mP[i], mpoly->mpqPr[i], mpoly->mpqPi[i]);
204     }
205 
206   return mpc_get_prec (mpoly->mP[0]);
207 }
208