Macaulay2 Engine
Loading...
Searching...
No Matches
polyroots.cpp
Go to the documentation of this file.
1
31
32#include "interface/factory.h"
33#include "interface/ring.h"
34
35// mps uses the c++ keyword register, which is no longer allowed in the C++17
36// standard, so we disable it by defining an empty macro.
37#define register
38#include <mps/mps.h>
39#undef register
40#include <stdlib.h>
41
42#include "aring-CCC.hpp"
43#include "aring.hpp"
44#include "error.h"
45#include "monoid.hpp"
46#include "polyring.hpp"
47#include "relem.hpp"
48#include "ring.hpp"
49#include "ringelem.hpp"
50
51#define abs(x) (((x) < 0) ? -(x) : (x))
52#define max(a, b) (((a) > (b)) ? (a) : (b))
53
55 long prec,
56 int unique)
57{
58 (void) unique;
59 const Ring *R = p->get_ring();
61 const Monoid *M = P->getMonoid();
62 if (P == nullptr) {
63 ERROR("expected a polynomial ring");
64 return nullptr;
65 }
66 if (P->n_vars() != 1) {
67 ERROR("expected a univariate polynomial ring");
68 return nullptr;
69 }
70 if (p->is_zero()) {
71 ERROR("expected a nonzero polynomial");
72 return nullptr;
73 }
74 const Ring *K = P->getCoefficients();
75 int lodeg,hideg; // lowest,highest degree
76 P->degree_of_var(0,p->get_value(),lodeg,hideg);
77 if (prec == -1)
78 prec = (K->get_precision() == 0 ? 53 : K->get_precision());
79
80 mps_context *s = mps_context_new ();
81 mps_monomial_poly *mps_p = mps_monomial_poly_new (s, hideg);
82 mps_context_select_algorithm(s, MPS_ALGORITHM_SECULAR_GA);
83
84 const auto ID = K->ringID();
85 for (Nterm *t = p->get_value(); t != nullptr; t = t->next) {
86 int deg;
87 M->to_expvector(t->monom, &deg); // number of vars = 1
88 if (ID==M2::ring_RR or ID==M2::ring_CC) {
90 if (ID==M2::ring_RR) {
91 cc.re = t->coeff.get_double();
92 cc.im = 0;
93 } else cc = *t->coeff.get_cc_doubles();
94 mps_monomial_poly_set_coefficient_d (s, mps_p, deg, cc.re, cc.im);
95 } else if (ID==M2::ring_RRR or ID==M2::ring_CCC) {
96 mpc_t mpc_cc;
97 mpc_init2(mpc_cc,K->get_precision());
98 if (ID==M2::ring_RRR) {
99 mpfr_get_f(mpc_cc->r,t->coeff.get_mpfr(),MPFR_RNDN);
100 } else {
101 mpfr_get_f(mpc_cc->r,&t->coeff.get_cc()->re,MPFR_RNDN);
102 mpfr_get_f(mpc_cc->i,&t->coeff.get_cc()->im,MPFR_RNDN);
103 }
104 mps_monomial_poly_set_coefficient_f (s, mps_p, deg, mpc_cc);
105 mpc_clear(mpc_cc);
106 } else if ((ID==M2::ring_old and K->is_ZZ()) or ID==M2::ring_QQ) {
107 mpq_t q, zero;
108 mpq_init(zero);
109 mpq_init(q);
110 if (ID==M2::ring_QQ)
111 mpq_set(q, t->coeff.get_mpq());
112 else mpq_set_z(q, t->coeff.get_mpz());
113 mps_monomial_poly_set_coefficient_q(s, mps_p, deg, q, zero);
114 mpq_clear(q);
115 mpq_clear(zero);
116 } else {
117 ERROR("'roots' expects coefficients in ZZ, QQ, RR or CC");
118 return nullptr;
119 }
120 }
121
122 /* Set the input polynomial */
123 mps_context_set_input_poly (s, MPS_POLYNOMIAL (mps_p));
124 mps_context_set_output_prec (s, prec);
125 mps_context_set_output_goal (s, MPS_OUTPUT_GOAL_APPROXIMATE);
126
127 /* Actually solve the polynomial */
128 mps_mpsolve (s);
129
130 // result to be returned
132 result = getmemarraytype(engine_RawRingElementArray, hideg);
133 result->len = static_cast<int>(hideg);
134
136 if (prec <= 53) {
137 /* Allocate space to hold the results. We check only floating point results in here */
138 cplx_t *result_mps = cplx_valloc (hideg);
139
140 /* Save roots computed in the vector results */
141 mps_context_get_roots_d (s, &result_mps, nullptr);
142
143 /* Print out roots */
144 // for (int i = 0; i < hideg; i++) {
145 // cplx_out_str (stdout, result_mps[i]);
146 // printf ("\n");
147 // }
148
150 // copy to mps_result to result
151
152 const Ring *C = IM2_Ring_CCC(prec);
153 for (int i = 0; i < hideg; i++) {
154 auto& mps_root = result_mps[i];
155 ring_elem m2_root;
156 C->from_complex_double(cplx_Re(mps_root), cplx_Im(mps_root),
157 m2_root);
158 result->array[i] = RingElement::make_raw(C, m2_root);
159 }
160
161 free (result_mps);
162 } else { // prec > 53
163 mpc_t *roots = nullptr;
164 rdpe_t *radii = nullptr;
165
166 mps_context_get_roots_m (s, &roots, &radii);
167 /* Sort roots in the order of increasing real part */
168 //sort_roots(hideg, roots, radii);
169 // for (int i = 0; i < hideg; i++) {
170 // mpc_out_str (stdout, 10, prec/4, roots[i]);
171 // printf ("\n");
172 // }
173
174 const Ring *C = IM2_Ring_CCC(prec);
175 const M2::ARingCCC C0(prec);
176
177 M2::ARingCCC::Element cc (C0);
178 for (int i = 0; i < hideg; i++) {
179 auto& mps_root = roots[i];
180 mpfr_set_f(&cc.value().re,mpc_Re(mps_root),MPFR_RNDN);
181 mpfr_set_f(&cc.value().im,mpc_Im(mps_root),MPFR_RNDN);
182 ring_elem m2_root;
183 C0.to_ring_elem(m2_root, cc);
184 result->array[i] = RingElement::make_raw(C, m2_root);
185 }
186
187 free(roots);
188 free(radii);
189 }
190
191 mps_monomial_poly_free(s, (mps_polynomial *)mps_p);
192 mps_context_free(s);
193 return result;
194}
195
196// Local Variables:
197// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
198// indent-tabs-mode: nil
199// End:
M2::ARingCCC — arbitrary-precision complex numbers (pair of MPFR floats).
Shared base of the aring framework (namespace M2) that unifies the engine's coefficient rings.
void to_ring_elem(ring_elem &result, const ElementType &a) const
aring-style adapter for arbitrary-precision complex numbers, stored as (MPFR, MPFR) pairs.
Definition aring-CCC.hpp:71
void to_expvector(const_monomial m, exponents_t result_exp) const
Definition monoid.cpp:747
Engine-side commutative monomial monoid: variable names, ordering, multidegree machinery,...
Definition monoid.hpp:89
virtual const Monoid * getMonoid() const
Definition polyring.hpp:282
virtual const Ring * getCoefficients() const
Definition polyring.hpp:277
virtual void degree_of_var(int n, const ring_elem a, int &lo, int &hi) const =0
int n_vars() const
Definition polyring.hpp:196
Abstract base for the engine's polynomial-ring hierarchy.
Definition polyring.hpp:96
virtual bool is_ZZ() const
Definition ring.hpp:171
virtual M2::RingID ringID() const
Definition ring.hpp:164
virtual unsigned long get_precision() const
Definition ring.cpp:438
virtual const PolynomialRing * cast_to_PolynomialRing() const
Definition ring.hpp:243
virtual bool from_complex_double(double re, double im, ring_elem &result) const
Definition ring.cpp:276
static RingElement * make_raw(const Ring *R, ring_elem f)
Definition relem.cpp:20
Front-end-visible "ring element" value: an engine ring_elem paired with the Ring* that gives it meani...
Definition relem.hpp:67
xxx xxx xxx
Definition ring.hpp:102
Engine error-reporting primitives: ERROR, INTERNAL_ERROR, error, error_message.
Engine-boundary C API for polynomial GCD, factorisation, and root finding.
int p
int zero
@ ring_CCC
Definition aring.hpp:90
@ ring_old
refers to all rings which are not ConcreteRing's.
Definition aring.hpp:94
@ ring_RR
Definition aring.hpp:87
@ ring_RRR
Definition aring.hpp:89
@ ring_QQ
Definition aring.hpp:79
@ ring_CC
Definition aring.hpp:88
const Ring * IM2_Ring_CCC(unsigned long prec)
Definition ring.cpp:108
void size_t s
Definition m2-mem.cpp:271
const int ERROR
Definition m2-mem.cpp:55
VALGRIND_MAKE_MEM_DEFINED & result(result)
#define getmemarraytype(S, len)
Definition m2-mem.h:142
engine_RawRingElementArray engine_RawRingElementArrayOrNull
Definition m2-types.h:176
Monoid — variable count, naming, grading, and monomial order of a polynomial ring.
PolynomialRing — abstract polynomial-ring base, the engine's most-reused class.
engine_RawRingElementArrayOrNull rawRoots(const RingElement *p, long prec, int unique)
Definition polyroots.cpp:54
RingElement — tagged (Ring*, ring_elem) pair, the engine's universal element type.
Engine-boundary C API for the legacy Ring hierarchy — coefficient, polynomial, and composite rings.
Ring — the legacy abstract base class for every coefficient and polynomial ring.
ring_elem — the universal value type carried by every Ring* in the engine.
Singly linked-list node carrying one term of a polynomial-ring element.
Definition ringelem.hpp:156