/* Copyright (C) 2013 Tom Bachmann This file is part of FLINT. FLINT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ // TODO reference types // TODO addmul // TODO document nmod_vecxx #ifndef NMOD_VECXX_H #define NMOD_VECXX_H #include #include "nmod_vec.h" // TODO reduce dependencies? #include "fmpzxx.h" #include "fmpqxx.h" #include "flintxx/expression.h" #include "flintxx/evaluation_tools.h" #include "flintxx/flint_classes.h" #include "flintxx/stdmath.h" #include "flintxx/vector.h" namespace flint { ////////////////////////////////////////////////////////////////////////////// // NMOD CLASS AND RULES ////////////////////////////////////////////////////////////////////////////// class nmodxx_ctx { private: nmod_t nmod; public: const nmod_t& _nmod() const {return nmod;} explicit nmodxx_ctx(mp_limb_t n) {nmod_init(&nmod, n);} // no destruction necessary bool operator==(const nmodxx_ctx& o) const {return nmod.n == o.nmod.n;} mp_limb_t n() const {return nmod.n;} }; class nmodxx_ctx_srcref { private: const nmod_t& nmod; nmodxx_ctx_srcref(const nmod_t& nm) : nmod(nm) {} public: const nmod_t& _nmod() const {return nmod;} nmodxx_ctx_srcref(const nmodxx_ctx& c) : nmod(c._nmod()) {} static nmodxx_ctx_srcref make(const nmod_t& nm) {return nmodxx_ctx_srcref(nm);} bool operator==(const nmodxx_ctx_srcref& o) const {return nmod.n == o.nmod.n;} mp_limb_t n() const {return nmod.n;} }; namespace detail { struct nmodxx_fake_c_type { }; } // detail template class nmodxx_expression : public expression, Operation, Data> { public: typedef expression, Operation, Data> base_t; FLINTXX_DEFINE_BASICS(nmodxx_expression) FLINTXX_DEFINE_CTORS(nmodxx_expression) FLINTXX_DEFINE_C_REF(nmodxx_expression, detail::nmodxx_fake_c_type, _limb) // static functions for nmodxx static nmodxx_expression make_nored(mp_limb_t n, nmodxx_ctx_srcref c) { return nmodxx_expression(Data::make_nored(n, c)); } static nmodxx_expression red(mp_limb_t n, nmodxx_ctx_srcref c) { nmodxx_expression res = make_nored(n, c); res.reduce(); return res; } template static typename mp::enable_if< traits::is_fmpzxx, nmodxx_expression>::type red( const Fmpz& n, nmodxx_ctx_srcref c) { return make_nored((n % c.n()).template to(), c); } template static typename mp::enable_if< traits::is_fmpqxx, nmodxx_expression>::type red( const Fmpq& n, nmodxx_ctx_srcref c) { return make_nored((n % fmpzxx(c.n())).template to(), c); } // TODO more // only makes sense on immediates nmodxx_ctx_srcref _ctx() const {return this->_data().ctx;} const nmod_t& _nmod() const {return this->_data().ctx._nmod();} void reduce() {NMOD_RED(_limb(), _limb(), _nmod());} void set_nored(mp_limb_t n) {this->_data().inner = n;} nmodxx_ctx_srcref estimate_ctx() const; evaluated_t create_temporary() const { return evaluated_t(estimate_ctx()); } FLINTXX_DEFINE_MEMBER_BINOP(pow) FLINTXX_DEFINE_MEMBER_UNOP(inv) }; namespace detail { struct nmodxx_data; } // detail typedef nmodxx_expression nmodxx; typedef nmodxx_expression > nmodxx_ref; typedef nmodxx_expression > nmodxx_srcref; namespace flint_classes { template struct ref_data { typedef void IS_REF_OR_CREF; typedef Nmod wrapped_t; typedef mp_limb_t& data_ref_t; typedef const mp_limb_t& data_srcref_t; mp_limb_t& inner; nmodxx_ctx_srcref ctx; ref_data(Nmod& o) : inner(o._data().inner), ctx(o._data().ctx) {} static ref_data make(mp_limb_t& f, nmodxx_ctx_srcref ctx) { return ref_data(f, ctx); } private: ref_data(mp_limb_t& fp, nmodxx_ctx_srcref c) : inner(fp), ctx(c) {} }; template struct srcref_data { typedef void IS_REF_OR_CREF; typedef Nmod wrapped_t; typedef const mp_limb_t& data_ref_t; typedef const mp_limb_t& data_srcref_t; const mp_limb_t& inner; nmodxx_ctx_srcref ctx; srcref_data(const Nmod& o) : inner(o._data().inner), ctx(o._data().ctx) {} srcref_data(Ref o) : inner(o._data().inner) {} static srcref_data make(const mp_limb_t& f, nmodxx_ctx_srcref ctx) { return srcref_data(f, ctx); } private: srcref_data(const mp_limb_t& fp, nmodxx_ctx_srcref c) : inner(fp), ctx(c) {} }; } // flint_classes namespace detail { struct nmodxx_data { nmodxx_ctx_srcref ctx; mp_limb_t inner; typedef mp_limb_t& data_ref_t; typedef const mp_limb_t& data_srcref_t; nmodxx_data(nmodxx_ctx_srcref c) : ctx(c), inner(0) {} private: nmodxx_data(mp_limb_t n, nmodxx_ctx_srcref c) : ctx(c), inner(n) {} public: static nmodxx_data make_nored(mp_limb_t n, nmodxx_ctx_srcref c) { return nmodxx_data(n, c); } nmodxx_data(const nmodxx_srcref& r) : ctx(r.estimate_ctx()), inner(r._limb()) {} }; } // detail // Temporary merging isn't really any use here. On the other hand, it does // not seem to hurt. Let's leave this for now. -- Tom Bachmann (15/10/2013) #if 0 namespace traits { template<> struct use_temporary_merging : mp::false_ { }; } // traits #endif namespace traits { template struct has_nmodxx_ctx : mp::false_ { }; template<> struct has_nmodxx_ctx : mp::true_ { }; template<> struct has_nmodxx_ctx : mp::true_ { }; template<> struct has_nmodxx_ctx : mp::true_ { }; } // traits namespace detail { struct has_nmodxx_ctx_predicate { template struct type : traits::has_nmodxx_ctx { }; }; // XXX this is needed for vectors ... template struct get_nmodxx_ctx { static nmodxx_ctx_srcref get(const T& t) {return t._ctx();} }; template nmodxx_ctx_srcref get_nmodxx_ctx_func(const T& t) { return get_nmodxx_ctx::get(t); } } // detail namespace tools { template nmodxx_ctx_srcref find_nmodxx_ctx(const Expr& e) { return detail::get_nmodxx_ctx_func( tools::find_subexpr(e)); } } // tools template inline nmodxx_ctx_srcref nmodxx_expression::estimate_ctx() const { return tools::find_nmodxx_ctx(*this); } namespace traits { template struct is_nmodxx : mp::or_< traits::is_T_expr, flint_classes::is_source > { }; } // traits namespace rules { #define NMODXX_COND_S FLINTXX_COND_S(nmodxx) #define NMODXX_COND_T FLINTXX_COND_T(nmodxx) #define NMODXX_DEFINE_INSTANTIATE_TEMPORARIES(Classname) \ template \ struct use_default_temporary_instantiation : mp::false_ { }; \ template \ struct instantiate_temporaries \ { \ static Classname get(const Expr& e) \ { \ return Classname(tools::find_nmodxx_ctx(e)); \ } \ }; // This is in order to make temporary allocation work even if there is no // immediate subexpression - c/f test_temporaries NMODXX_DEFINE_INSTANTIATE_TEMPORARIES(nmodxx) FLINTXX_DEFINE_EQUALS(nmodxx, e1._limb() == e2._limb()) FLINT_DEFINE_GET_COND(conversion, mp_limb_t, NMODXX_COND_S, from._limb()) template struct to_string >::type> { static std::string get(const Nmod& i, int base /* ignored */) { std::ostringstream oss; oss << i._limb() << " mod " << i._nmod().n; return oss.str(); } }; FLINT_DEFINE_DOIT_COND2(assignment, NMODXX_COND_T, NMODXX_COND_S, to._limb() = from._limb()) FLINT_DEFINE_CBINARY_EXPR_COND2(plus, nmodxx, NMODXX_COND_S, NMODXX_COND_S, to.set_nored(nmod_add(e1._limb(), e2._limb(), to._nmod()))) FLINT_DEFINE_CBINARY_EXPR_COND2(times, nmodxx, NMODXX_COND_S, NMODXX_COND_S, to.set_nored(nmod_mul(e1._limb(), e2._limb(), to._nmod()))) FLINT_DEFINE_BINARY_EXPR_COND2(minus, nmodxx, NMODXX_COND_S, NMODXX_COND_S, to.set_nored(nmod_sub(e1._limb(), e2._limb(), to._nmod()))) FLINT_DEFINE_BINARY_EXPR_COND2(divided_by, nmodxx, NMODXX_COND_S, NMODXX_COND_S, to.set_nored(nmod_div(e1._limb(), e2._limb(), to._nmod()))) FLINT_DEFINE_UNARY_EXPR_COND(negate, nmodxx, NMODXX_COND_S, to.set_nored(nmod_neg(from._limb(), to._nmod()))) FLINT_DEFINE_UNARY_EXPR_COND(inv_op, nmodxx, NMODXX_COND_S, to.set_nored(nmod_inv(from._limb(), to._nmod()))) FLINT_DEFINE_BINARY_EXPR_COND2(pow_op, nmodxx, NMODXX_COND_S, traits::is_unsigned_integer, to.set_nored(nmod_pow_ui(e1._limb(), e2, to._nmod()))) } ////////////////////////////////////////////////////////////////////////////// // NMOD_VEC CLASS AND RULES ////////////////////////////////////////////////////////////////////////////// namespace detail { struct nmod_vector_data { slong size; mp_limb_t* array; nmodxx_ctx_srcref ctx; nmod_vector_data(slong n, nmodxx_ctx_srcref c) : size(n), array(_nmod_vec_init(n)), ctx(c) {} ~nmod_vector_data() {_nmod_vec_clear(array);} nmod_vector_data(const nmod_vector_data& o) : size(o.size), array(_nmod_vec_init(o.size)), ctx(o.ctx) { _nmod_vec_set(array, o.array, size); } nmodxx_ref at(slong i) {return nmodxx_ref::make(array[i], ctx);} nmodxx_srcref at(slong i) const {return nmodxx_srcref::make(array[i], ctx);} }; struct nmod_vector_traits : wrapped_vector_traits { template static typename Expr::evaluated_t create_temporary(const Expr& e) { return typename Expr::evaluated_t(e.size(), tools::find_nmodxx_ctx(e)); } }; } // detail // TODO would it make more sense to have this have its own class? typedef vector_expression< detail::nmod_vector_traits, operations::immediate, detail::nmod_vector_data> nmod_vecxx; // TODO references namespace traits { template<> struct has_nmodxx_ctx : mp::true_ { }; } // traits namespace detail { template<> struct get_nmodxx_ctx { static nmodxx_ctx_srcref get(const nmod_vecxx& v) { return v._data().ctx; } }; } // detail template<> struct enable_vector_rules : mp::false_ { }; namespace rules { // TODO hack to make code look like references are implemented template struct NMOD_VECXX_COND_S : mp::equal_types { }; #define NMOD_VECXX_COND_T NMOD_VECXX_COND_S // TODO references FLINT_DEFINE_GET(equals, bool, nmod_vecxx, e1.size() == e2.size() && _nmod_vec_equal(e1._data().array, e2._data().array, e1.size())) FLINT_DEFINE_BINARY_EXPR_COND2(plus, nmod_vecxx, NMOD_VECXX_COND_S, NMOD_VECXX_COND_S, _nmod_vec_add(to._data().array, e1._data().array, e2._data().array, to.size(), to._data().ctx._nmod())) // TODO more } // rules } // flint #endif