Blender  V3.3
math_solvers.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2015 Blender Foundation. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "BLI_math.h"
11 #include "BLI_utildefines.h"
12 
13 #include "BLI_strict_flags.h"
14 
15 #include "eigen_capi.h"
16 
17 /********************************** Eigen Solvers *********************************/
18 
19 bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3],
20  float r_eigen_values[3],
21  float r_eigen_vectors[3][3])
22 {
23 #ifndef NDEBUG
24  /* We must assert given matrix is self-adjoint (i.e. symmetric) */
25  if ((m3[0][1] != m3[1][0]) || (m3[0][2] != m3[2][0]) || (m3[1][2] != m3[2][1])) {
26  BLI_assert(0);
27  }
28 #endif
29 
31  3, (const float *)m3, r_eigen_values, (float *)r_eigen_vectors);
32 }
33 
34 void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3])
35 {
36  EIG_svd_square_matrix(3, (const float *)m3, (float *)r_U, (float *)r_S, (float *)r_V);
37 }
38 
39 /***************************** Simple Solvers ************************************/
40 
42  const float *a, const float *b, const float *c, const float *d, float *r_x, const int count)
43 {
44  if (count < 1) {
45  return false;
46  }
47 
48  size_t bytes = sizeof(double) * (unsigned)count;
49  double *c1 = (double *)MEM_mallocN(bytes * 2, "tridiagonal_c1d1");
50  double *d1 = c1 + count;
51 
52  if (!c1) {
53  return false;
54  }
55 
56  int i;
57  double c_prev, d_prev, x_prev;
58 
59  /* forward pass */
60 
61  c1[0] = c_prev = ((double)c[0]) / b[0];
62  d1[0] = d_prev = ((double)d[0]) / b[0];
63 
64  for (i = 1; i < count; i++) {
65  double denum = b[i] - a[i] * c_prev;
66 
67  c1[i] = c_prev = c[i] / denum;
68  d1[i] = d_prev = (d[i] - a[i] * d_prev) / denum;
69  }
70 
71  /* back pass */
72 
73  x_prev = d_prev;
74  r_x[--i] = ((float)x_prev);
75 
76  while (--i >= 0) {
77  x_prev = d1[i] - c1[i] * x_prev;
78  r_x[i] = ((float)x_prev);
79  }
80 
81  MEM_freeN(c1);
82 
83  return isfinite(x_prev);
84 }
85 
87  const float *a, const float *b, const float *c, const float *d, float *r_x, const int count)
88 {
89  if (count < 1) {
90  return false;
91  }
92 
93  /* Degenerate case not handled correctly by the generic formula. */
94  if (count == 1) {
95  r_x[0] = d[0] / (a[0] + b[0] + c[0]);
96 
97  return isfinite(r_x[0]);
98  }
99 
100  /* Degenerate case that works but can be simplified. */
101  if (count == 2) {
102  const float a2[2] = {0, a[1] + c[1]};
103  const float c2[2] = {a[0] + c[0], 0};
104 
105  return BLI_tridiagonal_solve(a2, b, c2, d, r_x, count);
106  }
107 
108  /* If not really cyclic, fall back to the simple solver. */
109  float a0 = a[0], cN = c[count - 1];
110 
111  if (a0 == 0.0f && cN == 0.0f) {
112  return BLI_tridiagonal_solve(a, b, c, d, r_x, count);
113  }
114 
115  size_t bytes = sizeof(float) * (unsigned)count;
116  float *tmp = (float *)MEM_mallocN(bytes * 2, "tridiagonal_ex");
117  float *b2 = tmp + count;
118 
119  if (!tmp) {
120  return false;
121  }
122 
123  /* Prepare the non-cyclic system; relies on tridiagonal_solve ignoring values. */
124  memcpy(b2, b, bytes);
125  b2[0] -= a0;
126  b2[count - 1] -= cN;
127 
128  memset(tmp, 0, bytes);
129  tmp[0] = a0;
130  tmp[count - 1] = cN;
131 
132  /* solve for partial solution and adjustment vector */
133  bool success = BLI_tridiagonal_solve(a, b2, c, tmp, tmp, count) &&
134  BLI_tridiagonal_solve(a, b2, c, d, r_x, count);
135 
136  /* apply adjustment */
137  if (success) {
138  float coeff = (r_x[0] + r_x[count - 1]) / (1.0f + tmp[0] + tmp[count - 1]);
139 
140  for (int i = 0; i < count; i++) {
141  r_x[i] -= coeff * tmp[i];
142  }
143  }
144 
145  MEM_freeN(tmp);
146 
147  return success;
148 }
149 
151  Newton3D_JacobianFunc func_jacobian,
152  Newton3D_CorrectionFunc func_correction,
153  void *userdata,
154  float epsilon,
155  int max_iterations,
156  bool trace,
157  const float x_init[3],
158  float result[3])
159 {
160  float fdelta[3], fdeltav, next_fdeltav;
161  float jacobian[3][3], step[3], x[3], x_next[3];
162 
163  epsilon *= epsilon;
164 
165  copy_v3_v3(x, x_init);
166 
167  func_delta(userdata, x, fdelta);
168  fdeltav = len_squared_v3(fdelta);
169 
170  if (trace) {
171  printf("START (%g, %g, %g) %g %g\n", x[0], x[1], x[2], fdeltav, epsilon);
172  }
173 
174  for (int i = 0; i == 0 || (i < max_iterations && fdeltav > epsilon); i++) {
175  /* Newton's method step. */
176  func_jacobian(userdata, x, jacobian);
177 
178  if (!invert_m3(jacobian)) {
179  return false;
180  }
181 
182  mul_v3_m3v3(step, jacobian, fdelta);
183  sub_v3_v3v3(x_next, x, step);
184 
185  /* Custom out-of-bounds value correction. */
186  if (func_correction) {
187  if (trace) {
188  printf("%3d * (%g, %g, %g)\n", i, x_next[0], x_next[1], x_next[2]);
189  }
190 
191  if (!func_correction(userdata, x, step, x_next)) {
192  return false;
193  }
194  }
195 
196  func_delta(userdata, x_next, fdelta);
197  next_fdeltav = len_squared_v3(fdelta);
198 
199  if (trace) {
200  printf("%3d ? (%g, %g, %g) %g\n", i, x_next[0], x_next[1], x_next[2], next_fdeltav);
201  }
202 
203  /* Line search correction. */
204  while (next_fdeltav > fdeltav && next_fdeltav > epsilon) {
205  float g0 = sqrtf(fdeltav), g1 = sqrtf(next_fdeltav);
206  float g01 = -g0 / len_v3(step);
207  float det = 2.0f * (g1 - g0 - g01);
208  float l = (det == 0.0f) ? 0.1f : -g01 / det;
209  CLAMP_MIN(l, 0.1f);
210 
211  mul_v3_fl(step, l);
212  sub_v3_v3v3(x_next, x, step);
213 
214  func_delta(userdata, x_next, fdelta);
215  next_fdeltav = len_squared_v3(fdelta);
216 
217  if (trace) {
218  printf("%3d . (%g, %g, %g) %g\n", i, x_next[0], x_next[1], x_next[2], next_fdeltav);
219  }
220  }
221 
222  copy_v3_v3(x, x_next);
223  fdeltav = next_fdeltav;
224  }
225 
226  bool success = (fdeltav <= epsilon);
227 
228  if (trace) {
229  printf("%s (%g, %g, %g) %g\n", success ? "OK " : "FAIL", x[0], x[1], x[2], fdeltav);
230  }
231 
232  copy_v3_v3(result, x);
233  return success;
234 }
typedef float(TangentPoint)[2]
#define BLI_assert(a)
Definition: BLI_assert.h:46
bool invert_m3(float R[3][3])
Definition: math_matrix.c:1171
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
Definition: math_matrix.c:897
bool(* Newton3D_CorrectionFunc)(void *userdata, const float x[3], float step[3], float x_next[3])
void(* Newton3D_JacobianFunc)(void *userdata, const float x[3], float r_jacobian[3][3])
void(* Newton3D_DeltaFunc)(void *userdata, const float x[3], float r_delta[3])
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
Strict compiler flags for areas of code we want to ensure don't do conversions without us knowing abo...
#define CLAMP_MIN(a, b)
typedef double(DMatrix)[4][4]
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMLoop * l
bool EIG_self_adjoint_eigen_solve(const int size, const float *matrix, float *r_eigen_values, float *r_eigen_vectors)
Definition: eigenvalues.cc:25
int count
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta, Newton3D_JacobianFunc func_jacobian, Newton3D_CorrectionFunc func_correction, void *userdata, float epsilon, int max_iterations, bool trace, const float x_init[3], float result[3])
Solve a generic f(x) = 0 equation using Newton's method.
Definition: math_solvers.c:150
void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3])
Compute the SVD (Singular Values Decomposition) of given 3D matrix (m3 = USV*).
Definition: math_solvers.c:34
bool BLI_tridiagonal_solve(const float *a, const float *b, const float *c, const float *d, float *r_x, const int count)
Solve a tridiagonal system of equations:
Definition: math_solvers.c:41
bool BLI_tridiagonal_solve_cyclic(const float *a, const float *b, const float *c, const float *d, float *r_x, const int count)
Solve a possibly cyclic tridiagonal system using the Sherman-Morrison formula.
Definition: math_solvers.c:86
bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3], float r_eigen_values[3], float r_eigen_vectors[3][3])
Compute the eigen values and/or vectors of given 3D symmetric (aka adjoint) matrix.
Definition: math_solvers.c:19
#define sqrtf(x)
Definition: metal/compat.h:243
bool isfinite(uchar)
Definition: scene/image.cpp:31
static unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
static double epsilon
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
void EIG_svd_square_matrix(const int size, const float *matrix, float *r_U, float *r_S, float *r_V)
Definition: svd.cc:38