FORM v5.0.1-33-gdf7fc94
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, sort_vars);
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, sort_vars);
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, sort_vars);
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, sort_vars);
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 bool with_arghead = false;
168 const bool sort_vars = false;
169 const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars);
170
171 if ( var_map.size() > 1 ) {
172 return flint::mul_mpoly(BHEAD a, b, var_map, sort_vars);
173 }
174 else {
175 return flint::mul_poly(BHEAD a, b, var_map);
176 }
177}
178/*
179 #] flint_mul :
180 #[ flint_ratfun_add :
181*/
182WORD* flint_ratfun_add(PHEAD WORD *t1, WORD *t2) {
183
184 if ( AR.PolyFunExp == 1 ) {
185/* INTERNAL_ERROR_EXCL_START */
186 MLOCK(ErrorMessageLock);
187 MesPrint("!>flint_ratfun_add: PolyFunExp unimplemented.");
188 MUNLOCK(ErrorMessageLock);
189 Terminate(-1);
190/* INTERNAL_ERROR_EXCL_STOP */
191 }
192
193 WORD *oldworkpointer = AT.WorkPointer;
194
195 // Extract expressions: the num and den of both prf
196 vector<WORD *> e;
197 e.reserve(4);
198 for (WORD *t=t1+FUNHEAD; t<t1+t1[1];) {
199 e.push_back(t);
200 NEXTARG(t);
201 }
202 for (WORD *t=t2+FUNHEAD; t<t2+t2[1];) {
203 e.push_back(t);
204 NEXTARG(t);
205 }
206 const bool with_arghead = true;
207 const bool sort_vars = AC.OldPRFSignFlag ? true : false;
208 const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars);
209
210 if ( var_map.size() > 1 ) {
211 flint::ratfun_add_mpoly(BHEAD t1, t2, oldworkpointer, var_map, sort_vars);
212 }
213 else {
214 flint::ratfun_add_poly(BHEAD t1, t2, oldworkpointer, var_map);
215 }
216
217 return oldworkpointer;
218}
219/*
220 #] flint_ratfun_add :
221 #[ flint_ratfun_normalize :
222*/
223int flint_ratfun_normalize(PHEAD WORD *term) {
224
225 // The length of the coefficient
226 const WORD ncoeff = (term + *term)[-1];
227 // The end of the term data, before the coefficient:
228 const WORD *tstop = term + *term - ABS(ncoeff);
229
230 // Search the term for multiple PolyFun or one dirty one.
231 unsigned num_polyratfun = 0;
232 for (WORD *t = term+1; t < tstop; t += t[1]) {
233 if (*t == AR.PolyFun) {
234 // Found one!
235 num_polyratfun++;
236 if ((t[2] & MUSTCLEANPRF) != 0) {
237 // Dirty, increment again to force normalisation for single PolyFun
238 num_polyratfun++;
239 }
240 if (num_polyratfun > 1) {
241 // We're not counting all occurrences, just determinining if there
242 // is something to be done.
243 break;
244 }
245 }
246 }
247 if (num_polyratfun <= 1) {
248 // There is nothing to do, return early
249 return 0;
250 }
251
252 // When there are polyratfun with only one argument: rename them temporarily to TMPPOLYFUN.
253 for (WORD *t = term+1; t < tstop; t += t[1]) {
254 if (*t == AR.PolyFun && (t[1] == FUNHEAD+t[FUNHEAD] || t[1] == FUNHEAD+2 ) ) {
255 *t = TMPPOLYFUN;
256 }
257 }
258
259
260 // Extract all variables in the polyfuns
261 // Collect pointers to each relevant argument
262 vector<WORD *> e;
263 e.reserve(4); // There could be more than 4 args in principle, but 4 is probably common.
264 for (WORD *t=term+1; t<tstop; t+=t[1]) {
265 if (*t == AR.PolyFun) {
266 for (WORD *t2 = t+FUNHEAD; t2<t+t[1];) {
267 e.push_back(t2);
268 NEXTARG(t2);
269 }
270 }
271 }
272 const bool with_arghead = true;
273 const bool sort_vars = AC.OldPRFSignFlag ? true : false;
274 const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars);
275
276 if ( var_map.size() > 1 ) {
277 flint::ratfun_normalize_mpoly(BHEAD term, var_map, sort_vars);
278 }
279 else {
280 flint::ratfun_normalize_poly(BHEAD term, var_map);
281 }
282
283
284 // Undo renaming of single-argument PolyFun
285 const WORD *new_tstop = term + *term - ABS((term + *term)[-1]);
286 for (WORD *t=term+1; t<new_tstop; t+=t[1]) {
287 if (*t == TMPPOLYFUN ) *t = AR.PolyFun;
288 }
289
290 return 0;
291}
292/*
293 #] flint_ratfun_normalize :
294 #[ flint_rem :
295*/
296WORD* flint_rem(PHEAD WORD *a, WORD *b, const WORD must_fit_term) {
297 // Extract expressions
298 vector<WORD *> e;
299 e.reserve(2);
300 e.push_back(a);
301 e.push_back(b);
302 const bool with_arghead = false;
303 const bool sort_vars = false;
304 const flint::var_map_t var_map = flint::get_variables(e, with_arghead, sort_vars);
305
306 const bool return_rem = true;
307 if ( var_map.size() > 1 ) {
308 return flint::divmod_mpoly(BHEAD a, b, return_rem, must_fit_term, var_map, sort_vars);
309 }
310 else {
311 return flint::divmod_poly(BHEAD a, b, return_rem, must_fit_term, var_map);
312 }
313}
314/*
315 #] flint_rem :
316 #[ flint_check_version :
317*/
318
326 bool ok = true;
327 std::stringstream ss(flint_version);
328 int major, minor, patch;
329 char dot1, dot2;
330 if ( ss >> major >> dot1 >> minor >> dot2 >> patch ) {
331 if ( dot1 != '.' || dot2 != '.' || major < 0 || minor < 0 || patch < 0 ) {
332 ok = false;
333 }
334 else if ( major * 10000 + minor * 100 + patch < 30200 ) {
335 // flint < 3.2.0: https://github.com/form-dev/form/issues/679
336 ok = false;
337 }
338 }
339 else {
340 ok = false;
341 }
342 if ( !ok ) {
343 MesPrint("Bad FLINT version detected at runtime: %s",flint_version);
344 Terminate(-2);
345 }
346}
347
348/*
349 #] flint_check_version :
350*/
void flint_check_version(void)
Definition flintwrap.cc:325