/*============================================================================= This file is part of FLINT. FLINT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. FLINT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with FLINT; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =============================================================================*/ /****************************************************************************** Copyright (C) 2013 Tom Bachmann ******************************************************************************/ #ifndef CXX_PADICXX_H #define CXX_PADICXX_H CXX_PADICXX_H #include // std::max #include #include "padic.h" #include "flintxx/expression.h" #include "flintxx/flint_classes.h" #include "flintxx/flint_exception.h" #include "flintxx/frandxx.h" #include "flintxx/stdmath.h" #include "flintxx/traits.h" #include "flintxx/tuple.h" #include "fmpzxx.h" #include "fmpqxx.h" // TODO check codegen ... // TODO padic_output_prec does not work on non-padic expressions, // is that a problem? namespace flint { // function "declarations" FLINT_DEFINE_UNOP(exp_rectangular) FLINT_DEFINE_UNOP(exp_balanced) FLINT_DEFINE_UNOP(log_rectangular) FLINT_DEFINE_UNOP(log_balanced) FLINT_DEFINE_UNOP(log_satoh) FLINT_DEFINE_UNOP(teichmuller) FLINT_DEFINE_BINOP(padic_val_fac) class padicxx_ctx { private: mutable padic_ctx_t ctx; public: // NB: you must not modify user-visible state of ctx through a constant // instance of padicxx_ctx padic_ctx_t& _ctx() const {return ctx;} // XXX these two are not actually exposed in the C api ... fmpzxx_ref get_p() {return fmpzxx_ref::make(ctx[0].p);} fmpzxx_srcref get_p() const {return fmpzxx_srcref::make(ctx[0].p);} padic_print_mode mode() const {return _ctx()->mode;} padic_print_mode& mode() {return _ctx()->mode;} // TODO more constructors? Should we wrap padic_print_mode? padicxx_ctx(fmpzxx_srcref p, slong min, slong max, padic_print_mode mode) { padic_ctx_init(ctx, p._fmpz(), min, max, mode); } ~padicxx_ctx() {padic_ctx_clear(ctx);} }; class padicxx_ctx_srcref { private: mutable padic_ctx_struct* ctx; padicxx_ctx_srcref(padic_ctx_struct* c) : ctx(c) {} public: // NB: you must not modify user-visible state of ctx through a constant // instance of padicxx_ctx padic_ctx_struct* _ctx() const {return ctx;} // XXX these two are not actually exposed in the C api ... fmpzxx_ref get_p() {return fmpzxx_ref::make(ctx[0].p);} fmpzxx_srcref get_p() const {return fmpzxx_srcref::make(ctx[0].p);} padic_print_mode mode() const {return _ctx()->mode;} padicxx_ctx_srcref(padicxx_ctx& c) : ctx(c._ctx()) {} static padicxx_ctx_srcref make(padic_ctx_struct* c) {return padicxx_ctx_srcref(c);} }; namespace traits { template struct has_padicxx_ctx : mp::false_ { }; template struct is_padic_expr : has_padicxx_ctx::type> { }; } // traits namespace detail { struct has_padicxx_ctx_predicate { template struct type : traits::has_padicxx_ctx { }; }; template struct padicxx_max_prec; template struct padicxx_max_prec >::type> { static slong get(const T& p) {return p.prec();} }; template struct padicxx_max_prec >::type> { static slong get(const T&) {return 0;} }; template struct padicxx_max_prec_h; template struct padicxx_max_prec_h > { static slong get(const tuple& t) { slong p1 = padicxx_max_prec_h::get(t.tail); slong p2 = padicxx_max_prec::type>::get(t.head); return std::max(p1, p2); } }; template<> struct padicxx_max_prec_h { static slong get(empty_tuple) {return 0;} }; template struct padicxx_max_prec, mp::not_ > > >::type> { static slong get(const T& e) {return padicxx_max_prec_h::get(e._data());} }; } // detail namespace tools { template padicxx_ctx_srcref find_padicxx_ctx(const Expr& e) { return tools::find_subexpr(e).get_ctx(); } template slong padic_output_prec(const Expr& e) { return detail::padicxx_max_prec::get(e); } } // tools FLINT_DEFINE_UNOP(padicxx_unit) namespace detail { template struct padic_traits { typedef FLINT_UNOP_BUILD_RETTYPE(padicxx_unit, fmpzxx, Padic) unit_srcref_t; typedef slong prec_ref_t; typedef slong prec_srcref_t; typedef slong val_ref_t; typedef slong val_srcref_t; static slong prec(const Padic& p) {return tools::padic_output_prec(p);} static slong val(const Padic& p) {return padic_val(p.evaluate()._padic());} static unit_srcref_t unit(const Padic& p) {return padicxx_unit(p);} }; } //detail template class padicxx_expression : public expression, Operation, Data> { public: typedef expression, Operation, Data> base_t; FLINTXX_DEFINE_BASICS(padicxx_expression) FLINTXX_DEFINE_CTORS(padicxx_expression) FLINTXX_DEFINE_C_REF(padicxx_expression, padic_struct, _padic) public: typedef detail::padic_traits traits_t; // These only make sense with immediates void reduce() {padic_reduce(_padic(), _ctx());} void set_zero() {padic_zero(_padic());} void set_one() {padic_one(_padic());} #define PADICXX_DEFINE_CTX \ padicxx_ctx_srcref get_ctx() const {return this->_data().ctx;} \ padic_ctx_struct* _ctx() const {return get_ctx()._ctx();} PADICXX_DEFINE_CTX static padicxx_expression zero(padicxx_ctx_srcref ctx) {return padicxx_expression(ctx);} static padicxx_expression zero(padicxx_ctx_srcref ctx, slong N) {return padicxx_expression(ctx, N);} static padicxx_expression one(padicxx_ctx_srcref ctx) { padicxx_expression res(ctx); res.set_one(); return res; } static padicxx_expression one(padicxx_ctx_srcref ctx, slong N) { padicxx_expression res(ctx, N); res.set_one(); return res; } template static padicxx_expression from_QQ(const T& q, padicxx_ctx_srcref ctx, typename mp::enable_if, traits::is_fmpzxx, traits::is_integer > >::type* = 0) { padicxx_expression res(ctx); res = q; return res; } template static padicxx_expression from_QQ(const T& q, padicxx_ctx_srcref ctx, slong N, typename mp::enable_if, traits::is_fmpzxx, traits::is_integer > >::type* = 0) { padicxx_expression res(ctx, N); res = q; return res; } // TODO more? // The above method get_ctx() only works on immediates, i.e. instances of // padicxx. This next one here works on any composite expression which // contains at least one instance of padicxx. Returns the context of one of // those immediate subexpressions. #define PADICXX_DEFINE_ESTIMATE_CTX \ padicxx_ctx_srcref estimate_ctx() const \ { \ return tools::find_padicxx_ctx(*this); \ } PADICXX_DEFINE_ESTIMATE_CTX // Create a temporary. The context will be estimated, and the precision // will be the maximum of all subexpressions. evaluated_t create_temporary() const { return evaluated_t(estimate_ctx(), prec()); } // static methods which only make sense with padicxx static padicxx_expression randtest(frandxx& state, padicxx_ctx_srcref ctx, slong prec = PADIC_DEFAULT_PREC) { padicxx_expression res(ctx, prec); padic_randtest(res._padic(), state._data(), ctx._ctx()); return res; } static padicxx_expression randtest_not_zero(frandxx& state, padicxx_ctx_srcref ctx, slong prec = PADIC_DEFAULT_PREC) { padicxx_expression res(ctx, prec); padic_randtest_not_zero(res._padic(), state._data(), ctx._ctx()); return res; } static padicxx_expression randtest_int(frandxx& state, padicxx_ctx_srcref ctx, slong prec = PADIC_DEFAULT_PREC) { padicxx_expression res(ctx, prec); padic_randtest_int(res._padic(), state._data(), ctx._ctx()); return res; } #define PADICXX_DEFINE_TON \ typename flint_classes::to_srcref::type \ toN(slong N) const \ { \ return flint_classes::to_srcref::type::make( \ this->_data().inner, get_ctx(), N); \ } PADICXX_DEFINE_TON typename traits_t::unit_srcref_t unit() const {return traits_t::unit(*this);} // Compute the maximal precision of all subexpressions #define PADICXX_DEFINE_PREC \ typename traits_t::prec_ref_t prec() {return traits_t::prec(*this);} \ typename traits_t::prec_srcref_t prec() const \ {return traits_t::prec(*this);} PADICXX_DEFINE_PREC #define PADICXX_DEFINE_VAL \ typename traits_t::val_ref_t val() {return traits_t::val(*this);} \ typename traits_t::val_srcref_t val() const \ {return traits_t::val(*this);} PADICXX_DEFINE_VAL // these cause evaluation bool is_zero() const {return padic_is_zero(this->evaluate()._padic());} bool is_one() const {return padic_is_one(this->evaluate()._padic());} // forwarding of lazy functions FLINTXX_DEFINE_MEMBER_UNOP(exp) FLINTXX_DEFINE_MEMBER_UNOP(exp_balanced) FLINTXX_DEFINE_MEMBER_UNOP(exp_rectangular) FLINTXX_DEFINE_MEMBER_UNOP(inv) FLINTXX_DEFINE_MEMBER_UNOP(log) FLINTXX_DEFINE_MEMBER_UNOP(log_balanced) FLINTXX_DEFINE_MEMBER_UNOP(log_satoh) FLINTXX_DEFINE_MEMBER_UNOP(sqrt) FLINTXX_DEFINE_MEMBER_UNOP(teichmuller) FLINTXX_DEFINE_MEMBER_BINOP(pow) }; #define PADICXX_DEFINE_STD \ PADICXX_DEFINE_CTX \ PADICXX_DEFINE_ESTIMATE_CTX \ PADICXX_DEFINE_TON \ PADICXX_DEFINE_PREC \ PADICXX_DEFINE_VAL namespace detail { struct padic_data; } typedef padicxx_expression padicxx; typedef padicxx_expression > padicxx_ref; typedef padicxx_expression > padicxx_srcref; namespace traits { template<> struct has_padicxx_ctx : mp::true_ { }; template<> struct has_padicxx_ctx : mp::true_ { }; template<> struct has_padicxx_ctx : mp::true_ { }; template struct is_padicxx : flint_classes::is_Base { }; } // traits namespace detail { template<> struct padic_traits { typedef fmpzxx_srcref unit_srcref_t; template static fmpzxx_srcref unit(const Poly& p) {return fmpzxx_srcref::make(padic_unit(p._padic()));} typedef slong prec_ref_t; typedef slong prec_srcref_t; typedef slong val_ref_t; typedef slong val_srcref_t; template static slong prec(P p) {return p._data().N;} template static slong val(P p) {return padic_val(p._padic());} }; template<> struct padic_traits : padic_traits { typedef slong& prec_ref_t; typedef slong& val_ref_t; template static slong& prec(P& p) {return padic_prec(p._padic());} template static slong prec(const P& p) {return padic_prec(p._padic());} template static slong& val(P& p) {return padic_val(p._padic());} template static slong val(const P& p) {return padic_val(p._padic());} }; template<> struct padic_traits : padic_traits { }; template struct faketemplate : mp::enable_if > { }; } // detail // NB: usually, the "padicname" parameter would not be necessary. We would // leave that as a template, identifying the type by structname alone, and // conveniently delay all instantiations. Unfortunately qadic and padic_poly // have the same structname, so we cannot do this. // Instead we pass in the class name explicitly, and delay relevant functions // by hand... #define PADICXX_DEFINE_REF_STRUCTS_(padicname, structname, precname, ctxtype) \ namespace flint_classes { \ template<> \ struct ref_data \ { \ typedef void IS_REF_OR_CREF; \ typedef padicname wrapped_t; \ \ typedef structname* data_ref_t; \ typedef const structname* data_srcref_t; \ \ structname* inner; \ ctxtype ctx; \ \ template \ ref_data(T& o, typename detail::faketemplate::type* = 0) \ : inner(o._data().inner), ctx(o._data().ctx) {} \ \ static ref_data make(structname* f, ctxtype ctx) \ { \ return ref_data(f, ctx); \ } \ \ private: \ ref_data(structname* fp, ctxtype c) : inner(fp), ctx(c) {} \ }; \ \ template \ struct srcref_data \ { \ typedef void IS_REF_OR_CREF; \ typedef padicname wrapped_t; \ \ typedef const structname* data_ref_t; \ typedef const structname* data_srcref_t; \ \ const structname* inner; \ ctxtype ctx; \ slong N; \ \ template \ srcref_data(const T& o, \ typename detail::faketemplate::type* = 0) \ : inner(o._data().inner), ctx(o._data().ctx), N(o.prec()) {} \ template \ srcref_data(T o, typename detail::faketemplate::type* = 0) \ : inner(o._data().inner), ctx(o._data().ctx), N(o.prec()) {} \ \ static srcref_data make(const structname* f, ctxtype ctx) \ { \ return srcref_data(f, ctx); \ } \ static srcref_data make(const structname* f, ctxtype ctx, \ slong N) \ { \ return srcref_data(f, ctx, N); \ } \ \ private: \ srcref_data(const structname* fp, ctxtype c) \ : inner(fp), ctx(c), N(precname(fp)) {} \ srcref_data(const structname* fp, ctxtype c, slong n) \ : inner(fp), ctx(c), N(n) {} \ }; \ } /* flint_classes */ #define PADICXX_DEFINE_REF_STRUCTS(padicname, structname, precname) \ PADICXX_DEFINE_REF_STRUCTS_(padicname, structname, precname, padicxx_ctx_srcref) PADICXX_DEFINE_REF_STRUCTS(padicxx, padic_struct, padic_prec) namespace detail { struct padic_data { typedef padic_t& data_ref_t; typedef const padic_t& data_srcref_t; padicxx_ctx_srcref ctx; padic_t inner; padic_data(padicxx_ctx_srcref c) : ctx(c) { padic_init(inner); } padic_data(padicxx_ctx_srcref c, slong N) : ctx(c) { padic_init2(inner, N); } padic_data(const padic_data& o) : ctx(o.ctx) { padic_init2(inner, padic_prec(o.inner)); padic_set(inner, o.inner, ctx._ctx()); } ~padic_data() {padic_clear(inner);} padic_data(padicxx_srcref c) : ctx(c.get_ctx()) { padic_init2(inner, c.prec()); padic_set(inner, c._padic(), ctx._ctx()); } }; } // detail #define PADICXX_COND_S FLINTXX_COND_S(padicxx) #define PADICXX_COND_T FLINTXX_COND_T(padicxx) namespace rules { FLINT_DEFINE_DOIT_COND2(assignment, PADICXX_COND_T, PADICXX_COND_S, padic_set(to._padic(), from._padic(), to._ctx())) FLINT_DEFINE_DOIT_COND2(assignment, PADICXX_COND_T, traits::is_signed_integer, padic_set_si(to._padic(), from, to._ctx())) FLINT_DEFINE_DOIT_COND2(assignment, PADICXX_COND_T, traits::is_unsigned_integer, padic_set_ui(to._padic(), from, to._ctx())) FLINT_DEFINE_DOIT_COND2(assignment, PADICXX_COND_T, FMPZXX_COND_S, padic_set_fmpz(to._padic(), from._fmpz(), to._ctx())) FLINT_DEFINE_DOIT_COND2(assignment, PADICXX_COND_T, FMPQXX_COND_S, padic_set_fmpq(to._padic(), from._fmpq(), to._ctx())) FLINTXX_DEFINE_CONVERSION_TMP(fmpzxx, padicxx, padic_get_fmpz(to._fmpz(), from._padic(), from._ctx())) FLINTXX_DEFINE_CONVERSION_TMP(fmpqxx, padicxx, padic_get_fmpq(to._fmpq(), from._padic(), from._ctx())) FLINTXX_DEFINE_TO_STR(padicxx, padic_get_str(0, from._padic(), from._ctx())) FLINTXX_DEFINE_SWAP(padicxx, padic_swap(e1._padic(), e2._padic())) FLINTXX_DEFINE_EQUALS(padicxx, padic_equal(e1._padic(), e2._padic())) FLINT_DEFINE_UNARY_EXPR_COND(padicxx_unit_op, fmpzxx, PADICXX_COND_S, fmpz_set(to._fmpz(), padic_unit(from._padic()))) FLINT_DEFINE_PRINT_COND(PADICXX_COND_S, padic_fprint(to, from._padic(), from._ctx())) FLINT_DEFINE_CBINARY_EXPR_COND2(plus, padicxx, PADICXX_COND_S, PADICXX_COND_S, padic_add(to._padic(), e1._padic(), e2._padic(), to._ctx())) FLINT_DEFINE_BINARY_EXPR_COND2(minus, padicxx, PADICXX_COND_S, PADICXX_COND_S, padic_sub(to._padic(), e1._padic(), e2._padic(), to._ctx())) FLINT_DEFINE_CBINARY_EXPR_COND2(times, padicxx, PADICXX_COND_S, PADICXX_COND_S, padic_mul(to._padic(), e1._padic(), e2._padic(), to._ctx())) FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, padicxx, PADICXX_COND_S, PADICXX_COND_S, padic_div(to._padic(), e1._padic(), e2._padic(), to._ctx())) FLINT_DEFINE_BINARY_EXPR_COND2(shift, padicxx, PADICXX_COND_S, traits::fits_into_slong, padic_shift(to._padic(), e1._padic(), e2, to._ctx())) FLINT_DEFINE_UNARY_EXPR_COND(negate, padicxx, PADICXX_COND_S, padic_neg(to._padic(), from._padic(), to._ctx())) // lazy functions FLINT_DEFINE_UNARY_EXPR_COND(sqrt_op, padicxx, PADICXX_COND_S, execution_check( padic_sqrt(to._padic(), from._padic(), to._ctx()), "sqrt", "padic")) FLINT_DEFINE_BINARY_EXPR_COND2(pow_op, padicxx, PADICXX_COND_S, traits::fits_into_slong, padic_pow_si(to._padic(), e1._padic(), e2, to._ctx())) FLINT_DEFINE_UNARY_EXPR_COND(exp_op, padicxx, PADICXX_COND_S, execution_check( padic_exp(to._padic(), from._padic(), to._ctx()), "exp", "padic")) FLINT_DEFINE_UNARY_EXPR_COND(exp_balanced_op, padicxx, PADICXX_COND_S, execution_check(padic_exp_balanced( to._padic(), from._padic(), to._ctx()), "exp_balanced", "padic")) FLINT_DEFINE_UNARY_EXPR_COND(exp_rectangular_op, padicxx, PADICXX_COND_S, execution_check(padic_exp_rectangular( to._padic(), from._padic(), to._ctx()), "exp_rectangular", "padic")) FLINT_DEFINE_UNARY_EXPR_COND(log_op, padicxx, PADICXX_COND_S, execution_check( padic_log(to._padic(), from._padic(), to._ctx()), "log", "padic")) FLINT_DEFINE_UNARY_EXPR_COND(log_rectangular_op, padicxx, PADICXX_COND_S, execution_check(padic_log_rectangular( to._padic(), from._padic(), to._ctx()), "log_rectangular", "padic")) FLINT_DEFINE_UNARY_EXPR_COND(log_balanced_op, padicxx, PADICXX_COND_S, execution_check(padic_log_balanced( to._padic(), from._padic(), to._ctx()), "log_balanced", "padic")) FLINT_DEFINE_UNARY_EXPR_COND(log_satoh_op, padicxx, PADICXX_COND_S, execution_check(padic_log_satoh(to._padic(), from._padic(), to._ctx()), "log_satoh", "padic")) FLINT_DEFINE_UNARY_EXPR_COND(inv_op, padicxx, PADICXX_COND_S, padic_inv(to._padic(), from._padic(), to._ctx())) FLINT_DEFINE_UNARY_EXPR_COND(teichmuller_op, padicxx, PADICXX_COND_S, padic_teichmuller(to._padic(), from._padic(), to._ctx())) FLINT_DEFINE_BINARY_EXPR_COND2(padic_val_fac_op, fmpzxx, FMPZXX_COND_S, FMPZXX_COND_S, ::padic_val_fac(to._fmpz(), e1._fmpz(), e2._fmpz())) } // rules // immediate version of padic_val_fac template inline typename mp::enable_if, traits::is_fmpzxx >, ulong>::type padic_val_fac(T n, const Fmpz& p) { return padic_val_fac_ui(n, p._fmpz()); } } // flint #endif