FORM v5.0.0-35-g6318119
flintwrap.cc
Go to the documentation of this file.
1
5/* #[ License : */
6/*
7 * Copyright (C) 1984-2026 J.A.M. Vermaseren
8 * When using this file you are requested to refer to the publication
9 * J.A.M.Vermaseren "New features of FORM" math-ph/0010025
10 * This is considered a matter of courtesy as the development was paid
11 * for by FOM the Dutch physics granting agency and we would like to
12 * be able to track its scientific use to convince FOM of its value
13 * for the community.
14 *
15 * This file is part of FORM.
16 *
17 * FORM is free software: you can redistribute it and/or modify it under the
18 * terms of the GNU General Public License as published by the Free Software
19 * Foundation, either version 3 of the License, or (at your option) any later
20 * version.
21 *
22 * FORM is distributed in the hope that it will be useful, but WITHOUT ANY
23 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
24 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
25 * details.
26 *
27 * You should have received a copy of the GNU General Public License along
28 * with FORM. If not, see <http://www.gnu.org/licenses/>.
29 */
30/* #] License : */
31
32extern "C" {
33#include "form3.h"
34}
35
36#include <sstream>
37#include "flintinterface.h"
38
39
40/*
41 #[ flint_final_cleanup_thread :
42*/
43void flint_final_cleanup_thread(void) {
44 flint::cleanup();
45}
46/*
47 #] flint_final_cleanup_thread :
48 #[ flint_final_cleanup_master :
49*/
50void flint_final_cleanup_master(void) {
51 flint::cleanup_master();
52}
53/*
54 #] flint_final_cleanup_master :
55 #[ flint_div :
56*/
57WORD* flint_div(PHEAD WORD *a, WORD *b, const WORD must_fit_term) {
58 // Extract expressions
59 vector<WORD *> e;
60 e.reserve(2);
61 e.push_back(a);
62 e.push_back(b);
63 const bool with_arghead = false;
64 const bool sort_vars = false;
65 const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars);
66
67 const bool return_rem = false;
68 if ( var_map.size() > 1 ) {
69 return flint::divmod_mpoly(BHEAD a, b, return_rem, must_fit_term, var_map);
70 }
71 else {
72 return flint::divmod_poly(BHEAD a, b, return_rem, must_fit_term, var_map);
73 }
74}
75/*
76 #] flint_div :
77 #[ flint_factorize_argument :
78*/
79int flint_factorize_argument(PHEAD WORD *argin, WORD *argout) {
80
81 const bool with_arghead = true;
82 const bool sort_vars = true;
83 const flint::var_map_t var_map = flint::get_variables(vector<WORD*>(1,argin), with_arghead,
84 sort_vars);
85
86 const bool is_fun_arg = true;
87 if ( var_map.size() > 1 ) {
88 flint::factorize_mpoly(BHEAD argin, argout, with_arghead, is_fun_arg, var_map);
89 }
90 else {
91 flint::factorize_poly(BHEAD argin, argout, with_arghead, is_fun_arg, var_map);
92 }
93
94 return 0;
95}
96/*
97 #] flint_factorize_argument :
98 #[ flint_factorize_dollar :
99*/
100WORD* flint_factorize_dollar(PHEAD WORD *argin) {
101
102 const bool with_arghead = false;
103 const bool sort_vars = true;
104 const flint::var_map_t var_map = flint::get_variables(vector<WORD*>(1,argin), with_arghead,
105 sort_vars);
106
107 const bool is_fun_arg = false;
108 if ( var_map.size() > 1 ) {
109 return flint::factorize_mpoly(BHEAD argin, NULL, with_arghead, is_fun_arg, var_map);
110 }
111 else {
112 return flint::factorize_poly(BHEAD argin, NULL, with_arghead, is_fun_arg, var_map);
113 }
114}
115/*
116 #] flint_factorize_dollar :
117 #[ flint_gcd :
118*/
119WORD* flint_gcd(PHEAD WORD *a, WORD *b, const WORD must_fit_term) {
120 // Extract expressions
121 vector<WORD *> e;
122 e.reserve(2);
123 e.push_back(a);
124 e.push_back(b);
125 const bool with_arghead = false;
126 const bool sort_vars = true;
127 const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars);
128
129 if ( var_map.size() > 1 ) {
130 return flint::gcd_mpoly(BHEAD a, b, must_fit_term, var_map);
131 }
132 else {
133 return flint::gcd_poly(BHEAD a, b, must_fit_term, var_map);
134 }
135}
136/*
137 #] flint_gcd :
138 #[ flint_inverse :
139*/
140WORD* flint_inverse(PHEAD WORD *a, WORD *b) {
141 // Extract expressions
142 vector<WORD *> e;
143 e.reserve(2);
144 e.push_back(a);
145 e.push_back(b);
146 const flint::var_map_t var_map = flint::get_variables(e, false, false);
147
148 if ( var_map.size() > 1 ) {
149 MLOCK(ErrorMessageLock);
150 MesPrint("flint_inverse: error: only univariate polynomials are supported.");
151 MUNLOCK(ErrorMessageLock);
152 Terminate(-1);
153 }
154
155 return flint::inverse_poly(BHEAD a, b, var_map);
156}
157/*
158 #] flint_inverse :
159 #[ flint_mul :
160*/
161WORD* flint_mul(PHEAD WORD *a, WORD *b) {
162 // Extract expressions
163 vector<WORD *> e;
164 e.reserve(2);
165 e.push_back(a);
166 e.push_back(b);
167 const flint::var_map_t var_map = flint::get_variables(e, false, false);
168
169 if ( var_map.size() > 1 ) {
170 return flint::mul_mpoly(BHEAD a, b, var_map);
171 }
172 else {
173 return flint::mul_poly(BHEAD a, b, var_map);
174 }
175}
176/*
177 #] flint_mul :
178 #[ flint_ratfun_add :
179*/
180WORD* flint_ratfun_add(PHEAD WORD *t1, WORD *t2) {
181
182 if ( AR.PolyFunExp == 1 ) {
183 MLOCK(ErrorMessageLock);
184 MesPrint("flint_ratfun_add: PolyFunExp unimplemented.");
185 MUNLOCK(ErrorMessageLock);
186 Terminate(-1);
187 }
188
189 WORD *oldworkpointer = AT.WorkPointer;
190
191 // Extract expressions: the num and den of both prf
192 vector<WORD *> e;
193 e.reserve(4);
194 for (WORD *t=t1+FUNHEAD; t<t1+t1[1];) {
195 e.push_back(t);
196 NEXTARG(t);
197 }
198 for (WORD *t=t2+FUNHEAD; t<t2+t2[1];) {
199 e.push_back(t);
200 NEXTARG(t);
201 }
202 const bool with_arghead = true;
203 const bool sort_vars = true;
204 const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars);
205
206 if ( var_map.size() > 1 ) {
207 flint::ratfun_add_mpoly(BHEAD t1, t2, oldworkpointer, var_map);
208 }
209 else {
210 flint::ratfun_add_poly(BHEAD t1, t2, oldworkpointer, var_map);
211 }
212
213 return oldworkpointer;
214}
215/*
216 #] flint_ratfun_add :
217 #[ flint_ratfun_normalize :
218*/
219int flint_ratfun_normalize(PHEAD WORD *term) {
220
221 // The length of the coefficient
222 const WORD ncoeff = (term + *term)[-1];
223 // The end of the term data, before the coefficient:
224 const WORD *tstop = term + *term - ABS(ncoeff);
225
226 // Search the term for multiple PolyFun or one dirty one.
227 unsigned num_polyratfun = 0;
228 for (WORD *t = term+1; t < tstop; t += t[1]) {
229 if (*t == AR.PolyFun) {
230 // Found one!
231 num_polyratfun++;
232 if ((t[2] & MUSTCLEANPRF) != 0) {
233 // Dirty, increment again to force normalisation for single PolyFun
234 num_polyratfun++;
235 }
236 if (num_polyratfun > 1) {
237 // We're not counting all occurrences, just determinining if there
238 // is something to be done.
239 break;
240 }
241 }
242 }
243 if (num_polyratfun <= 1) {
244 // There is nothing to do, return early
245 return 0;
246 }
247
248 // When there are polyratfun with only one argument: rename them temporarily to TMPPOLYFUN.
249 for (WORD *t = term+1; t < tstop; t += t[1]) {
250 if (*t == AR.PolyFun && (t[1] == FUNHEAD+t[FUNHEAD] || t[1] == FUNHEAD+2 ) ) {
251 *t = TMPPOLYFUN;
252 }
253 }
254
255
256 // Extract all variables in the polyfuns
257 // Collect pointers to each relevant argument
258 vector<WORD *> e;
259 e.reserve(4); // There could be more than 4 args in principle, but 4 is probably common.
260 for (WORD *t=term+1; t<tstop; t+=t[1]) {
261 if (*t == AR.PolyFun) {
262 for (WORD *t2 = t+FUNHEAD; t2<t+t[1];) {
263 e.push_back(t2);
264 NEXTARG(t2);
265 }
266 }
267 }
268 const bool with_arghead = true;
269 const bool sort_vars = true;
270 const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars);
271
272 if ( var_map.size() > 1 ) {
273 flint::ratfun_normalize_mpoly(BHEAD term, var_map);
274 }
275 else {
276 flint::ratfun_normalize_poly(BHEAD term, var_map);
277 }
278
279
280 // Undo renaming of single-argument PolyFun
281 const WORD *new_tstop = term + *term - ABS((term + *term)[-1]);
282 for (WORD *t=term+1; t<new_tstop; t+=t[1]) {
283 if (*t == TMPPOLYFUN ) *t = AR.PolyFun;
284 }
285
286 return 0;
287}
288/*
289 #] flint_ratfun_normalize :
290 #[ flint_rem :
291*/
292WORD* flint_rem(PHEAD WORD *a, WORD *b, const WORD must_fit_term) {
293 // Extract expressions
294 vector<WORD *> e;
295 e.reserve(2);
296 e.push_back(a);
297 e.push_back(b);
298 const bool with_arghead = false;
299 const bool sort_vars = false;
300 const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars);
301
302 const bool return_rem = true;
303 if ( var_map.size() > 1 ) {
304 return flint::divmod_mpoly(BHEAD a, b, return_rem, must_fit_term, var_map);
305 }
306 else {
307 return flint::divmod_poly(BHEAD a, b, return_rem, must_fit_term, var_map);
308 }
309}
310/*
311 #] flint_rem :
312 #[ flint_check_version :
313*/
314
322 bool ok = true;
323 std::stringstream ss(flint_version);
324 int major, minor, patch;
325 char dot1, dot2;
326 if ( ss >> major >> dot1 >> minor >> dot2 >> patch ) {
327 if ( dot1 != '.' || dot2 != '.' || major < 0 || minor < 0 || patch < 0 ) {
328 ok = false;
329 }
330 else if ( major * 10000 + minor * 100 + patch < 30200 ) {
331 // flint < 3.2.0: https://github.com/form-dev/form/issues/679
332 ok = false;
333 }
334 }
335 else {
336 ok = false;
337 }
338 if ( !ok ) {
339 MesPrint("Bad FLINT version detected at runtime: %s",flint_version);
340 Terminate(-2);
341 }
342}
343
344/*
345 #] flint_check_version :
346*/
void flint_check_version(void)
Definition flintwrap.cc:321