Motr  M0
ls_solve.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2020 Seagate Technology LLC and/or its Affiliates
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * For any questions about this software or licensing,
17  * please email opensource@seagate.com or cortx-questions@seagate.com.
18  *
19  */
20 
21 
22 #include "lib/assert.h"
23 #include "lib/types.h"
24 #include "lib/errno.h" /* EDOM */
25 #include "lib/misc.h" /* NULL */
26 
27 #include "sns/parity_ops.h"
28 #include "sns/ls_solve.h"
29 
30 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_SNS
31 #include "lib/trace.h"
32 
33 M0_INTERNAL void m0_linsys_init(struct m0_linsys *lynsys,
34  struct m0_matrix *m,
35  struct m0_matvec *v, struct m0_matvec *r)
36 {
37  M0_PRE(m != NULL && v != NULL && r != NULL);
38  M0_PRE(m->m_height > 0 && m->m_width > 0);
39  M0_PRE(m->m_width == m->m_height && r->mv_size == v->mv_size &&
40  v->mv_size == m->m_width);
41 
42  lynsys->l_mat = m;
43  lynsys->l_res = r;
44  lynsys->l_vec = v;
45 }
46 
47 M0_INTERNAL void m0_linsys_fini(struct m0_linsys *lynsys)
48 {
49  lynsys->l_mat = NULL;
50  lynsys->l_res = NULL;
51  lynsys->l_vec = NULL;
52 }
53 
54 /* Works with partially processed matrix */
55 static uint32_t find_max_row_index_for_col(struct m0_matrix *m,
56  uint32_t column)
57 {
58  uint32_t i = 0;
59  uint32_t ret = column;
60  m0_parity_elem_t max_el = *m0_matrix_elem_get(m, column, column);
61 
62  for (i = column + 1; i < m->m_height; ++i) {
63  m0_parity_elem_t cur_el = *m0_matrix_elem_get(m, column, i);
64 
65  if (m0_parity_lt(max_el, cur_el)) {
66  max_el = cur_el;
67  ret = i;
68  }
69  }
70 
71  return ret;
72 }
73 
74 static void triangularize(struct m0_matrix *m, struct m0_matvec *v)
75 {
76  uint32_t col = 0;
77  uint32_t current_row = 0;
78 
79  for (; col < m->m_width; ++col, ++current_row) {
80  uint32_t max_row;
81  m0_parity_elem_t divisor;
82  uint32_t row;
83 
84  /* move row with max first elem to the top of matrix */
85  max_row = find_max_row_index_for_col(m, col);
86  m0_matrix_swap_row(m, current_row, max_row);
87  m0_matvec_swap_row(v, current_row, max_row);
88 
89  /* divide row to eliminate first element of the row */
90  divisor = *m0_matrix_elem_get(m, col, current_row);
91  m0_matrix_row_operate(m, col, divisor, m0_parity_div);
92  m0_matvec_row_operate(v, col, divisor, m0_parity_div);
93 
94  /* eliminate first elements in other rows */
95  row = current_row + 1;
96  for (; row < m->m_height; ++row) {
97  m0_parity_elem_t mult = *m0_matrix_elem_get(m, col, row);
100  }
101  }
102 }
103 
104 static void substitute(struct m0_matrix *m, struct m0_matvec *v, struct m0_matvec *r)
105 {
106  uint32_t col = m->m_width - 1;
107  uint32_t row = m->m_height - 1;
108 
109  for (; (int32_t)row >= 0; --row, --col) {
110  uint32_t pos;
111  m0_parity_elem_t *ev = m0_matvec_elem_get(v, row);
112  m0_parity_elem_t *em = m0_matrix_elem_get(m, col, row);
114  m0_parity_elem_t rhs = *ev;
115 
116  for (pos = 1; pos < m->m_height - row; ++pos) {
117  m0_parity_elem_t *er_prev = m0_matvec_elem_get(r, row + pos);
118  m0_parity_elem_t *em_prev = m0_matrix_elem_get(m, col + pos, row);
119  rhs = m0_parity_sub(rhs, m0_parity_mul(*er_prev, *em_prev));
120  }
121 
122  *er = m0_parity_div(rhs, *em);
123  }
124 }
125 
126 M0_INTERNAL void m0_linsys_solve(struct m0_linsys *lynsys)
127 {
128  struct m0_matrix *m = lynsys->l_mat;
129  struct m0_matvec *v = lynsys->l_vec;
130  struct m0_matvec *r = lynsys->l_res;
131 
132  triangularize(m, v);
133  substitute(m, v, r);
134 }
135 
136 M0_INTERNAL int m0_matrix_invert(const struct m0_matrix *in_mat,
137  struct m0_matrix *mat_inverse)
138 {
139  uint32_t col;
140  uint32_t current_row;
141  int ret;
142  struct m0_matrix mat;
143  m0_parity_elem_t mult;
144 
145  if (!m0_matrix_is_square(in_mat) || !m0_matrix_is_square(mat_inverse))
146  return M0_ERR_INFO(-EIO, "Input matrix not a square one");
147  M0_PRE(in_mat->m_width == mat_inverse->m_width);
148 
149  ret = m0_matrix_init(&mat, in_mat->m_width, in_mat->m_height);
150  if (ret != 0)
151  return ret;
152  m0_matrix_submatrix_get((struct m0_matrix *)in_mat, &mat, 0, 0);
153  m0_identity_matrix_fill(mat_inverse);
154 
155  for (col = 0, current_row = 0; col < mat.m_width; ++col,
156  ++current_row) {
157  uint32_t max_row;
158  m0_parity_elem_t divisor;
159  uint32_t row;
160 
161  /* move row with max first elem to the top of matrix */
162  max_row = find_max_row_index_for_col(&mat, col);
163  m0_matrix_swap_row(&mat, current_row, max_row);
164  m0_matrix_swap_row(mat_inverse, current_row, max_row);
165 
166  /* divide row to eliminate first element of the row */
167  divisor = *m0_matrix_elem_get(&mat, col, current_row);
168  if (divisor == 0) {
169  m0_matrix_fini(&mat);
170  return M0_ERR(-EDOM);
171  }
172  m0_matrix_row_operate(&mat, col, divisor, m0_parity_div);
173  m0_matrix_row_operate(mat_inverse, col, divisor,
174  m0_parity_div);
175 
176  /* eliminate first elements in all other rows */
177  for (row = 0; row < mat.m_height; ++row) {
178  if (row == current_row)
179  continue;
180  mult = *m0_matrix_elem_get(&mat, col, row);
181  if (mult == 0)
182  continue;
183  m0_matrix_rows_operate1(&mat, row, col, m0_parity_mul,
184  mult, m0_parity_sub);
185  m0_matrix_rows_operate1(mat_inverse, row, col,
186  m0_parity_mul, mult,
187  m0_parity_sub);
188  }
189  }
190  m0_matrix_fini(&mat);
191  return 0;
192 }
193 
194 #undef M0_TRACE_SUBSYSTEM
195 
196 /*
197  * Local variables:
198  * c-indentation-style: "K&R"
199  * c-basic-offset: 8
200  * tab-width: 8
201  * fill-column: 80
202  * scroll-step: 1
203  * End:
204  */
#define M0_PRE(cond)
#define NULL
Definition: misc.h:38
static struct m0_addb2_mach * m
Definition: consumer.c:38
M0_INTERNAL void m0_linsys_init(struct m0_linsys *lynsys, struct m0_matrix *m, struct m0_matvec *v, struct m0_matvec *r)
Definition: ls_solve.c:33
static m0_parity_elem_t m0_parity_lt(m0_parity_elem_t x, m0_parity_elem_t y)
Definition: parity_ops.h:69
struct m0_matrix * l_mat
Definition: ls_solve.h:43
uint32_t m_height
Definition: matvec.h:57
M0_INTERNAL bool m0_matrix_is_square(const struct m0_matrix *mat)
Definition: matvec.c:413
struct m0_matvec * l_vec
Definition: ls_solve.h:44
static m0_parity_elem_t m0_parity_div(m0_parity_elem_t x, m0_parity_elem_t y)
Definition: parity_ops.h:60
M0_INTERNAL void m0_matrix_row_operate(struct m0_matrix *m, uint32_t row, m0_parity_elem_t c, m0_matvec_matrix_binary_operator_t f)
Definition: matvec.c:142
int i
Definition: dir.c:1033
M0_INTERNAL void m0_matvec_row_operate(struct m0_matvec *v, uint32_t row, m0_parity_elem_t c, m0_matvec_matrix_binary_operator_t f)
Definition: matvec.c:155
#define M0_ERR_INFO(rc, fmt,...)
Definition: trace.h:215
static void substitute(struct m0_matrix *m, struct m0_matvec *v, struct m0_matvec *r)
Definition: ls_solve.c:104
return M0_ERR(-EOPNOTSUPP)
M0_INTERNAL void m0_linsys_fini(struct m0_linsys *lynsys)
Definition: ls_solve.c:47
M0_INTERNAL void m0_matvec_rows_operate1(struct m0_matvec *v, uint32_t row0, uint32_t row1, m0_matvec_matrix_binary_operator_t f1, m0_parity_elem_t c1, m0_matvec_matrix_binary_operator_t f)
Definition: matvec.c:265
uint32_t mv_size
Definition: matvec.h:35
M0_INTERNAL void m0_matvec_swap_row(struct m0_matvec *v, uint32_t r0, uint32_t r1)
Definition: matvec.c:131
M0_INTERNAL void m0_matrix_rows_operate1(struct m0_matrix *m, uint32_t row0, uint32_t row1, m0_matvec_matrix_binary_operator_t f1, m0_parity_elem_t c1, m0_matvec_matrix_binary_operator_t f)
Definition: matvec.c:199
struct m0_matvec * l_res
Definition: ls_solve.h:45
M0_INTERNAL void m0_linsys_solve(struct m0_linsys *lynsys)
Definition: ls_solve.c:126
m0_parity_elem_t * m0_matrix_elem_get(const struct m0_matrix *m, uint32_t x, uint32_t y)
Definition: matvec.c:86
m0_parity_elem_t * m0_matvec_elem_get(const struct m0_matvec *v, uint32_t x)
Definition: matvec.c:80
M0_INTERNAL void m0_matrix_submatrix_get(const struct m0_matrix *mat, struct m0_matrix *submat, uint32_t x_off, uint32_t y_off)
Definition: matvec.c:324
M0_INTERNAL void m0_matrix_fini(struct m0_matrix *m)
Definition: matvec.c:70
M0_INTERNAL void m0_identity_matrix_fill(struct m0_matrix *identity_mat)
Definition: matvec.c:371
M0_INTERNAL int m0_matrix_init(struct m0_matrix *m, uint32_t w, uint32_t h)
Definition: matvec.c:49
static int r[NR]
Definition: thread.c:46
int m0_parity_elem_t
Definition: parity_ops.h:36
static m0_parity_elem_t m0_parity_sub(m0_parity_elem_t x, m0_parity_elem_t y)
Definition: parity_ops.h:46
M0_INTERNAL int m0_matrix_invert(const struct m0_matrix *in_mat, struct m0_matrix *mat_inverse)
Definition: ls_solve.c:136
static m0_parity_elem_t m0_parity_mul(m0_parity_elem_t x, m0_parity_elem_t y)
Definition: parity_ops.h:51
uint32_t m_width
Definition: matvec.h:56
static uint32_t find_max_row_index_for_col(struct m0_matrix *m, uint32_t column)
Definition: ls_solve.c:55
static void triangularize(struct m0_matrix *m, struct m0_matvec *v)
Definition: ls_solve.c:74
M0_INTERNAL void m0_matrix_swap_row(struct m0_matrix *m, uint32_t r0, uint32_t r1)
Definition: matvec.c:120