/*
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