1 /*
2 Copyright (C) 2013 Tom Bachmann
3
4 This file is part of FLINT.
5
6 FLINT is free software: you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License (LGPL) as published
8 by the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version. See <http://www.gnu.org/licenses/>.
10 */
11
12 #ifndef CXX_PADICXX_H
13 #define CXX_PADICXX_H CXX_PADICXX_H
14
15 #include <algorithm> // std::max
16 #include <cstdlib>
17
18 #include "padic.h"
19
20 #include "flintxx/expression.h"
21 #include "flintxx/flint_classes.h"
22 #include "flintxx/flint_exception.h"
23 #include "flintxx/frandxx.h"
24 #include "flintxx/stdmath.h"
25 #include "flintxx/traits.h"
26 #include "flintxx/tuple.h"
27
28 #include "fmpzxx.h"
29 #include "fmpqxx.h"
30
31 // TODO check codegen ...
32 // TODO padic_output_prec does not work on non-padic expressions,
33 // is that a problem?
34
35 namespace flint {
36 // function "declarations"
37 FLINT_DEFINE_UNOP(exp_rectangular)
FLINT_DEFINE_UNOP(exp_balanced)38 FLINT_DEFINE_UNOP(exp_balanced)
39 FLINT_DEFINE_UNOP(log_rectangular)
40 FLINT_DEFINE_UNOP(log_balanced)
41 FLINT_DEFINE_UNOP(log_satoh)
42 FLINT_DEFINE_UNOP(teichmuller)
43 FLINT_DEFINE_BINOP(padic_val_fac)
44
45 class padicxx_ctx
46 {
47 private:
48 mutable padic_ctx_t ctx;
49
50 public:
51 // NB: you must not modify user-visible state of ctx through a constant
52 // instance of padicxx_ctx
53 padic_ctx_t& _ctx() const {return ctx;}
54
55 // XXX these two are not actually exposed in the C api ...
56 fmpzxx_ref get_p() {return fmpzxx_ref::make(ctx[0].p);}
57 fmpzxx_srcref get_p() const {return fmpzxx_srcref::make(ctx[0].p);}
58
59 padic_print_mode mode() const {return _ctx()->mode;}
60 padic_print_mode& mode() {return _ctx()->mode;}
61
62 // TODO more constructors? Should we wrap padic_print_mode?
63 padicxx_ctx(fmpzxx_srcref p, slong min, slong max, padic_print_mode mode)
64 {
65 padic_ctx_init(ctx, p._fmpz(), min, max, mode);
66 }
67
68 ~padicxx_ctx() {padic_ctx_clear(ctx);}
69 };
70
71 class padicxx_ctx_srcref
72 {
73 private:
74 mutable padic_ctx_struct* ctx;
75
padicxx_ctx_srcref(padic_ctx_struct * c)76 padicxx_ctx_srcref(padic_ctx_struct* c) : ctx(c) {}
77
78 public:
79 // NB: you must not modify user-visible state of ctx through a constant
80 // instance of padicxx_ctx
_ctx()81 padic_ctx_struct* _ctx() const {return ctx;}
82
83 // XXX these two are not actually exposed in the C api ...
get_p()84 fmpzxx_ref get_p() {return fmpzxx_ref::make(ctx[0].p);}
get_p()85 fmpzxx_srcref get_p() const {return fmpzxx_srcref::make(ctx[0].p);}
86
mode()87 padic_print_mode mode() const {return _ctx()->mode;}
88
padicxx_ctx_srcref(padicxx_ctx & c)89 padicxx_ctx_srcref(padicxx_ctx& c)
90 : ctx(c._ctx()) {}
91
make(padic_ctx_struct * c)92 static padicxx_ctx_srcref make(padic_ctx_struct* c)
93 {return padicxx_ctx_srcref(c);}
94 };
95
96 namespace traits {
97 template<class T> struct has_padicxx_ctx : mp::false_ { };
98
99 template<class T> struct is_padic_expr
100 : has_padicxx_ctx<typename tools::evaluation_helper<T>::type> { };
101 } // traits
102 namespace detail {
103 struct has_padicxx_ctx_predicate
104 {
105 template<class T> struct type : traits::has_padicxx_ctx<T> { };
106 };
107
108 template<class T, class Enable = void>
109 struct padicxx_max_prec;
110
111 template<class T>
112 struct padicxx_max_prec<T,
113 typename mp::enable_if<traits::has_padicxx_ctx<T> >::type>
114 {
115 static slong get(const T& p) {return p.prec();}
116 };
117
118 template<class T>
119 struct padicxx_max_prec<T,
120 typename mp::disable_if<traits::is_padic_expr<T> >::type>
121 {
122 static slong get(const T&) {return 0;}
123 };
124
125 template<class Data>
126 struct padicxx_max_prec_h;
127 template<class Head, class Tail>
128 struct padicxx_max_prec_h<tuple<Head, Tail> >
129 {
130 static slong get(const tuple<Head, Tail>& t)
131 {
132 slong p1 = padicxx_max_prec_h<Tail>::get(t.tail);
133 slong p2 =
134 padicxx_max_prec<typename traits::basetype<Head>::type>::get(t.head);
135 return std::max(p1, p2);
136 }
137 };
138 template<>
139 struct padicxx_max_prec_h<empty_tuple>
140 {
141 static slong get(empty_tuple) {return 0;}
142 };
143
144 template<class T>
145 struct padicxx_max_prec<T, typename mp::enable_if<mp::and_<
146 traits::is_padic_expr<T>,
147 mp::not_<traits::is_immediate<T> > > >::type>
148 {
149 static slong get(const T& e)
150 {return padicxx_max_prec_h<typename T::data_t>::get(e._data());}
151 };
152 } // detail
153 namespace tools {
154 template<class Expr>
155 padicxx_ctx_srcref find_padicxx_ctx(const Expr& e)
156 {
157 return tools::find_subexpr<detail::has_padicxx_ctx_predicate>(e).get_ctx();
158 }
159
160 template<class Expr>
161 slong padic_output_prec(const Expr& e)
162 {
163 return detail::padicxx_max_prec<Expr>::get(e);
164 }
165 } // tools
166
167 FLINT_DEFINE_UNOP(padicxx_unit)
168
169 namespace detail {
170 template<class Padic>
171 struct padic_traits
172 {
173 typedef FLINT_UNOP_BUILD_RETTYPE(padicxx_unit, fmpzxx, Padic)
174 unit_srcref_t;
175
176 typedef slong prec_ref_t;
177 typedef slong prec_srcref_t;
178
179 typedef slong val_ref_t;
180 typedef slong val_srcref_t;
181
182 static slong prec(const Padic& p) {return tools::padic_output_prec(p);}
183 static slong val(const Padic& p) {return padic_val(p.evaluate()._padic());}
184
185 static unit_srcref_t unit(const Padic& p) {return padicxx_unit(p);}
186 };
187 } //detail
188
189 template<class Operation, class Data>
190 class padicxx_expression
191 : public expression<derived_wrapper<padicxx_expression>, Operation, Data>
192 {
193 public:
194 typedef expression<derived_wrapper< ::flint::padicxx_expression>,
195 Operation, Data> base_t;
196
197 FLINTXX_DEFINE_BASICS(padicxx_expression)
198 FLINTXX_DEFINE_CTORS(padicxx_expression)
199 FLINTXX_DEFINE_C_REF(padicxx_expression, padic_struct, _padic)
200
201 public:
202 typedef detail::padic_traits<padicxx_expression> traits_t;
203
204 // These only make sense with immediates
205 void reduce() {padic_reduce(_padic(), _ctx());}
206 void set_zero() {padic_zero(_padic());}
207 void set_one() {padic_one(_padic());}
208
209 #define PADICXX_DEFINE_CTX \
210 padicxx_ctx_srcref get_ctx() const {return this->_data().ctx;} \
211 padic_ctx_struct* _ctx() const {return get_ctx()._ctx();}
212 PADICXX_DEFINE_CTX
213
214 static padicxx_expression zero(padicxx_ctx_srcref ctx)
215 {return padicxx_expression(ctx);}
216 static padicxx_expression zero(padicxx_ctx_srcref ctx, slong N)
217 {return padicxx_expression(ctx, N);}
218 static padicxx_expression one(padicxx_ctx_srcref ctx)
219 {
220 padicxx_expression res(ctx);
221 res.set_one();
222 return res;
223 }
224 static padicxx_expression one(padicxx_ctx_srcref ctx, slong N)
225 {
226 padicxx_expression res(ctx, N);
227 res.set_one();
228 return res;
229 }
230
231 template<class T>
232 static padicxx_expression from_QQ(const T& q, padicxx_ctx_srcref ctx,
233 typename mp::enable_if<mp::or_<traits::is_fmpqxx<T>,
234 traits::is_fmpzxx<T>, traits::is_integer<T> > >::type* = 0)
235 {
236 padicxx_expression res(ctx);
237 res = q;
238 return res;
239 }
240 template<class T>
241 static padicxx_expression from_QQ(const T& q, padicxx_ctx_srcref ctx,
242 slong N,
243 typename mp::enable_if<mp::or_<traits::is_fmpqxx<T>,
244 traits::is_fmpzxx<T>, traits::is_integer<T> > >::type* = 0)
245 {
246 padicxx_expression res(ctx, N);
247 res = q;
248 return res;
249 }
250 // TODO more?
251
252 // The above method get_ctx() only works on immediates, i.e. instances of
253 // padicxx. This next one here works on any composite expression which
254 // contains at least one instance of padicxx. Returns the context of one of
255 // those immediate subexpressions.
256 #define PADICXX_DEFINE_ESTIMATE_CTX \
257 padicxx_ctx_srcref estimate_ctx() const \
258 { \
259 return tools::find_padicxx_ctx(*this); \
260 }
261 PADICXX_DEFINE_ESTIMATE_CTX
262
263 // Create a temporary. The context will be estimated, and the precision
264 // will be the maximum of all subexpressions.
265 evaluated_t create_temporary() const
266 {
267 return evaluated_t(estimate_ctx(), prec());
268 }
269
270 // static methods which only make sense with padicxx
271 static padicxx_expression randtest(frandxx& state,
272 padicxx_ctx_srcref ctx, slong prec = PADIC_DEFAULT_PREC)
273 {
274 padicxx_expression res(ctx, prec);
275 padic_randtest(res._padic(), state._data(), ctx._ctx());
276 return res;
277 }
278 static padicxx_expression randtest_not_zero(frandxx& state,
279 padicxx_ctx_srcref ctx, slong prec = PADIC_DEFAULT_PREC)
280 {
281 padicxx_expression res(ctx, prec);
282 padic_randtest_not_zero(res._padic(), state._data(), ctx._ctx());
283 return res;
284 }
285 static padicxx_expression randtest_int(frandxx& state,
286 padicxx_ctx_srcref ctx, slong prec = PADIC_DEFAULT_PREC)
287 {
288 padicxx_expression res(ctx, prec);
289 padic_randtest_int(res._padic(), state._data(), ctx._ctx());
290 return res;
291 }
292
293 #define PADICXX_DEFINE_TON \
294 typename flint_classes::to_srcref<typename base_t::derived_t>::type \
295 toN(slong N) const \
296 { \
297 return flint_classes::to_srcref<typename base_t::derived_t>::type::make( \
298 this->_data().inner, get_ctx(), N); \
299 }
300 PADICXX_DEFINE_TON
301
302 typename traits_t::unit_srcref_t unit() const
303 {return traits_t::unit(*this);}
304
305 // Compute the maximal precision of all subexpressions
306 #define PADICXX_DEFINE_PREC \
307 typename traits_t::prec_ref_t prec() {return traits_t::prec(*this);} \
308 typename traits_t::prec_srcref_t prec() const \
309 {return traits_t::prec(*this);}
310 PADICXX_DEFINE_PREC
311
312 #define PADICXX_DEFINE_VAL \
313 typename traits_t::val_ref_t val() {return traits_t::val(*this);} \
314 typename traits_t::val_srcref_t val() const \
315 {return traits_t::val(*this);}
316 PADICXX_DEFINE_VAL
317
318 // these cause evaluation
319 bool is_zero() const {return padic_is_zero(this->evaluate()._padic());}
320 bool is_one() const {return padic_is_one(this->evaluate()._padic());}
321
322 // forwarding of lazy functions
323 FLINTXX_DEFINE_MEMBER_UNOP(exp)
324 FLINTXX_DEFINE_MEMBER_UNOP(exp_balanced)
325 FLINTXX_DEFINE_MEMBER_UNOP(exp_rectangular)
326 FLINTXX_DEFINE_MEMBER_UNOP(inv)
327 FLINTXX_DEFINE_MEMBER_UNOP(log)
328 FLINTXX_DEFINE_MEMBER_UNOP(log_balanced)
329 FLINTXX_DEFINE_MEMBER_UNOP(log_satoh)
330 FLINTXX_DEFINE_MEMBER_UNOP(sqrt)
331 FLINTXX_DEFINE_MEMBER_UNOP(teichmuller)
332 FLINTXX_DEFINE_MEMBER_BINOP(pow)
333 };
334
335 #define PADICXX_DEFINE_STD \
336 PADICXX_DEFINE_CTX \
337 PADICXX_DEFINE_ESTIMATE_CTX \
338 PADICXX_DEFINE_TON \
339 PADICXX_DEFINE_PREC \
340 PADICXX_DEFINE_VAL
341
342 namespace detail {
343 struct padic_data;
344 }
345
346 typedef padicxx_expression<operations::immediate, detail::padic_data> padicxx;
347 typedef padicxx_expression<operations::immediate,
348 flint_classes::ref_data<padicxx, padic_struct> > padicxx_ref;
349 typedef padicxx_expression<operations::immediate, flint_classes::srcref_data<
350 padicxx, padicxx_ref, padic_struct> > padicxx_srcref;
351
352 namespace traits {
353 template<> struct has_padicxx_ctx<padicxx> : mp::true_ { };
354 template<> struct has_padicxx_ctx<padicxx_ref> : mp::true_ { };
355 template<> struct has_padicxx_ctx<padicxx_srcref> : mp::true_ { };
356
357 template<class T> struct is_padicxx : flint_classes::is_Base<padicxx, T> { };
358 } // traits
359
360 namespace detail {
361 template<>
362 struct padic_traits<padicxx_srcref>
363 {
364 typedef fmpzxx_srcref unit_srcref_t;
365 template<class Poly>
366 static fmpzxx_srcref unit(const Poly& p)
367 {return fmpzxx_srcref::make(padic_unit(p._padic()));}
368
369 typedef slong prec_ref_t;
370 typedef slong prec_srcref_t;
371
372 typedef slong val_ref_t;
373 typedef slong val_srcref_t;
374
375 template<class P>
376 static slong prec(P p) {return p._data().N;}
377 template<class P>
378 static slong val(P p) {return padic_val(p._padic());}
379 };
380
381 template<>
382 struct padic_traits<padicxx_ref>
383 : padic_traits<padicxx_srcref>
384 {
385 typedef slong& prec_ref_t;
386 typedef slong& val_ref_t;
387
388 template<class P>
389 static slong& prec(P& p) {return padic_prec(p._padic());}
390 template<class P>
391 static slong prec(const P& p) {return padic_prec(p._padic());}
392
393 template<class P>
394 static slong& val(P& p) {return padic_val(p._padic());}
395 template<class P>
396 static slong val(const P& p) {return padic_val(p._padic());}
397 };
398 template<>
399 struct padic_traits<padicxx>
400 : padic_traits<padicxx_ref> { };
401
402 template<class T, class U>
403 struct faketemplate : mp::enable_if<mp::equal_types<T, U> > { };
404 } // detail
405
406 // NB: usually, the "padicname" parameter would not be necessary. We would
407 // leave that as a template, identifying the type by structname alone, and
408 // conveniently delay all instantiations. Unfortunately qadic and padic_poly
409 // have the same structname, so we cannot do this.
410 // Instead we pass in the class name explicitly, and delay relevant functions
411 // by hand...
412 #define PADICXX_DEFINE_REF_STRUCTS_(padicname, structname, precname, ctxtype) \
413 namespace flint_classes { \
414 template<> \
415 struct ref_data<padicname, structname> \
416 { \
417 typedef void IS_REF_OR_CREF; \
418 typedef padicname wrapped_t; \
419 \
420 typedef structname* data_ref_t; \
421 typedef const structname* data_srcref_t; \
422 \
423 structname* inner; \
424 ctxtype ctx; \
425 \
426 template<class T> \
427 ref_data(T& o, typename detail::faketemplate<T, padicname>::type* = 0) \
428 : inner(o._data().inner), ctx(o._data().ctx) {} \
429 \
430 static ref_data make(structname* f, ctxtype ctx) \
431 { \
432 return ref_data(f, ctx); \
433 } \
434 \
435 private: \
436 ref_data(structname* fp, ctxtype c) : inner(fp), ctx(c) {} \
437 }; \
438 \
439 template<class Ref> \
440 struct srcref_data<padicname, Ref, structname> \
441 { \
442 typedef void IS_REF_OR_CREF; \
443 typedef padicname wrapped_t; \
444 \
445 typedef const structname* data_ref_t; \
446 typedef const structname* data_srcref_t; \
447 \
448 const structname* inner; \
449 ctxtype ctx; \
450 slong N; \
451 \
452 template<class T> \
453 srcref_data(const T& o, \
454 typename detail::faketemplate<T, padicname>::type* = 0) \
455 : inner(o._data().inner), ctx(o._data().ctx), N(o.prec()) {} \
456 template<class T> \
457 srcref_data(T o, typename detail::faketemplate<T, Ref>::type* = 0) \
458 : inner(o._data().inner), ctx(o._data().ctx), N(o.prec()) {} \
459 \
460 static srcref_data make(const structname* f, ctxtype ctx) \
461 { \
462 return srcref_data(f, ctx); \
463 } \
464 static srcref_data make(const structname* f, ctxtype ctx, \
465 slong N) \
466 { \
467 return srcref_data(f, ctx, N); \
468 } \
469 \
470 private: \
471 srcref_data(const structname* fp, ctxtype c) \
472 : inner(fp), ctx(c), N(precname(fp)) {} \
473 srcref_data(const structname* fp, ctxtype c, slong n) \
474 : inner(fp), ctx(c), N(n) {} \
475 }; \
476 } /* flint_classes */
477 #define PADICXX_DEFINE_REF_STRUCTS(padicname, structname, precname) \
478 PADICXX_DEFINE_REF_STRUCTS_(padicname, structname, precname, padicxx_ctx_srcref)
479 PADICXX_DEFINE_REF_STRUCTS(padicxx, padic_struct, padic_prec)
480
481 namespace detail {
482 struct padic_data
483 {
484 typedef padic_t& data_ref_t;
485 typedef const padic_t& data_srcref_t;
486
487 padicxx_ctx_srcref ctx;
488 padic_t inner;
489
490 padic_data(padicxx_ctx_srcref c)
491 : ctx(c)
492 {
493 padic_init(inner);
494 }
495
496 padic_data(padicxx_ctx_srcref c, slong N)
497 : ctx(c)
498 {
499 padic_init2(inner, N);
500 }
501
502 padic_data(const padic_data& o)
503 : ctx(o.ctx)
504 {
505 padic_init2(inner, padic_prec(o.inner));
506 padic_set(inner, o.inner, ctx._ctx());
507 }
508
509 ~padic_data() {padic_clear(inner);}
510
511 padic_data(padicxx_srcref c)
512 : ctx(c.get_ctx())
513 {
514 padic_init2(inner, c.prec());
515 padic_set(inner, c._padic(), ctx._ctx());
516 }
517 };
518 } // detail
519
520 #define PADICXX_COND_S FLINTXX_COND_S(padicxx)
521 #define PADICXX_COND_T FLINTXX_COND_T(padicxx)
522
523 namespace rules {
524
525 FLINT_DEFINE_DOIT_COND2(assignment, PADICXX_COND_T, PADICXX_COND_S,
526 padic_set(to._padic(), from._padic(), to._ctx()))
527 FLINT_DEFINE_DOIT_COND2(assignment, PADICXX_COND_T, traits::is_signed_integer,
528 padic_set_si(to._padic(), from, to._ctx()))
529 FLINT_DEFINE_DOIT_COND2(assignment, PADICXX_COND_T, traits::is_unsigned_integer,
530 padic_set_ui(to._padic(), from, to._ctx()))
531 FLINT_DEFINE_DOIT_COND2(assignment, PADICXX_COND_T, FMPZXX_COND_S,
532 padic_set_fmpz(to._padic(), from._fmpz(), to._ctx()))
533 FLINT_DEFINE_DOIT_COND2(assignment, PADICXX_COND_T, FMPQXX_COND_S,
534 padic_set_fmpq(to._padic(), from._fmpq(), to._ctx()))
535
536 FLINTXX_DEFINE_CONVERSION_TMP(fmpzxx, padicxx,
537 padic_get_fmpz(to._fmpz(), from._padic(), from._ctx()))
538 FLINTXX_DEFINE_CONVERSION_TMP(fmpqxx, padicxx,
539 padic_get_fmpq(to._fmpq(), from._padic(), from._ctx()))
540
541 FLINTXX_DEFINE_TO_STR(padicxx, padic_get_str(0, from._padic(), from._ctx()))
542
543 FLINTXX_DEFINE_SWAP(padicxx, padic_swap(e1._padic(), e2._padic()))
544
545 FLINTXX_DEFINE_EQUALS(padicxx, padic_equal(e1._padic(), e2._padic()))
546
547 FLINT_DEFINE_UNARY_EXPR_COND(padicxx_unit_op, fmpzxx, PADICXX_COND_S,
548 fmpz_set(to._fmpz(), padic_unit(from._padic())))
549
550 FLINT_DEFINE_PRINT_COND(PADICXX_COND_S,
551 padic_fprint(to, from._padic(), from._ctx()))
552
553
554 FLINT_DEFINE_CBINARY_EXPR_COND2(plus, padicxx, PADICXX_COND_S, PADICXX_COND_S,
555 padic_add(to._padic(), e1._padic(), e2._padic(), to._ctx()))
556 FLINT_DEFINE_BINARY_EXPR_COND2(minus, padicxx, PADICXX_COND_S, PADICXX_COND_S,
557 padic_sub(to._padic(), e1._padic(), e2._padic(), to._ctx()))
558 FLINT_DEFINE_CBINARY_EXPR_COND2(times, padicxx, PADICXX_COND_S, PADICXX_COND_S,
559 padic_mul(to._padic(), e1._padic(), e2._padic(), to._ctx()))
560 FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, padicxx, PADICXX_COND_S, PADICXX_COND_S,
561 padic_div(to._padic(), e1._padic(), e2._padic(), to._ctx()))
562 FLINT_DEFINE_BINARY_EXPR_COND2(shift, padicxx, PADICXX_COND_S,
563 traits::fits_into_slong,
564 padic_shift(to._padic(), e1._padic(), e2, to._ctx()))
565
566 FLINT_DEFINE_UNARY_EXPR_COND(negate, padicxx, PADICXX_COND_S,
567 padic_neg(to._padic(), from._padic(), to._ctx()))
568
569 // lazy functions
570 FLINT_DEFINE_UNARY_EXPR_COND(sqrt_op, padicxx, PADICXX_COND_S,
571 execution_check(
572 padic_sqrt(to._padic(), from._padic(), to._ctx()), "sqrt", "padic"))
573 FLINT_DEFINE_BINARY_EXPR_COND2(pow_op, padicxx, PADICXX_COND_S,
574 traits::fits_into_slong,
575 padic_pow_si(to._padic(), e1._padic(), e2, to._ctx()))
576 FLINT_DEFINE_UNARY_EXPR_COND(exp_op, padicxx, PADICXX_COND_S,
577 execution_check(
578 padic_exp(to._padic(), from._padic(), to._ctx()), "exp", "padic"))
579 FLINT_DEFINE_UNARY_EXPR_COND(exp_balanced_op, padicxx, PADICXX_COND_S,
580 execution_check(padic_exp_balanced(
581 to._padic(), from._padic(), to._ctx()), "exp_balanced", "padic"))
582 FLINT_DEFINE_UNARY_EXPR_COND(exp_rectangular_op, padicxx, PADICXX_COND_S,
583 execution_check(padic_exp_rectangular(
584 to._padic(), from._padic(), to._ctx()),
585 "exp_rectangular", "padic"))
586 FLINT_DEFINE_UNARY_EXPR_COND(log_op, padicxx, PADICXX_COND_S,
587 execution_check(
588 padic_log(to._padic(), from._padic(), to._ctx()), "log", "padic"))
589 FLINT_DEFINE_UNARY_EXPR_COND(log_rectangular_op, padicxx, PADICXX_COND_S,
590 execution_check(padic_log_rectangular(
591 to._padic(), from._padic(), to._ctx()),
592 "log_rectangular", "padic"))
593 FLINT_DEFINE_UNARY_EXPR_COND(log_balanced_op, padicxx, PADICXX_COND_S,
594 execution_check(padic_log_balanced(
595 to._padic(), from._padic(), to._ctx()), "log_balanced", "padic"))
596 FLINT_DEFINE_UNARY_EXPR_COND(log_satoh_op, padicxx, PADICXX_COND_S,
597 execution_check(padic_log_satoh(to._padic(), from._padic(), to._ctx()),
598 "log_satoh", "padic"))
599 FLINT_DEFINE_UNARY_EXPR_COND(inv_op, padicxx, PADICXX_COND_S,
600 padic_inv(to._padic(), from._padic(), to._ctx()))
601 FLINT_DEFINE_UNARY_EXPR_COND(teichmuller_op, padicxx, PADICXX_COND_S,
602 padic_teichmuller(to._padic(), from._padic(), to._ctx()))
603
604 FLINT_DEFINE_BINARY_EXPR_COND2(padic_val_fac_op, fmpzxx,
605 FMPZXX_COND_S, FMPZXX_COND_S,
606 ::padic_val_fac(to._fmpz(), e1._fmpz(), e2._fmpz()))
607 } // rules
608
609 // immediate version of padic_val_fac
610 template<class Fmpz, class T>
611 inline typename mp::enable_if<mp::and_<
612 traits::is_unsigned_integer<T>, traits::is_fmpzxx<Fmpz> >,
613 ulong>::type
614 padic_val_fac(T n, const Fmpz& p)
615 {
616 return padic_val_fac_ui(n, p._fmpz());
617 }
618 } // flint
619
620 #endif
621