1 /*
2     Copyright (C) 2011, 2013 Sebastian Pancratz
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 #include "fmpz_mat.h"
13 #include "padic_mat.h"
14 
15 /*
16     Assumptions:
17 
18     o  That the matrix dimensions be compatible.
19     o  That the matrices be non-empty.
20     o  That ord_p(A) >= ord_p(B).
21  */
22 
_padic_mat_add(padic_mat_t C,const padic_mat_t A,const padic_mat_t B,const padic_ctx_t ctx)23 void _padic_mat_add(padic_mat_t C, const padic_mat_t A, const padic_mat_t B,
24                                    const padic_ctx_t ctx)
25 {
26     if (padic_mat_is_zero(A))
27     {
28         padic_mat_set(C, B, ctx);
29         return;
30     }
31     if (padic_mat_is_zero(B))
32     {
33         padic_mat_set(C, A, ctx);
34         return;
35     }
36     if (padic_mat_val(B) >= padic_mat_prec(C))
37     {
38         padic_mat_zero(C);
39         return;
40     }
41 
42 
43     if (padic_mat_val(A) == padic_mat_val(B))
44     {
45         fmpz_mat_add(padic_mat(C), padic_mat(A), padic_mat(B));
46         padic_mat_val(C) = padic_mat_val(B);
47         _padic_mat_canonicalise(C, ctx);
48     }
49     else  /* padic_mat_val(A) > padic_mat_val(B) */
50     {
51         fmpz_t x;
52 
53         fmpz_init(x);
54         fmpz_pow_ui(x, ctx->p, padic_mat_val(A) - padic_mat_val(B));
55 
56         if (C == B)
57         {
58             fmpz_mat_scalar_addmul_fmpz(padic_mat(C), padic_mat(A), x);
59         }
60         else if (C == A)
61         {
62             fmpz_mat_scalar_mul_fmpz(padic_mat(C), padic_mat(A), x);
63             fmpz_mat_add(padic_mat(C), padic_mat(B), padic_mat(C));
64             padic_mat_val(C) = padic_mat_val(B);
65         }
66         else
67         {
68             fmpz_mat_set(padic_mat(C), padic_mat(B));
69             fmpz_mat_scalar_addmul_fmpz(padic_mat(C), padic_mat(A), x);
70             padic_mat_val(C) = padic_mat_val(B);
71         }
72 
73         fmpz_clear(x);
74     }
75 
76     /* Reduction */
77     {
78         fmpz_t pow;
79         int alloc = _padic_ctx_pow_ui(pow, padic_mat_prec(C)- padic_mat_val(C), ctx);
80 
81         /* TODO: Improve, use input precision */
82         _fmpz_vec_scalar_mod_fmpz(padic_mat(C)->entries,
83             padic_mat(C)->entries, padic_mat_nrows(C)*padic_mat_ncols(C), pow);
84 
85         if (fmpz_mat_is_zero(padic_mat(C)))
86         {
87             padic_mat_val(C) = 0;
88         }
89 
90 
91         if (alloc)
92             fmpz_clear(pow);
93     }
94 }
95 
padic_mat_add(padic_mat_t C,const padic_mat_t A,const padic_mat_t B,const padic_ctx_t ctx)96 void padic_mat_add(padic_mat_t C, const padic_mat_t A, const padic_mat_t B,
97                                   const padic_ctx_t ctx)
98 {
99     if (padic_mat_is_empty(C))
100     {
101         return;
102     }
103 
104     if (padic_mat_val(A) >= padic_mat_val(B))
105     {
106         _padic_mat_add(C, A, B, ctx);
107     }
108     else
109     {
110         _padic_mat_add(C, B, A, ctx);
111     }
112 }
113 
114