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