1+ /*
2+ Copyright (C) 2025, Vincent Neiger
3+ Copyright (C) 2025, Mael Hostettler
4+
5+ This file is part of FLINT.
6+
7+ FLINT is free software: you can redistribute it and/or modify it under
8+ the terms of the GNU Lesser General Public License (LGPL) as published
9+ by the Free Software Foundation; either version 3 of the License, or
10+ (at your option) any later version. See <https://www.gnu.org/licenses/>.
11+ */
12+
13+ #include "nmod.h"
14+ #include "nmod_vec.h"
15+ #include "nmod_poly.h"
16+
17+ void
18+ nmod_geometric_progression_init (nmod_geometric_progression_t G , ulong r , slong d , nmod_t mod )
19+ {
20+ ulong q , inv_r , inv_q , tmp , qk , inv_qk , qq , s ;
21+ nn_ptr diff , inv_diff , prod_diff ;
22+ slong i ;
23+
24+ G -> d = d ;
25+ G -> mod = mod ;
26+
27+ nmod_poly_init2 (G -> f , mod .n , 2 * d - 1 );
28+ nmod_poly_init (G -> g1 , mod .n );
29+ nmod_poly_init (G -> g2 , mod .n );
30+ nmod_poly_set_coeff_ui (G -> g1 , 0 , 1 );
31+ nmod_poly_set_coeff_ui (G -> g2 , 0 , 1 );
32+
33+ G -> x = _nmod_vec_init (d );
34+ G -> w = _nmod_vec_init (d );
35+ G -> z = _nmod_vec_init (d );
36+ G -> y = _nmod_vec_init (d );
37+
38+ G -> x [0 ] = 1 ;
39+ G -> y [0 ] = 1 ;
40+ G -> w [0 ] = 1 ;
41+ G -> z [0 ] = 1 ;
42+
43+ q = nmod_mul (r , r , mod );
44+ inv_r = nmod_inv (r , mod );
45+ inv_q = nmod_mul (inv_r , inv_r , mod );
46+
47+ nmod_poly_set_coeff_ui (G -> f , 0 , 1 );
48+ tmp = r ;
49+ for (i = 1 ; i < 2 * d - 1 ; i ++ )
50+ {
51+ nmod_poly_set_coeff_ui (G -> f , i , nmod_mul (nmod_poly_get_coeff_ui (G -> f , i - 1 ), tmp , mod ));
52+ tmp = nmod_mul (tmp , q , mod );
53+ }
54+
55+ tmp = inv_r ;
56+ for (i = 1 ; i < d ; i ++ )
57+ {
58+ G -> x [i ] = nmod_mul (G -> x [i - 1 ], tmp , mod );
59+ tmp = nmod_mul (tmp , inv_q , mod );
60+ }
61+
62+ inv_diff = _nmod_vec_init (d );
63+ diff = _nmod_vec_init (d );
64+ prod_diff = _nmod_vec_init (d );
65+ inv_diff [0 ] = 1 ;
66+ diff [0 ] = 1 ;
67+ prod_diff [0 ] = 1 ;
68+
69+ qk = q ; // montgomery inversion
70+ for (i = 1 ; i < d ; i ++ )
71+ {
72+ diff [i ] = qk - 1 ;
73+ inv_diff [i ] = diff [i ];
74+ qk = nmod_mul (qk , q , mod );
75+ prod_diff [i ] = nmod_mul (diff [i ], prod_diff [i - 1 ], mod );
76+ }
77+
78+ tmp = n_invmod (prod_diff [d - 1 ], mod .n );
79+ for (i = d - 1 ; i > 0 ; i -- )
80+ {
81+ inv_diff [i ] = nmod_mul (prod_diff [i - 1 ], tmp , mod );
82+ tmp = nmod_mul (tmp , diff [i ], mod );
83+ }
84+ inv_diff [0 ] = tmp ;
85+ // end montgomery inversion
86+
87+ // sets sequences w, y, z and polynomials g1, g2
88+ qk = 1 ;
89+ inv_qk = 1 ;
90+ qq = 1 ;
91+ s = 1 ;
92+
93+ for (i = 1 ; i < d ; i ++ )
94+ {
95+ qq = nmod_mul (qq , qk , mod ); // prod q^i
96+ s = nmod_mul (s , inv_qk , mod ); // prod 1/q^i
97+ G -> w [i ] = nmod_mul (G -> w [i - 1 ], inv_diff [i ], mod ); // prod 1/(q^i-1)
98+ tmp = nmod_mul (qq , G -> w [i ], mod ); // prod q^i/(q^i-1)
99+ nmod_poly_set_coeff_ui (G -> g2 , i , tmp );
100+
101+ if ((i & 1 ) == 1 )
102+ {
103+ nmod_poly_set_coeff_ui (G -> g1 , i , nmod_neg (tmp , mod ));
104+ G -> y [i ] = nmod_neg (prod_diff [i ], mod );
105+ G -> z [i ] = nmod_neg (G -> w [i ], mod );
106+ }
107+ else
108+ {
109+ nmod_poly_set_coeff_ui (G -> g1 , i , tmp );
110+ G -> y [i ] = prod_diff [i ];
111+ G -> z [i ] = G -> w [i ];
112+ }
113+ G -> y [i ] = nmod_mul (G -> y [i ], s , mod );
114+
115+ qk = nmod_mul (qk , q , mod );
116+ inv_qk = nmod_mul (inv_qk , inv_q , mod );
117+ }
118+
119+ _nmod_vec_clear (prod_diff );
120+ _nmod_vec_clear (inv_diff );
121+ _nmod_vec_clear (diff );
122+ }
123+
124+ void
125+ nmod_geometric_progression_clear (nmod_geometric_progression_t G )
126+ {
127+ nmod_poly_clear (G -> f );
128+ nmod_poly_clear (G -> g2 );
129+ nmod_poly_clear (G -> g1 );
130+ _nmod_vec_clear (G -> x );
131+ _nmod_vec_clear (G -> z );
132+ _nmod_vec_clear (G -> y );
133+ _nmod_vec_clear (G -> w );
134+ }
0 commit comments