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 QADICXX_H
13 #define QADICXX_H
14 
15 #include <algorithm> // std::max
16 
17 #include "qadic.h"
18 
19 #include "flintxx/expression.h"
20 #include "flintxx/flint_classes.h"
21 #include "flintxx/matrix.h" // trace ...
22 
23 #include "padicxx.h"
24 
25 namespace flint {
26 FLINT_DEFINE_BINOP(frobenius)
FLINT_DEFINE_UNOP(norm)27 FLINT_DEFINE_UNOP(norm)
28 FLINT_DEFINE_UNOP(norm_analytic)
29 FLINT_DEFINE_UNOP(norm_resultant)
30 
31 class qadicxx_ctx
32 {
33 private:
34     mutable qadic_ctx_t ctx;
35 
36 public:
37     // NB: you must not modify user-visible state of ctx through a constant
38     // instance of qadicxx_ctx
39     qadic_ctx_t& _ctx() const {return ctx;}
40     padicxx_ctx_srcref pctx() const
41         {return padicxx_ctx_srcref::make(&ctx->pctx);}
42 
43     // TODO more constructors? Should we wrap padic_print_mode?
44     qadicxx_ctx(fmpzxx_srcref p, slong d, slong min, slong max,
45         padic_print_mode mode, const char* var = "x")
46     {
47         qadic_ctx_init_conway(ctx, p._fmpz(), d, min, max, var, mode);
48     }
49 
50     ~qadicxx_ctx() {qadic_ctx_clear(ctx);}
51 };
52 
print(const qadicxx_ctx & c)53 inline void print(const qadicxx_ctx& c)
54 {
55     qadic_ctx_print(c._ctx());
56 }
57 
58 namespace traits {
59 template<class T> struct has_qadicxx_ctx : mp::false_ { };
60 
61 template<class T> struct is_qadic_expr
62     : has_qadicxx_ctx<typename tools::evaluation_helper<T>::type> { };
63 } // traits
64 
65 namespace detail {
66 struct has_qadicxx_ctx_predicate
67 {
68     template<class T> struct type : traits::has_qadicxx_ctx<T> { };
69 };
70 } // detail
71 
72 namespace tools {
73 template<class Expr>
find_qadicxx_ctx(const Expr & e)74 const qadicxx_ctx& find_qadicxx_ctx(const Expr& e)
75 {
76     return tools::find_subexpr<detail::has_qadicxx_ctx_predicate>(e).get_qctx();
77 }
78 } // tools
79 
80 namespace detail {
81 template<class Qadic>
82 struct qadic_traits
83 {
precqadic_traits84     static slong prec(const Qadic& q) {return tools::padic_output_prec(q);}
85 };
86 } // detail
87 
88 template<class Operation, class Data>
89 class qadicxx_expression
90     : public expression<derived_wrapper<qadicxx_expression>, Operation, Data>
91 {
92 public:
93     typedef expression<derived_wrapper< ::flint::qadicxx_expression>,
94               Operation, Data> base_t;
95 
96     FLINTXX_DEFINE_BASICS(qadicxx_expression)
97     FLINTXX_DEFINE_CTORS(qadicxx_expression)
98     FLINTXX_DEFINE_C_REF(qadicxx_expression, qadic_struct, _qadic)
99 
100     typedef detail::qadic_traits<qadicxx_expression> traits_t;
101 
102     // These only make sense with immediates
reduce()103     void reduce() {qadic_reduce(_qadic(), _ctx());}
set_zero()104     void set_zero() {qadic_zero(_qadic());}
set_one()105     void set_one() {qadic_one(_qadic());}
set_gen()106     void set_gen() {qadic_gen(_qadic(), _ctx());}
107 
get_qctx()108     const qadicxx_ctx& get_qctx() const {return this->_data().ctx;}
get_ctx()109     padicxx_ctx_srcref get_ctx() const {return get_qctx().pctx();}
_ctx()110     qadic_ctx_t& _ctx() const {return get_qctx()._ctx();}
111 
112     // these only make sense with qadicxx
zero(const qadicxx_ctx & ctx)113     static qadicxx_expression zero(const qadicxx_ctx& ctx)
114         {return qadicxx_expression(ctx);}
zero(const qadicxx_ctx & ctx,slong N)115     static qadicxx_expression zero(const qadicxx_ctx& ctx, slong N)
116         {return qadicxx_expression(ctx, N);}
one(const qadicxx_ctx & ctx)117     static qadicxx_expression one(const qadicxx_ctx& ctx)
118     {
119         qadicxx_expression res(ctx);
120         res.set_one();
121         return res;
122     }
one(const qadicxx_ctx & ctx,slong N)123     static qadicxx_expression one(const qadicxx_ctx& ctx, slong N)
124     {
125         qadicxx_expression res(ctx, N);
126         res.set_one();
127         return res;
128     }
gen(const qadicxx_ctx & ctx)129     static qadicxx_expression gen(const qadicxx_ctx& ctx)
130     {
131         qadicxx_expression res(ctx);
132         res.set_gen();
133         return res;
134     }
gen(const qadicxx_ctx & ctx,slong N)135     static qadicxx_expression gen(const qadicxx_ctx& ctx, slong N)
136     {
137         qadicxx_expression res(ctx, N);
138         res.set_gen();
139         return res;
140     }
141 
142     template<class Padic>
143     static qadicxx_expression from_ground(const qadicxx_ctx& ctx,
144             const Padic& p,
145             typename mp::enable_if<traits::is_padicxx<Padic> >::type* = 0)
146     {
147         qadicxx_expression res(ctx);
148         res = p;
149         return res;
150     }
151 
152     template<class Padic>
153     static qadicxx_expression from_ground(const qadicxx_ctx& ctx, slong N,
154             const Padic& p,
155             typename mp::enable_if<traits::is_padicxx<Padic> >::type* = 0)
156     {
157         qadicxx_expression res(ctx, N);
158         res = p;
159         return res;
160     }
161 
162     static qadicxx_expression randtest(frandxx& state,
163             const qadicxx_ctx& ctx, slong prec = PADIC_DEFAULT_PREC)
164     {
165         qadicxx_expression res(ctx, prec);
166         qadic_randtest(res._qadic(), state._data(), ctx._ctx());
167         return res;
168     }
169     static qadicxx_expression randtest_not_zero(frandxx& state,
170             const qadicxx_ctx& ctx, slong prec = PADIC_DEFAULT_PREC)
171     {
172         qadicxx_expression res(ctx, prec);
173         qadic_randtest_not_zero(res._qadic(), state._data(), ctx._ctx());
174         return res;
175     }
176     static qadicxx_expression randtest_val(frandxx& state,
177             slong val, const qadicxx_ctx& ctx, slong prec = PADIC_DEFAULT_PREC)
178     {
179         qadicxx_expression res(ctx, prec);
180         qadic_randtest_val(res._qadic(), state._data(), val, ctx._ctx());
181         return res;
182     }
183     static qadicxx_expression randtest_int(frandxx& state,
184             const qadicxx_ctx& ctx, slong prec = PADIC_DEFAULT_PREC)
185     {
186         qadicxx_expression res(ctx, prec);
187         qadic_randtest_int(res._qadic(), state._data(), ctx._ctx());
188         return res;
189     }
190 
estimate_ctx()191     const qadicxx_ctx& estimate_ctx() const
192     {
193         return tools::find_qadicxx_ctx(*this);
194     }
195 
196     // Create a temporary. The context will be estimated, and the precision
197     // will be the maximum of all subexpressions.
create_temporary()198     evaluated_t create_temporary() const
199     {
200         return evaluated_t(estimate_ctx(), prec());
201     }
202 
203     // TODO randomisation
204 
205     typename flint_classes::to_srcref<typename base_t::derived_t>::type
toN(slong N)206     toN(slong N) const
207     {
208         return flint_classes::to_srcref<typename base_t::derived_t>::type::make(
209                 this->_data().inner, get_qctx(), N);
210     }
211 
prec()212     slong prec () const {return traits_t::prec(*this);}
213 
214     // these cause evaluation
val()215     slong val() const {return qadic_val(this->evaluate()._qadic());}
is_zero()216     bool is_zero() const {return qadic_is_zero(this->evaluate()._qadic());}
is_one()217     bool is_one() const {return qadic_is_one(this->evaluate()._qadic());}
218 
219     // forwarding of lazy functions
220     FLINTXX_DEFINE_MEMBER_BINOP(frobenius)
221     FLINTXX_DEFINE_MEMBER_BINOP(pow)
222     FLINTXX_DEFINE_MEMBER_UNOP(exp)
223     FLINTXX_DEFINE_MEMBER_UNOP(exp_balanced)
224     FLINTXX_DEFINE_MEMBER_UNOP(exp_rectangular)
225     FLINTXX_DEFINE_MEMBER_UNOP(inv)
226     FLINTXX_DEFINE_MEMBER_UNOP(log)
227     FLINTXX_DEFINE_MEMBER_UNOP(log_balanced)
228     FLINTXX_DEFINE_MEMBER_UNOP(teichmuller)
229 
230     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(padicxx, trace)
231     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(padicxx, norm)
232     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(padicxx, norm_analytic)
233     FLINTXX_DEFINE_MEMBER_UNOP_RTYPE(padicxx, norm_resultant)
234 };
235 
236 namespace detail {
237 struct qadic_data;
238 }
239 
240 typedef qadicxx_expression<operations::immediate, detail::qadic_data> qadicxx;
241 typedef qadicxx_expression<operations::immediate,
242             flint_classes::ref_data<qadicxx, qadic_struct> > qadicxx_ref;
243 typedef qadicxx_expression<operations::immediate, flint_classes::srcref_data<
244     qadicxx, qadicxx_ref, qadic_struct> > qadicxx_srcref;
245 
246 namespace traits {
247 template<> struct has_padicxx_ctx<qadicxx> : mp::true_ { };
248 template<> struct has_padicxx_ctx<qadicxx_ref> : mp::true_ { };
249 template<> struct has_padicxx_ctx<qadicxx_srcref> : mp::true_ { };
250 template<> struct has_qadicxx_ctx<qadicxx> : mp::true_ { };
251 template<> struct has_qadicxx_ctx<qadicxx_ref> : mp::true_ { };
252 template<> struct has_qadicxx_ctx<qadicxx_srcref> : mp::true_ { };
253 
254 template<class T> struct is_qadicxx : flint_classes::is_Base<padicxx, T> { };
255 } // traits
256 
257 namespace detail {
258 template<>
259 struct qadic_traits<qadicxx_srcref>
260 {
261     template<class Q>
262     static slong prec(const Q& q) {return q._data().N;}
263 };
264 template<>
265 struct qadic_traits<qadicxx_ref>
266 {
267     template<class Q>
268     static slong prec(const Q& q) {return qadic_prec(q._qadic());}
269 };
270 template<> struct qadic_traits<qadicxx> : qadic_traits<qadicxx_ref> { };
271 }
272 
273 PADICXX_DEFINE_REF_STRUCTS_(qadicxx, qadic_struct, qadic_prec, const qadicxx_ctx&)
274 
275 namespace detail {
276 struct qadic_data
277 {
278     typedef qadic_t& data_ref_t;
279     typedef const qadic_t& data_srcref_t;
280 
281     const qadicxx_ctx& ctx;
282     qadic_t inner;
283 
284     qadic_data(const qadicxx_ctx& c)
285         : ctx(c)
286     {
287         qadic_init(inner);
288     }
289 
290     qadic_data(const qadicxx_ctx& c, slong N)
291         : ctx(c)
292     {
293         qadic_init2(inner, N);
294     }
295 
296     qadic_data(const qadic_data& o)
297         : ctx(o.ctx)
298     {
299         qadic_init2(inner, qadic_prec(o.inner));
300         qadic_set(inner, o.inner, ctx._ctx());
301     }
302 
303     ~qadic_data() {qadic_clear(inner);}
304 
305     qadic_data(qadicxx_srcref c)
306         : ctx(c.get_qctx())
307     {
308         qadic_init2(inner, c.prec());
309         qadic_set(inner, c._qadic(), ctx._ctx());
310     }
311 };
312 } // detail
313 
314 #define QADICXX_COND_S FLINTXX_COND_S(qadicxx)
315 #define QADICXX_COND_T FLINTXX_COND_T(qadicxx)
316 
317 namespace rules {
318 FLINT_DEFINE_DOIT_COND2(assignment, QADICXX_COND_T, QADICXX_COND_S,
319         qadic_set(to._qadic(), from._qadic(), to._ctx()))
320 
321 FLINT_DEFINE_DOIT_COND2(assignment, QADICXX_COND_T, traits::is_unsigned_integer,
322         qadic_set_ui(to._qadic(), from, to._ctx()))
323 FLINT_DEFINE_DOIT_COND2(assignment, QADICXX_COND_T, PADICXX_COND_S,
324         padic_poly_set_padic(to._qadic(), from._padic(), from._ctx()))
325 
326 FLINT_DEFINE_PRINT_PRETTY_COND(QADICXX_COND_S,
327         qadic_fprint_pretty(to, from._qadic(), from._ctx()))
328 
329 template<class T>
330 struct conversion<padicxx, T,
331     typename mp::enable_if< QADICXX_COND_S<T> >::type>
332 {
333     static padicxx get(const T& from)
334     {
335         padicxx res(from.estimate_ctx().pctx(), from.prec());
336         execution_check(qadic_get_padic(res._padic(), from._qadic(), from._ctx()),
337                 "get_padic", "qadic");
338         return res;
339     }
340 };
341 
342 FLINTXX_DEFINE_SWAP(qadicxx, qadic_swap(e1._qadic(), e2._qadic()))
343 
344 FLINTXX_DEFINE_EQUALS(qadicxx, qadic_equal(e1._qadic(), e2._qadic()))
345 
346 FLINT_DEFINE_CBINARY_EXPR_COND2(plus, qadicxx, QADICXX_COND_S, QADICXX_COND_S,
347         qadic_add(to._qadic(), e1._qadic(), e2._qadic(), to._ctx()))
348 FLINT_DEFINE_BINARY_EXPR_COND2(minus, qadicxx, QADICXX_COND_S, QADICXX_COND_S,
349         qadic_sub(to._qadic(), e1._qadic(), e2._qadic(), to._ctx()))
350 FLINT_DEFINE_CBINARY_EXPR_COND2(times, qadicxx, QADICXX_COND_S, QADICXX_COND_S,
351         qadic_mul(to._qadic(), e1._qadic(), e2._qadic(), to._ctx()))
352 
353 FLINT_DEFINE_UNARY_EXPR_COND(negate, qadicxx, QADICXX_COND_S,
354         qadic_neg(to._qadic(), from._qadic(), to._ctx()))
355 
356 FLINT_DEFINE_UNARY_EXPR_COND(inv_op, qadicxx, QADICXX_COND_S,
357         qadic_inv(to._qadic(), from._qadic(), to._ctx()))
358 FLINT_DEFINE_BINARY_EXPR_COND2(pow_op, qadicxx, QADICXX_COND_S,
359         traits::is_fmpzxx,
360         qadic_pow(to._qadic(), e1._qadic(), e2._fmpz(), to._ctx()))
361 
362 FLINT_DEFINE_UNARY_EXPR_COND(exp_op, qadicxx, QADICXX_COND_S,
363         execution_check(
364             qadic_exp(to._qadic(), from._qadic(), to._ctx()), "exp", "qadic"))
365 FLINT_DEFINE_UNARY_EXPR_COND(exp_balanced_op, qadicxx, QADICXX_COND_S,
366         execution_check(qadic_exp_balanced(
367                 to._qadic(), from._qadic(), to._ctx()), "exp_balanced", "qadic"))
368 FLINT_DEFINE_UNARY_EXPR_COND(exp_rectangular_op, qadicxx, QADICXX_COND_S,
369         execution_check(qadic_exp_rectangular(
370                 to._qadic(), from._qadic(), to._ctx()),
371             "exp_rectangular", "qadic"))
372 FLINT_DEFINE_UNARY_EXPR_COND(log_op, qadicxx, QADICXX_COND_S,
373         execution_check(
374             qadic_log(to._qadic(), from._qadic(), to._ctx()), "log", "qadic"))
375 FLINT_DEFINE_UNARY_EXPR_COND(log_rectangular_op, qadicxx, QADICXX_COND_S,
376         execution_check(qadic_log_rectangular(
377                 to._qadic(), from._qadic(), to._ctx()),
378             "log_rectangular", "qadic"))
379 FLINT_DEFINE_UNARY_EXPR_COND(log_balanced_op, qadicxx, QADICXX_COND_S,
380         execution_check(qadic_log_balanced(
381                 to._qadic(), from._qadic(), to._ctx()), "log_balanced", "qadic"))
382 FLINT_DEFINE_UNARY_EXPR_COND(teichmuller_op, qadicxx, QADICXX_COND_S,
383             qadic_teichmuller(to._qadic(), from._qadic(), to._ctx()))
384 
385 FLINT_DEFINE_BINARY_EXPR_COND2(frobenius_op, qadicxx, QADICXX_COND_S,
386         traits::fits_into_slong,
387         qadic_frobenius(to._qadic(), e1._qadic(), e2, to._ctx()))
388 
389 FLINT_DEFINE_UNARY_EXPR_COND(trace_op, padicxx, QADICXX_COND_S,
390             qadic_trace(to._padic(), from._qadic(), from._ctx()))
391 FLINT_DEFINE_UNARY_EXPR_COND(norm_op, padicxx, QADICXX_COND_S,
392             qadic_norm(to._padic(), from._qadic(), from._ctx()))
393 FLINT_DEFINE_UNARY_EXPR_COND(norm_analytic_op, padicxx, QADICXX_COND_S,
394             qadic_norm_analytic(to._padic(), from._qadic(), from._ctx()))
395 FLINT_DEFINE_UNARY_EXPR_COND(norm_resultant_op, padicxx, QADICXX_COND_S,
396             qadic_norm_resultant(to._padic(), from._qadic(), from._ctx()))
397 } // rules
398 } // flint
399 
400 #endif
401