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