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 FMPZ_FACTORXX_H
13 #define FMPZ_FACTORXX_H
14 
15 #include "fmpz_factor.h"
16 #include "fmpz_vec.h"
17 
18 #include "flintxx/ltuple.h"
19 
20 // TODO codegen
21 // TODO factor_pp1 multiple return values
22 
23 namespace flint {
24 FLINT_DEFINE_THREEARY(factor_trial_range)
FLINT_DEFINE_UNOP(expand)25 FLINT_DEFINE_UNOP(expand)
26 FLINT_DEFINE_UNOP(expand_iterative)
27 FLINT_DEFINE_UNOP(expand_multiexp)
28 
29 namespace detail {
30 template<class Delay>
31 class fmpz_factorxx_delayed
32 {
33 private:
34     fmpz_factor_t inner;
35 
36     void copy_init(const fmpz_factorxx_delayed& o)
37     {
38 	_fmpz_factor_fit_length(inner, o.inner->num);
39 	_fmpz_factor_set_length(inner, o.inner->num);
40 	inner->sign = o.inner->sign;
41 	for(slong i = 0;i < o.inner->num;++i)
42 	{
43 	    fmpz_set(inner->p + i, o.inner->p + i);
44 	    inner->exp[i] = o.inner->exp[i];
45 	}
46     }
47 
48 public:
49     fmpz_factorxx_delayed() {fmpz_factor_init(inner);}
50     ~fmpz_factorxx_delayed() {fmpz_factor_clear(inner);}
51 
52     fmpz_factorxx_delayed(const fmpz_factorxx_delayed& o)
53     {
54 	fmpz_factor_init(inner);
55 	copy_init(o);
56     }
57 
58     fmpz_factorxx_delayed& operator=(const fmpz_factorxx_delayed& o)
59     {
60 	copy_init(o);
61 	return *this;
62     }
63 
64     bool operator==(const fmpz_factorxx_delayed& o)
65     {
66 	if(o.sign() != sign() || o.size() != size())
67 	    return false;
68 	for(ulong i = 0;i < size();++i)
69 	    if(p(i) != o.p(i) || exp(i) != o.exp(i))
70 		return false;
71 	return true;
72     }
73 
74     ulong size() const {return inner->num;}
75     ulong exp(slong i) const {return inner->exp[i];}
76     ulong& exp(slong i) {return inner->exp[i];}
77     fmpzxx_srcref p(slong i) const {return fmpzxx_srcref::make(inner->p + i);}
78     fmpzxx_ref p(slong i) {return fmpzxx_ref::make(inner->p + i);}
79     int sign() const {return inner->sign;}
80     int& sign() {return inner->sign;}
81 
82     fmpz_factor_t& _data() {return inner;}
83     const fmpz_factor_t& _data() const {return inner;}
84 
85     void print() const {fmpz_factor_print(inner);}
86 
87     template<class Fmpz>
88     typename mp::enable_if<traits::is_fmpzxx<Fmpz> >::type
89     set_factor(const Fmpz& f)
90     {
91 	fmpz_factor(_data(), f.evaluate()._fmpz());
92     }
93 
94     template<class T>
95     typename mp::enable_if<traits::fits_into_slong<T> >::type
96     set_factor(T t)
97     {
98 	fmpz_factor_si(_data(), t);
99     }
100 
101     template<class Fmpz>
102     typename mp::enable_if<traits::is_fmpzxx<Fmpz>, bool>::type
103     set_factor_trial_range(const Fmpz& f, ulong start, ulong nprimes)
104     {
105 	return fmpz_factor_trial_range(_data(), f.evaluate()._fmpz(),
106 		start, nprimes);
107     }
108 
109     template<class Fmpz>
110     typename mp::enable_if<traits::is_fmpzxx<Fmpz>, bool>::type
111     set_factor_pp1(const Fmpz& f, ulong B1, ulong B2_sqrt, ulong c)
112     {
113 	return fmpz_factor_pp1(_data(), f.evaluate()._fmpz(),
114 		B1, B2_sqrt, c);
115     }
116 
117 #define FLINTXX_DEFINE_MEMBER_UNOP_EXTRA(funcname, Class, rtype) \
118     FLINT_UNOP_BUILD_RETTYPE(funcname, rtype, Class) \
119     funcname() const {return flint::funcname(*this);}
120 
121     FLINTXX_DEFINE_MEMBER_UNOP_EXTRA(expand, fmpz_factorxx_delayed, fmpzxx)
122     FLINTXX_DEFINE_MEMBER_UNOP_EXTRA(expand_iterative, fmpz_factorxx_delayed, fmpzxx)
123     FLINTXX_DEFINE_MEMBER_UNOP_EXTRA(expand_multiexp, fmpz_factorxx_delayed, fmpzxx)
124 };
125 } // detail
126 typedef detail::fmpz_factorxx_delayed<void> fmpz_factorxx;
127 
128 template<class Fmpz>
129 inline typename mp::enable_if<mp::or_<
130         traits::is_fmpzxx<Fmpz>, traits::fits_into_slong<Fmpz> >,
factor(const Fmpz & f)131     fmpz_factorxx>::type factor(const Fmpz& f)
132 {
133     fmpz_factorxx res;
134     res.set_factor(f);
135     return res;
136 }
137 
138 namespace rules {
139 namespace rdetail {
140 typedef make_ltuple<mp::make_tuple<bool, fmpz_factorxx>::type>::type
141     fmpz_factor_rt;
142 
143 template<class T> struct signed_or_fmpz
144     : mp::or_<FMPZXX_COND_S<T>, traits::fits_into_slong<T> > { };
145 } // rdetail
146 FLINT_DEFINE_THREEARY_EXPR_COND3(factor_trial_range_op, rdetail::fmpz_factor_rt,
147 	rdetail::signed_or_fmpz,
148 	traits::is_unsigned_integer, traits::is_unsigned_integer,
149 	to.template get<0>() = to.template get<1>().set_factor_trial_range(
150 	    e1, e2, e3))
151 
152 FLINT_DEFINE_UNARY_EXPR_(expand_op, fmpzxx, fmpz_factorxx,
153 	fmpz_factor_expand(to._fmpz(), from._data()))
154 FLINT_DEFINE_UNARY_EXPR_(expand_iterative_op, fmpzxx, fmpz_factorxx,
155 	fmpz_factor_expand_iterative(to._fmpz(), from._data()))
156 FLINT_DEFINE_UNARY_EXPR_(expand_multiexp_op, fmpzxx, fmpz_factorxx,
157 	fmpz_factor_expand_multiexp(to._fmpz(), from._data()))
158 } // rules
159 
160 template<class Fmpz>
161 inline typename mp::enable_if<traits::is_fmpzxx<Fmpz>, fmpz_factorxx>::type
factor_pp1(const Fmpz & f,ulong B1,ulong B2_sqrt,ulong c)162 factor_pp1(const Fmpz& f, ulong B1, ulong B2_sqrt, ulong c)
163 {
164     fmpz_factorxx res;
165     res.set_factor_pp1(f, B1, B2_sqrt, c);
166     return res;
167 }
168 
print(const fmpz_factorxx & f)169 inline void print(const fmpz_factorxx& f)
170 {
171     f.print();
172 }
173 } // flint
174 
175 #endif
176