├── SagfreeElasticBeam.py ├── demo_nosagfree.gif ├── demo_sagfree.gif ├── praxis.py └── readme.md /SagfreeElasticBeam.py: -------------------------------------------------------------------------------- 1 | import time 2 | import taichi as ti 3 | import numpy as np 4 | import sys 5 | from scipy.sparse import csc_matrix 6 | from scipy.sparse.linalg import lsqr 7 | from praxis import * 8 | 9 | ti.init(arch=ti.x64) 10 | 11 | n_grid = 32 12 | beam_x, beam_y = 6, 13 13 | beam_width, beam_height = 20, 6 14 | 15 | n_particles = beam_width * beam_height * 4 16 | 17 | dx, inv_dx = 1 / float(n_grid), float(n_grid) 18 | dt = 1e-4 19 | gravity = 20.0 20 | p_vol, p_rho = (dx * 0.5)**2, 1 21 | p_mass = p_vol * p_rho 22 | E, nu = 0.1e4, 0.2 # Young's modulus and Poisson's ratio 23 | mu, la = E / (2 * (1 + nu)), E * nu / ((1+nu) * (1 - 2 * nu)) # Lame parameters 24 | x = ti.Vector.field(2, dtype=float, shape=n_particles) # position 25 | v = ti.Vector.field(2, dtype=float, shape=n_particles) # velocity 26 | C = ti.Matrix.field(2, 2, dtype=float, shape=n_particles) # affine velocity field 27 | F = ti.Matrix.field(2, 2, dtype=float, shape=n_particles) # deformation gradient 28 | color = ti.field( dtype=int, shape=n_particles) # color id 29 | Jp = ti.field( dtype=float, shape=n_particles) # plastic deformation 30 | grid_v = ti.Vector.field(2, dtype=float, shape=(n_grid, n_grid)) # grid node momentum/velocity 31 | grid_m = ti.field( dtype=float, shape=(n_grid, n_grid)) # grid node mass 32 | grid_i = ti.field( dtype=int, shape=(n_grid, n_grid)) # grid node index 33 | 34 | USE_SAGFREE_INIT = 0 35 | 36 | #################################################################### 37 | # functions for the forward MPM simulation 38 | 39 | @ti.kernel 40 | def cleanGrid(): 41 | for i, j in grid_m: 42 | grid_v[i, j] = [0, 0] 43 | grid_m[i, j] = 0 44 | 45 | @ti.kernel 46 | def P2G(): 47 | for p in x: 48 | base = (x[p] * inv_dx - 0.5).cast(int) 49 | fx = x[p] * inv_dx - base.cast(float) 50 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 51 | F[p] = (ti.Matrix.identity(ti.f32, 2) + dt * C[p]) @ F[p] 52 | R, S = ti.polar_decompose(F[p]) 53 | Jp[p] = Jp[p] * (1 + dt * C[p].trace()) 54 | cauchy = (2 * mu * (F[p] - R) + la * (R.transpose() @ F[p] - ti.Matrix.identity(ti.f32, 2)).trace() * R) @ F[p].transpose() 55 | stress = (-dt * p_vol * 4 * inv_dx * inv_dx) * cauchy 56 | affine = stress + p_mass * C[p] 57 | for i, j in ti.static(ti.ndrange(3, 3)): 58 | offset = ti.Vector([i, j]) 59 | dpos = (offset.cast(float) - fx) * dx 60 | weight = w[i][0] * w[j][1] 61 | grid_v[base + offset] += weight * (p_mass * v[p] + affine @ dpos) 62 | grid_m[base + offset] += weight * p_mass 63 | 64 | 65 | @ti.kernel 66 | def updateGrid(g : ti.f32): 67 | for i, j in grid_m: 68 | if grid_m[i, j] > 0: 69 | grid_v[i, j] = (1 / grid_m[i, j]) * grid_v[i, j] # Momentum to velocity 70 | grid_v[i, j][1] -= dt * g 71 | 72 | # boundary 73 | if i < 3 and grid_v[i, j][0] < 0: grid_v[i, j][0] = 0 74 | if i > n_grid - 3 and grid_v[i, j][0] > 0: grid_v[i, j][0] = 0 75 | if j < 3 and grid_v[i, j][1] < 0: grid_v[i, j][1] = 0 76 | if j > n_grid - 3 and grid_v[i, j][1] > 0: grid_v[i, j][1] = 0 77 | 78 | # fixed left side of the beam 79 | if i < beam_x + 3: grid_v[i, j] = [0, 0] 80 | 81 | @ti.kernel 82 | def G2P(): 83 | for p in x: 84 | base = (x[p] * inv_dx - 0.5).cast(int) 85 | fx = x[p] * inv_dx - base.cast(float) 86 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1.0) ** 2, 0.5 * (fx - 0.5) ** 2] 87 | new_v = ti.Vector.zero(ti.f32, 2) 88 | new_C = ti.Matrix.zero(ti.f32, 2, 2) 89 | for i, j in ti.static(ti.ndrange(3, 3)): 90 | dpos = ti.Vector([i, j]).cast(float) - fx 91 | g_v = grid_v[base + ti.Vector([i, j])] 92 | weight = w[i][0] * w[j][1] 93 | new_v += weight * g_v 94 | new_C += 4 * inv_dx * weight * g_v.outer_product(dpos) 95 | v[p], C[p] = new_v, new_C 96 | x[p] += dt * v[p] 97 | 98 | #################################################################### 99 | # initialization function 100 | 101 | @ti.kernel 102 | def initialize(): 103 | for i in range(beam_width * 2): 104 | for j in range(beam_height * 2): 105 | p_count = j + i * beam_height * 2 106 | x[p_count] = ti.Matrix([(float(beam_x) + i * 0.5 + 0.25) * dx, (float(beam_y) + j * 0.5 + 0.25) * dx]) 107 | color[p_count] = 1 108 | v[p_count] = ti.Matrix([0, 0]) 109 | F[p_count] = ti.Matrix([[1, 0], [0, 1]]) 110 | Jp[p_count] = 1 111 | 112 | #################################################################### 113 | # functions for sagfree initialization 114 | 115 | @ti.kernel 116 | def P2GStatic(): 117 | for p in x: 118 | base = (x[p] * inv_dx - 0.5).cast(int) 119 | fx = x[p] * inv_dx - base.cast(float) 120 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 121 | R, S = ti.polar_decompose(F[p]) 122 | cauchy = (2 * mu * (F[p] - R) + la * (R.transpose() @ F[p] - ti.Matrix.identity(ti.f32, 2)).trace() * R) @ F[p].transpose() 123 | affine = (-p_vol * 4 * inv_dx * inv_dx) * cauchy 124 | for i, j in ti.static(ti.ndrange(3, 3)): 125 | offset = ti.Vector([i, j]) 126 | dpos = (offset.cast(float) - fx) * dx 127 | weight = w[i][0] * w[j][1] 128 | grid_v[base + offset] += weight * (affine @ dpos) 129 | grid_m[base + offset] += weight * p_mass 130 | 131 | def computeRowAndColNum(): 132 | for i in range(0, n_grid): 133 | for j in range(0, n_grid): 134 | grid_i[i, j] = -1 135 | 136 | rn = 0 137 | for i in range(0, n_grid): 138 | for j in range(0, n_grid): 139 | if grid_m[i, j] > 0 and i >= beam_x + 3: 140 | grid_i[i, j] = rn 141 | rn = rn + 1 142 | 143 | cn = 0 144 | for i in range(0, n_particles): 145 | if x[i][0] > (beam_x + 1) * dx: # extra columns for particles 146 | cn = cn + 1 147 | 148 | return rn, cn 149 | 150 | def getSpMCoeff() : 151 | print("get sparse matrix information 2D") 152 | start_time = time.time() 153 | arr_len = 0 154 | for p in range(0, n_particles): 155 | if x[p][0] > (beam_x + 1) * dx: 156 | basex = int(x[p][0] * inv_dx - 0.5) 157 | basey = int(x[p][1] * inv_dx - 0.5) 158 | fx = np.array([float(x[p][0] * inv_dx - basex), float(x[p][1] * inv_dx - basey)]) 159 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 160 | for i in range(0, 3): 161 | for j in range(0, 3): 162 | offset = np.array([i, j]).astype(np.float) 163 | dpos = (offset - fx) * dx 164 | weight = w[i][0] * w[j][1] 165 | if (grid_m[basex + i, basey + j] > 0 and basex + i >= beam_x + 3) : 166 | arr_len = arr_len + 1 167 | 168 | row = np.zeros(arr_len*4) 169 | col = np.zeros(arr_len*4) 170 | dat = np.zeros(arr_len*4) 171 | arr_len = 0 172 | col_num = 0 173 | for p in range(0, n_particles): 174 | if x[p][0] > (beam_x + 1) * dx: 175 | basex = int(x[p][0] * inv_dx - 0.5) 176 | basey = int(x[p][1] * inv_dx - 0.5) 177 | fx = np.array([float(x[p][0] * inv_dx - basex), float(x[p][1] * inv_dx - basey)]) 178 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 179 | for i in range(0, 3): 180 | for j in range(0, 3): 181 | offset = np.array([i, j]).astype(np.float) 182 | dpos = (offset - fx) * dx 183 | weight = w[i][0] * w[j][1] 184 | if (grid_m[basex + i, basey + j] > 0 and basex + i >= beam_x + 3) : 185 | row_id = grid_i[basex + i, basey + j] 186 | col_id = col_num 187 | row[arr_len*4+0]=row_id * 2 + 0 188 | col[arr_len*4+0]=col_id * 3 + 0 189 | dat[arr_len*4+0]=weight * dpos[0] 190 | 191 | row[arr_len*4+1]=row_id * 2 + 0 192 | col[arr_len*4+1]=col_id * 3 + 2 193 | dat[arr_len*4+1]=weight * dpos[1] 194 | 195 | row[arr_len*4+2]=row_id * 2 + 1 196 | col[arr_len*4+2]=col_id * 3 + 2 197 | dat[arr_len*4+2]=weight * dpos[0] 198 | 199 | row[arr_len*4+3]=row_id * 2 + 1 200 | col[arr_len*4+3]=col_id * 3 + 1 201 | dat[arr_len*4+3]=weight * dpos[1] 202 | arr_len = arr_len + 1 203 | col_num = col_num + 1 204 | print("-- done") 205 | print("construction time: %s seconds" % (time.time() - start_time)) 206 | return row, col, dat 207 | 208 | def getRhsVec(row_num) : 209 | rhs = np.zeros(row_num * 2) 210 | row_num = 0 211 | for i in range(0, n_grid): 212 | for j in range(0, n_grid): 213 | if grid_m[i, j] > 0 and i >= beam_x + 3: 214 | rhs[row_num * 2 + 0] = 0 215 | rhs[row_num * 2 + 1] = gravity * grid_m[i, j] 216 | row_num = row_num + 1 217 | return rhs 218 | 219 | def directSolverLsqr(A_sp, b) : 220 | print("direct solver - lsqr") 221 | start_time = time.time() 222 | c, istop, itn, normr = lsqr(A_sp, b)[:4] 223 | print("solver time: %s seconds" % (time.time() - start_time)) 224 | return c 225 | 226 | def evalAffine(f00, f11, f10): 227 | localF = np.array([[f00, f10], [f10, f11]]) 228 | U, S, Vt = np.linalg.svd(localF) 229 | R = U @ Vt 230 | S = Vt.T @ np.diag(S) @ Vt 231 | cauchy = (2 * mu * (localF - R) + la * np.trace(R.T @ localF - np.eye(2)) * R) @ localF.T 232 | affine = (-p_vol * 4 * inv_dx * inv_dx) * cauchy 233 | return affine 234 | 235 | def findSol(A0) : 236 | n = 3 237 | t0 = 1e-20 238 | h0 = 1 239 | prin = 0 240 | 241 | def f(r, n): 242 | A = evalAffine(r[0], r[1], r[2]) 243 | diff = A - A0 244 | val = diff[0, 0] * diff[0, 0] 245 | val += diff[0, 1] * diff[0, 1] 246 | val += diff[1, 0] * diff[1, 0] 247 | val += diff[1, 1] * diff[1, 1] 248 | return val 249 | 250 | r = np.array([1.0, 1.0, 0.0]) 251 | pr, r = praxis ( t0, h0, n, prin, r, f ) 252 | 253 | return r 254 | 255 | #################################################################### 256 | # functions for verification 257 | 258 | @ti.kernel 259 | def P2GStaticTest(): 260 | for p in x: 261 | base = (x[p] * inv_dx - 0.5).cast(int) 262 | fx = x[p] * inv_dx - base.cast(float) 263 | w = [0.5 * (1.5 - fx) ** 2, 0.75 - (fx - 1) ** 2, 0.5 * (fx - 0.5) ** 2] 264 | affine = F[p] 265 | for i, j in ti.static(ti.ndrange(3, 3)): 266 | offset = ti.Vector([i, j]) 267 | dpos = (offset.cast(float) - fx) * dx 268 | weight = w[i][0] * w[j][1] 269 | grid_v[base + offset] += weight * (affine @ dpos) 270 | grid_m[base + offset] += weight * p_mass 271 | 272 | def verifyGlobalStep(): 273 | cleanGrid() 274 | col_num = 0 275 | for p in range(0, n_particles): 276 | if x[p][0] >= (beam_x + 1) * dx: 277 | F[p][0, 0] = c[col_num * 3 + 0] 278 | F[p][1, 1] = c[col_num * 3 + 1] 279 | F[p][0, 1] = c[col_num * 3 + 2] 280 | F[p][1, 0] = c[col_num * 3 + 2] 281 | col_num = col_num + 1 282 | 283 | P2GStaticTest() 284 | 285 | for i in range(0, n_grid): 286 | for j in range(0, n_grid): 287 | if grid_m[i, j] > 0 and i >= beam_x + 3: 288 | if not np.isclose(grid_v[i, j][0], 0, atol = 1e-6) : 289 | print("Error in global step: ", i, j, grid_v[i, j][0] - 0) 290 | if not np.isclose(grid_v[i, j][1], gravity * grid_m[i, j], atol = 1e-6) : 291 | print("Error in global step: ", i, j, grid_v[i, j][1] - gravity * grid_m[i, j]) 292 | 293 | def verifyLocalStep(res_array, col_num): 294 | for i in range(0, col_num): 295 | affine = evalAffine(res_array[i * 3 + 0], res_array[i * 3 + 1], res_array[i * 3 + 2]) 296 | res_vec = np.array([affine[0, 0], affine[1, 1], affine[1, 0]]) 297 | tar_vec = np.array([c[i * 3], c[i * 3 + 1], c[i * 3 + 2]]) 298 | if not np.allclose(res_vec, tar_vec, atol = 1e-6): 299 | print("Error in local step: ", c[i * 3], c[i * 3 + 1], c[i * 3 + 2], res_vec, tar_vec, res_vec - tar_vec) 300 | 301 | #################################################################### 302 | # start from here 303 | #################################################################### 304 | 305 | initialize() 306 | 307 | if USE_SAGFREE_INIT: 308 | # get lhs matrix 309 | P2GStatic() 310 | row_num, col_num = computeRowAndColNum() 311 | row, col, dat = getSpMCoeff() 312 | A_sp = csc_matrix((dat, (row, col)), shape=(row_num * 2, col_num * 3)) 313 | At_sp = csc_matrix((dat, (col, row)), shape=(col_num * 3, row_num * 2)) 314 | 315 | # get rhs vector 316 | b = getRhsVec(row_num) 317 | 318 | # solve the global stage 319 | c = directSolverLsqr(A_sp, b) 320 | 321 | # verify results from the global stage 322 | verifyGlobalStep() 323 | 324 | # solve the local stage 325 | res_array = np.zeros(col_num * 3) 326 | for i in range(0, col_num) : 327 | res = findSol(np.array([[c[i * 3], c[i * 3 + 2]], [c[i * 3 + 2], c[i * 3 + 1]]])) 328 | res_array[i * 3 + 0] = res[0] 329 | res_array[i * 3 + 1] = res[1] 330 | res_array[i * 3 + 2] = res[2] 331 | 332 | # verify results from the local stage 333 | verifyLocalStep(res_array, col_num) 334 | 335 | # copy the results into F 336 | col_num = 0 337 | for p in range(0, n_particles): 338 | if x[p][0] >= (beam_x + 1) * dx: 339 | F[p][0, 0] = res_array[col_num * 3 + 0] 340 | F[p][1, 1] = res_array[col_num * 3 + 1] 341 | F[p][0, 1] = res_array[col_num * 3 + 2] 342 | F[p][1, 0] = res_array[col_num * 3 + 2] 343 | col_num = col_num + 1 344 | 345 | 346 | gui = ti.GUI("Sagfree elastic beam", res=512, background_color=0x222222) 347 | 348 | frame = 0 349 | while not gui.get_event(ti.GUI.ESCAPE, ti.GUI.EXIT): 350 | 351 | print("frame ", frame) 352 | if frame > 200 : 353 | gravity = -20.0 * np.sin(frame) 354 | frame = frame + 1 355 | 356 | for s in range(int(2e-3 // dt)): 357 | cleanGrid() 358 | P2G() 359 | updateGrid(gravity) 360 | G2P() 361 | gui.circles(x.to_numpy(), radius=1.5, color=0xED553B) 362 | 363 | gui.show() 364 | 365 | cleanGrid() 366 | -------------------------------------------------------------------------------- /demo_nosagfree.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kuiwuchn/SagFreeMPM/1b89c582c641848094b54f98043724f0c46ef3e6/demo_nosagfree.gif -------------------------------------------------------------------------------- /demo_sagfree.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kuiwuchn/SagFreeMPM/1b89c582c641848094b54f98043724f0c46ef3e6/demo_sagfree.gif -------------------------------------------------------------------------------- /praxis.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | # 3 | def beale_f ( x, n ): 4 | 5 | #*****************************************************************************80 6 | # 7 | ## BEALE_F evaluates the Beale function. 8 | # 9 | # Discussion: 10 | # 11 | # The function is the sum of the squares of three functions. 12 | # 13 | # This function has a valley approaching the line X(2) = 1. 14 | # 15 | # Licensing: 16 | # 17 | # This code is distributed under the GNU LGPL license. 18 | # 19 | # Modified: 20 | # 21 | # 01 August 2016 22 | # 23 | # Author: 24 | # 25 | # John Burkardt 26 | # 27 | # Reference: 28 | # 29 | # E Beale, 30 | # On an Iterative Method for Finding a Local Minimum of a Function 31 | # of More than One Variable, 32 | # Technical Report 25, Statistical Techniques Research Group, 33 | # Princeton University, 1958. 34 | # 35 | # Richard Brent, 36 | # Algorithms for Finding Zeros and Extrema of Functions Without 37 | # Calculating Derivatives, 38 | # Stanford University Technical Report STAN-CS-71-198. 39 | # 40 | # Parameters: 41 | # 42 | # Input, real X(N), the evaluation point. 43 | # 44 | # Input, integer N, the number of variables. 45 | # 46 | # Output, real VALUE, the function value. 47 | # 48 | c1 = 1.5 49 | c2 = 2.25 50 | c3 = 2.625 51 | 52 | fx1 = c1 - x[0] * ( 1.0 - x[1] ) 53 | fx2 = c2 - x[0] * ( 1.0 - x[1] ** 2 ) 54 | fx3 = c3 - x[0] * ( 1.0 - x[1] ** 3 ) 55 | 56 | value = fx1 ** 2 + fx2 ** 2 + fx3 ** 2 57 | 58 | return value 59 | 60 | def beale_test ( ): 61 | 62 | #*****************************************************************************80 63 | # 64 | ## BEALE_TEST calls PRAXIS for the Beale function. 65 | # 66 | # Licensing: 67 | # 68 | # This code is distributed under the GNU LGPL license. 69 | # 70 | # Modified: 71 | # 72 | # 04 August 2016 73 | # 74 | # Author: 75 | # 76 | # John Burkardt 77 | # 78 | import numpy as np 79 | import platform 80 | 81 | n = 2 82 | 83 | print ( '' ) 84 | print ( 'BEALE_TEST' ) 85 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 86 | print ( ' The Beale function.' ) 87 | 88 | t0 = 0.00001 89 | h0 = 0.25 90 | prin = 0 91 | 92 | x = np.array ( [ 0.1, 0.1 ] ) 93 | 94 | r8vec_print ( n, x, ' Initial point:' ) 95 | 96 | print ( ' Function value = %g' % ( beale_f ( x, n ) ) ) 97 | 98 | pr, x = praxis ( t0, h0, n, prin, x, beale_f ) 99 | 100 | r8vec_print ( n, x, ' Computed minimizer:' ) 101 | 102 | print ( ' Function value = %g' % ( beale_f ( x, n ) ) ) 103 | # 104 | # Terminate. 105 | # 106 | print ( '' ) 107 | print ( 'BEALE_TEST:' ) 108 | print ( ' Normal end of execution.' ) 109 | return 110 | 111 | def box_f ( x, n ): 112 | 113 | #*****************************************************************************80 114 | # 115 | ## BOX_F evaluates the Box function. 116 | # 117 | # Discussion: 118 | # 119 | # The function is formed by the sum of squares of 10 separate terms. 120 | # 121 | # Licensing: 122 | # 123 | # This code is distributed under the GNU LGPL license. 124 | # 125 | # Modified: 126 | # 127 | # 01 August 2016 128 | # 129 | # Author: 130 | # 131 | # John Burkardt 132 | # 133 | # Parameters: 134 | # 135 | # Input, real X(N), the evaluation point. 136 | # 137 | # Input, integer N, the number of variables. 138 | # 139 | # Output, real VALUE, the function value. 140 | # 141 | import numpy as np 142 | 143 | value = 0.0 144 | 145 | for i in range ( 1, 11 ): 146 | 147 | c = - i / 10.0 148 | 149 | fx = np.exp ( c * x[0] ) - np.exp ( c * x[1] ) \ 150 | - x[2] * ( np.exp ( c ) - np.exp ( 10.0 * c ) ) 151 | 152 | value = value + fx ** 2 153 | 154 | return value 155 | 156 | def box_test ( ): 157 | 158 | #*****************************************************************************80 159 | # 160 | ## BOX_TEST calls PRAXIS for the Box function. 161 | # 162 | # Licensing: 163 | # 164 | # This code is distributed under the GNU LGPL license. 165 | # 166 | # Modified: 167 | # 168 | # 01 August 2016 169 | # 170 | # Author: 171 | # 172 | # John Burkardt 173 | # 174 | import numpy as np 175 | import platform 176 | 177 | n = 3 178 | 179 | print ( '' ) 180 | print ( 'BOX_TEST' ) 181 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 182 | print ( ' The Box function.' ) 183 | 184 | t0 = 0.00001 185 | h0 = 20.0 186 | prin = 0 187 | 188 | x = np.array ( [ 0.0, 10.0, 20.0 ] ) 189 | 190 | r8vec_print ( n, x, ' Initial point:' ) 191 | 192 | print ( ' Function value = %g' % ( box_f ( x, n ) ) ) 193 | 194 | pr, x = praxis ( t0, h0, n, prin, x, box_f ) 195 | 196 | r8vec_print ( n, x, ' Computed minimizer:' ) 197 | 198 | print ( ' Function value = %g' % ( box_f ( x, n ) ) ) 199 | # 200 | # Terminate. 201 | # 202 | print ( '' ) 203 | print ( 'BOX_TEST:' ) 204 | print ( ' Normal end of execution.' ) 205 | return 206 | 207 | def chebyquad_f ( x, n ): 208 | 209 | #*****************************************************************************80 210 | # 211 | ## CHEBYQUAD_F evaluates the Chebyquad function. 212 | # 213 | # Discussion: 214 | # 215 | # The function is formed by the sum of squares of N separate terms. 216 | # 217 | # Licensing: 218 | # 219 | # This code is distributed under the GNU LGPL license. 220 | # 221 | # Modified: 222 | # 223 | # 04 August 2016 224 | # 225 | # Author: 226 | # 227 | # John Burkardt 228 | # 229 | # Parameters: 230 | # 231 | # Input, real X(N), the evaluation point. 232 | # 233 | # Input, integer N, the number of variables. 234 | # 235 | # Output, real VALUE, the function value. 236 | # 237 | import numpy as np 238 | 239 | fvec = np.zeros ( n ) 240 | 241 | for j in range ( 0, n ): 242 | 243 | t1 = 1.0; 244 | t2 = 2.0 * x[j] - 1.0 245 | t = 2.0 * t2 246 | 247 | for i in range ( 0, n ): 248 | fvec[i] = fvec[i] + t2 249 | th = t * t2 - t1 250 | t1 = t2 251 | t2 = th 252 | 253 | for i in range ( 0, n ): 254 | fvec[i] = fvec[i] / n 255 | if ( ( i % 2 ) == 1 ): 256 | fvec[i] = fvec[i] + 1.0 / ( i * ( i + 2 ) ) 257 | # 258 | # Compute F. 259 | # 260 | value = 0.0 261 | for i in range ( 0, n ): 262 | value = value + fvec[i] ** 2 263 | 264 | return value 265 | 266 | def chebyquad_test ( ): 267 | 268 | #*****************************************************************************80 269 | # 270 | ## CHEBYQUAD_TEST calls PRAXIS for the Chebyquad function. 271 | # 272 | # Licensing: 273 | # 274 | # This code is distributed under the GNU LGPL license. 275 | # 276 | # Modified: 277 | # 278 | # 01 August 2016 279 | # 280 | # Author: 281 | # 282 | # John Burkardt 283 | # 284 | import numpy as np 285 | import platform 286 | 287 | n = 8 288 | 289 | print ( '' ) 290 | print ( 'CHEBYQUAD_TEST' ) 291 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 292 | print ( ' The Chebyquad function.' ) 293 | 294 | t0 = 0.00001 295 | h0 = 0.1 296 | prin = 0 297 | 298 | x = np.zeros ( n ) 299 | 300 | for i in range ( 0, n ): 301 | x[i] = float ( i + 1 ) / float ( n + 1 ) 302 | 303 | r8vec_print ( n, x, ' Initial point:' ) 304 | 305 | print ( ' Function value = %g' % ( chebyquad_f ( x, n ) ) ) 306 | 307 | pr, x = praxis ( t0, h0, n, prin, x, chebyquad_f ) 308 | 309 | r8vec_print ( n, x, ' Computed minimizer:' ) 310 | 311 | print ( ' Function value = %g' % ( chebyquad_f ( x, n ) ) ) 312 | # 313 | # Terminate. 314 | # 315 | print ( '' ) 316 | print ( 'CHEBYQUAD_TEST:' ) 317 | print ( ' Normal end of execution.' ) 318 | return 319 | 320 | def cube_f ( x, n ): 321 | 322 | #*****************************************************************************80 323 | # 324 | ## CUBE_F evaluates the Cube function. 325 | # 326 | # Discussion: 327 | # 328 | # The function is the sum of the squares of two functions. 329 | # 330 | # Licensing: 331 | # 332 | # This code is distributed under the GNU LGPL license. 333 | # 334 | # Modified: 335 | # 336 | # 02 August 2016 337 | # 338 | # Author: 339 | # 340 | # John Burkardt 341 | # 342 | # Parameters: 343 | # 344 | # Input, real X(N), the evaluation point. 345 | # 346 | # Input, integer N, the number of variables. 347 | # 348 | # Output, real VALUE, the function value. 349 | # 350 | fx1 = 10.0 * ( x[1] - x[0] ** 3 ) 351 | fx2 = 1.0 - x[0] 352 | 353 | value = fx1 ** 2 + fx2 ** 2 354 | 355 | return value 356 | 357 | def cube_test ( ): 358 | 359 | #*****************************************************************************80 360 | # 361 | ## CUBE_TEST calls PRAXIS for the Cube function. 362 | # 363 | # Licensing: 364 | # 365 | # This code is distributed under the GNU LGPL license. 366 | # 367 | # Modified: 368 | # 369 | # 02 August 2016 370 | # 371 | # Author: 372 | # 373 | # John Burkardt 374 | # 375 | import numpy as np 376 | import platform 377 | 378 | n = 2 379 | 380 | print ( '' ) 381 | print ( 'CUBE_TEST' ) 382 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 383 | print ( ' The Cube function.' ) 384 | 385 | t0 = 0.00001 386 | h0 = 1.0 387 | prin = 0 388 | 389 | x = np.array ( [ -1.2, -1.0 ] ) 390 | 391 | r8vec_print ( n, x, ' Initial point:' ) 392 | 393 | print ( ' Function value = %g' % ( cube_f ( x, n ) ) ) 394 | 395 | pr, x = praxis ( t0, h0, n, prin, x, cube_f ) 396 | 397 | r8vec_print ( n, x, ' Computed minimizer:' ) 398 | 399 | print ( ' Function value = %g' % ( cube_f ( x, n ) ) ) 400 | # 401 | # Terminate. 402 | # 403 | print ( '' ) 404 | print ( 'CUBE_TEST:' ) 405 | print ( ' Normal end of execution.' ) 406 | return 407 | 408 | def helix_f ( x, n ): 409 | 410 | #*****************************************************************************80 411 | # 412 | ## HELIX_F evaluates the Helix function. 413 | # 414 | # Discussion: 415 | # 416 | # The function is the sum of the squares of three functions. 417 | # 418 | # Licensing: 419 | # 420 | # This code is distributed under the GNU LGPL license. 421 | # 422 | # Modified: 423 | # 424 | # 04 August 2016 425 | # 426 | # Author: 427 | # 428 | # John Burkardt 429 | # 430 | # Parameters: 431 | # 432 | # Input, real X(N), the evaluation point. 433 | # 434 | # Input, integer N, the number of variables. 435 | # 436 | # Output, real VALUE, the function value. 437 | # 438 | import numpy as np 439 | 440 | r = np.linalg.norm ( x ) 441 | 442 | if ( 0.0 <= x[0] ): 443 | theta = 0.5 * np.arctan2 ( x[1], x[0] ) / np.pi 444 | else: 445 | theta = 0.5 * ( np.arctan2 ( x[1], x[0] ) + np.pi ) / np.pi 446 | 447 | fx1 = 10.0 * ( x[2] - 10.0 * theta ) 448 | fx2 = 10.0 * ( r - 1.0 ) 449 | fx3 = x[2] 450 | 451 | value = fx1 ** 2 + fx2 ** 2 + fx3 ** 2 452 | 453 | return value 454 | 455 | def helix_test ( ): 456 | 457 | #*****************************************************************************80 458 | # 459 | ## HELIX_TEST calls PRAXIS for the Fletcher-Powell Helix function. 460 | # 461 | # Licensing: 462 | # 463 | # This code is distributed under the GNU LGPL license. 464 | # 465 | # Modified: 466 | # 467 | # 03 August 2016 468 | # 469 | # Author: 470 | # 471 | # John Burkardt 472 | # 473 | import numpy as np 474 | import platform 475 | 476 | n = 3 477 | 478 | print ( '' ) 479 | print ( 'HELIX_TEST' ) 480 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 481 | print ( ' The Fletcher-Powell Helix function.' ) 482 | 483 | t0 = 0.00001 484 | h0 = 1.0 485 | prin = 0 486 | 487 | x = np.array ( [ -1.0, 0.0, 0.0 ] ) 488 | 489 | r8vec_print ( n, x, ' Initial point:' ) 490 | 491 | print ( ' Function value = %g' % ( helix_f ( x, n ) ) ) 492 | 493 | pr, x = praxis ( t0, h0, n, prin, x, helix_f ) 494 | 495 | r8vec_print ( n, x, ' Computed minimizer:' ) 496 | 497 | print ( ' Function value = %g' % ( helix_f ( x, n ) ) ) 498 | # 499 | # Terminate. 500 | # 501 | print ( '' ) 502 | print ( 'HELIX_TEST:' ) 503 | print ( ' Normal end of execution.' ) 504 | return 505 | 506 | def hilbert_f ( x, n ): 507 | 508 | #*****************************************************************************80 509 | # 510 | ## HILBERT_F evaluates the Hilbert function. 511 | # 512 | # Discussion: 513 | # 514 | # The function is a positive definite quadratic function of the form 515 | # 516 | # f(x) = x' A x 517 | # 518 | # where A is the Hilbert matrix, A(I,J) = 1/(I+J-1). 519 | # 520 | # Licensing: 521 | # 522 | # This code is distributed under the GNU LGPL license. 523 | # 524 | # Modified: 525 | # 526 | # 02 August 2016 527 | # 528 | # Author: 529 | # 530 | # John Burkardt 531 | # 532 | # Parameters: 533 | # 534 | # Input, real X(N), the evaluation point. 535 | # 536 | # Input, integer N, the number of variables. 537 | # 538 | # Output, real VALUE, the function value. 539 | # 540 | value = 0.0 541 | 542 | for i in range ( 0, n ): 543 | for j in range ( 0, n ): 544 | value = value + x[i] * x[j] / ( i + j + 1 ) 545 | 546 | return value 547 | 548 | def hilbert_test ( ): 549 | 550 | #*****************************************************************************80 551 | # 552 | ## HILBERT_TEST calls PRAXIS for the Hilbert function. 553 | # 554 | # Licensing: 555 | # 556 | # This code is distributed under the GNU LGPL license. 557 | # 558 | # Modified: 559 | # 560 | # 03 August 2016 561 | # 562 | # Author: 563 | # 564 | # John Burkardt 565 | # 566 | import numpy as np 567 | import platform 568 | 569 | n = 10 570 | 571 | print ( '' ) 572 | print ( 'HILBERT_TEST' ) 573 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 574 | print ( ' The Hilbert function.' ) 575 | 576 | t0 = 0.00001 577 | h0 = 10.0 578 | prin = 0 579 | 580 | x = np.ones ( n ) 581 | 582 | r8vec_print ( n, x, ' Initial point:' ) 583 | 584 | print ( ' Function value = %g' % ( hilbert_f ( x, n ) ) ) 585 | 586 | pr, x = praxis ( t0, h0, n, prin, x, hilbert_f ) 587 | 588 | r8vec_print ( n, x, ' Computed minimizer:' ) 589 | 590 | print ( ' Function value = %g' % ( hilbert_f ( x, n ) ) ) 591 | # 592 | # Terminate. 593 | # 594 | print ( '' ) 595 | print ( 'HILBERT_TEST:' ) 596 | print ( ' Normal end of execution.' ) 597 | return 598 | 599 | def powell3d_f ( x, n ): 600 | 601 | #*****************************************************************************80 602 | # 603 | ## POWELL3D_F evaluates the Powell 3D function. 604 | # 605 | # Licensing: 606 | # 607 | # This code is distributed under the GNU LGPL license. 608 | # 609 | # Modified: 610 | # 611 | # 03 August 2016 612 | # 613 | # Author: 614 | # 615 | # John Burkardt 616 | # 617 | # Reference: 618 | # 619 | # M J D Powell, 620 | # An Efficient Method for Finding the Minimum of a Function of 621 | # Several Variables Without Calculating Derivatives, 622 | # Computer Journal, 623 | # Volume 7, Number 2, pages 155-162, 1964. 624 | # 625 | # Parameters: 626 | # 627 | # Input, real X(N), the evaluation point. 628 | # 629 | # Input, integer N, the number of variables. 630 | # 631 | # Output, real VALUE, the function value. 632 | # 633 | import numpy as np 634 | 635 | value = 3.0 - 1.0 / ( 1.0 + ( x[0] - x[1] ) ** 2 ) \ 636 | - np.sin ( 0.5 * np.pi * x[1] * x[2] ) \ 637 | - np.exp ( - ( ( x[0] - 2.0 * x[1] + x[2] ) / x[1] ) ** 2 ) 638 | 639 | return value 640 | 641 | def powell3d_test ( ): 642 | 643 | #*****************************************************************************80 644 | # 645 | ## POWELL3D_TEST calls PRAXIS for the Powell 3D function. 646 | # 647 | # Licensing: 648 | # 649 | # This code is distributed under the GNU LGPL license. 650 | # 651 | # Modified: 652 | # 653 | # 03 August 2016 654 | # 655 | # Author: 656 | # 657 | # John Burkardt 658 | # 659 | import numpy as np 660 | import platform 661 | 662 | n = 3 663 | 664 | print ( '' ) 665 | print ( 'POWELL3D_TEST' ) 666 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 667 | print ( ' The Powell 3D function.' ) 668 | 669 | t0 = 0.00001 670 | h0 = 1.0 671 | prin = 0 672 | 673 | x = np.array ( [ 0.0, 1.0, 2.0 ] ) 674 | 675 | r8vec_print ( n, x, ' Initial point:' ) 676 | 677 | print ( ' Function value = %g' % ( powell3d_f ( x, n ) ) ) 678 | 679 | pr, x = praxis ( t0, h0, n, prin, x, powell3d_f ) 680 | 681 | r8vec_print ( n, x, ' Computed minimizer:' ) 682 | 683 | print ( ' Function value = %g' % ( powell3d_f ( x, n ) ) ) 684 | # 685 | # Terminate. 686 | # 687 | print ( '' ) 688 | print ( 'POWELL3D_TEST:' ) 689 | print ( ' Normal end of execution.' ) 690 | return 691 | 692 | def flin ( n, jsearch, l, f, x, nf, v, q0, q1, qd0, qd1, qa, qb, qc ): 693 | 694 | #*****************************************************************************80 695 | # 696 | ## FLIN is the function of one variable to be minimized by MINNY. 697 | # 698 | # Discussion: 699 | # 700 | # F(X) is a scalar function of a vector argument X. 701 | # 702 | # A minimizer of F(X) is sought along a line or parabola. 703 | # 704 | # This function has been modified, by removing the occurrence of a 705 | # common block, so that it looks more like a "normal" function that does 706 | # not rely so strongly on peculiarities of FORTRAN. 707 | # 708 | # Licensing: 709 | # 710 | # This code is distributed under the GNU LGPL license. 711 | # 712 | # Modified: 713 | # 714 | # 01 August 2016 715 | # 716 | # Author: 717 | # 718 | # Original FORTRAN77 version by Richard Brent. 719 | # Python version by John Burkardt. 720 | # 721 | # Reference: 722 | # 723 | # Richard Brent, 724 | # Algorithms for Minimization with Derivatives, 725 | # Prentice Hall, 1973, 726 | # Reprinted by Dover, 2002. 727 | # 728 | # Parameters: 729 | # 730 | # Input, integer N, the number of variables. 731 | # 732 | # Input, integer JSEARCH, indicates the kind of search. 733 | # If J is a legal column index, linear search in direction of V(*,JSEARCH). 734 | # Otherwise, then the search is parabolic, based on X, Q0 and Q1. 735 | # 736 | # Input, real L, is the parameter determining the particular 737 | # point at which F is to be evaluated. 738 | # For a linear search, L is the step size. 739 | # For a quadratic search, L is a parameter which specifies 740 | # a point in the plane of X, Q0 and Q1. 741 | # 742 | # Input, real F ( X, N ), the function to be minimized. 743 | # 744 | # Input, real X(N), the base point of the search. 745 | # 746 | # Input/output, integer NF, the function evaluation counter. 747 | # 748 | # Input, real V(N,N), a matrix whose columns constitute 749 | # search directions. 750 | # 751 | # Input, real Q0(N), Q1(N), two auxiliary points used to 752 | # determine the plane when a quadratic search is performed. 753 | # 754 | # Input, real QD0, QD1, values needed to compute the 755 | # coefficients QA, QB, QC. 756 | # 757 | # Input/output, real QA, QB, QC, coefficients used to combine 758 | # Q0, X, and A1 if a quadratic search is used. (Yes, technically 759 | # these are input quantities as well.) 760 | # 761 | # Output, real VALUE, the value of the function at the 762 | # minimizing point. 763 | # 764 | import numpy as np 765 | 766 | t = np.zeros ( n ) 767 | # 768 | # The search is linear. 769 | # 770 | if ( 0 <= jsearch ): 771 | 772 | t[0:n] = x[0:n] + l * v[0:n,jsearch] 773 | # 774 | # The search is along a parabolic space curve. 775 | # 776 | else: 777 | 778 | qa = l * ( l - qd1 ) / ( qd0 + qd1 ) / qd0 779 | qb = - ( l + qd0 ) * ( l - qd1 ) / qd1 / qd0 780 | qc = ( l + qd0 ) * l / qd1 / ( qd0 + qd1 ) 781 | 782 | t[0:n] = qa * q0[0:n] + qb * x[0:n] + qc * q1[0:n] 783 | # 784 | # The function evaluation counter NF is incremented. 785 | # 786 | nf = nf + 1 787 | # 788 | # Evaluate the function. 789 | # 790 | value = f ( t, n ) 791 | 792 | return value, nf, qa, qb, qc 793 | 794 | def minfit ( n, tol, a ): 795 | 796 | #*****************************************************************************80 797 | # 798 | ## MINFIT computes the singular value decomposition of an N by N array. 799 | # 800 | # Discussion: 801 | # 802 | # This is an improved version of the EISPACK routine MINFIT 803 | # restricted to the case M = N and P = 0. 804 | # 805 | # The singular values of the array A are returned in Q. A is 806 | # overwritten with the orthogonal matrix V such that U * diag(Q) = A * V, 807 | # where U is another orthogonal matrix. 808 | # 809 | # Licensing: 810 | # 811 | # This code is distributed under the GNU LGPL license. 812 | # 813 | # Modified: 814 | # 815 | # 01 August 2016 816 | # 817 | # Author: 818 | # 819 | # Original FORTRAN77 version by Richard Brent. 820 | # Python version by John Burkardt. 821 | # 822 | # Reference: 823 | # 824 | # Richard Brent, 825 | # Algorithms for Minimization with Derivatives, 826 | # Prentice Hall, 1973, 827 | # Reprinted by Dover, 2002. 828 | # 829 | # James Wilkinson, Christian Reinsch, 830 | # Handbook for Automatic Computation, 831 | # Volume II, Linear Algebra, Part 2, 832 | # Springer Verlag, 1971. 833 | # 834 | # Brian Smith, James Boyle, Jack Dongarra, Burton Garbow, Yasuhiko Ikebe, 835 | # Virginia Klema, Cleve Moler, 836 | # Matrix Eigensystem Routines, EISPACK Guide, 837 | # Lecture Notes in Computer Science, Volume 6, 838 | # Springer Verlag, 1976, 839 | # ISBN13: 978-3540075462, 840 | # LC: QA193.M37. 841 | # 842 | # Parameters: 843 | # 844 | # Input, integer N, the order of the matrix A. 845 | # 846 | # Input, real TOL, a tolerance which determines when a vector 847 | # (a column or part of a column of the matrix) may be considered 848 | # "essentially" equal to zero. 849 | # 850 | # Input/output, real A(N,N). On input, an N by N array whose 851 | # singular value decomposition is desired. On output, the 852 | # SVD orthogonal matrix factor V. 853 | # 854 | # Output, real Q(N), the singular values. 855 | # 856 | import numpy as np 857 | 858 | kt_max = 30 859 | 860 | e = np.zeros ( n ) 861 | q = np.zeros ( n ) 862 | # 863 | # Householder's reduction to bidiagonal form. 864 | # 865 | if ( n == 1 ): 866 | q[0] = a[0,0] 867 | a[0,0] = 1.0 868 | return a, q 869 | 870 | g = 0.0 871 | x = 0.0 872 | 873 | for i in range ( 0, n ): 874 | 875 | e[i] = g 876 | l = i + 1 877 | 878 | s = 0.0 879 | for i1 in range ( i, n ): 880 | s = s + a[i1,i] ** 2 881 | 882 | g = 0.0 883 | 884 | if ( tol <= s ): 885 | 886 | f = a[i,i] 887 | 888 | g = np.sqrt ( s ) 889 | if ( 0.0 <= f ): 890 | g = - g 891 | 892 | h = f * g - s 893 | a[i,i] = f - g 894 | 895 | for j in range ( l, n ): 896 | 897 | f = 0.0 898 | for i1 in range ( i, n ): 899 | f = f + a[i1,i] * a[i1,j] 900 | f = f / h 901 | 902 | for i1 in range ( i, n ): 903 | a[i1,j] = a[i1,j] + f * a[i1,i] 904 | 905 | q[i] = g 906 | 907 | s = 0.0 908 | for j1 in range ( l, n ): 909 | s = s + a[i,j1] ** 2 910 | 911 | g = 0.0 912 | 913 | if ( tol <= s ): 914 | 915 | if ( i < n - 1 ): 916 | f = a[i,i+1] 917 | 918 | g = np.sqrt ( s ) 919 | if ( 0.0 <= f ): 920 | g = - g 921 | 922 | h = f * g - s 923 | 924 | if ( i < n - 1 ): 925 | 926 | a[i,i+1] = f - g 927 | 928 | for j1 in range ( l, n ): 929 | e[j1] = a[i,j1] / h 930 | 931 | for j in range ( l, n ): 932 | 933 | s = 0.0 934 | for j1 in range ( l, n ): 935 | s = s + a[j,j1] * a[i,j1] 936 | 937 | for j1 in range ( l, n ): 938 | a[j,j1] = a[j,j1] + s * e[j1] 939 | 940 | y = abs ( q[i] ) + abs ( e[i] ) 941 | 942 | x = max ( x, y ) 943 | # 944 | # Accumulation of right-hand transformations. 945 | # 946 | a[n-1,n-1] = 1.0 947 | g = e[n-1] 948 | l = n - 1 949 | 950 | for i in range ( n - 2, -1, -1 ): 951 | 952 | if ( g != 0.0 ): 953 | 954 | h = a[i,i+1] * g 955 | 956 | for i1 in range ( l, n ): 957 | a[i1,i] = a[i,i1] / h 958 | 959 | for j in range ( l, n ): 960 | 961 | s = 0.0 962 | for j1 in range ( l, n ): 963 | s = s + a[i,j1] * a[j1,j] 964 | 965 | for i1 in range ( l, n ): 966 | a[i1,j] = a[i1,j] + s * a[i1,i] 967 | 968 | for j1 in range ( l, n ): 969 | a[i,j1] = 0.0 970 | 971 | for i1 in range ( l, n ): 972 | a[i1,i] = 0.0 973 | 974 | a[i,i] = 1.0 975 | 976 | g = e[i] 977 | 978 | l = i 979 | # 980 | # Diagonalization of the bidiagonal form. 981 | # 982 | epsx = r8_epsilon ( ) * x 983 | 984 | for k in range ( n - 1, -1, -1 ): 985 | 986 | kt = 0 987 | 988 | while ( True ): 989 | 990 | kt = kt + 1 991 | 992 | if ( kt_max < kt ): 993 | e[k] = 0.0 994 | print ( '' ) 995 | print ( 'MINFIT - Fatal error!' ) 996 | print ( ' The QR algorithm failed to converge.' ) 997 | exit ( 'MINFIT - Fatal error!' ) 998 | 999 | skip = False 1000 | 1001 | for l2 in range ( k, -1, -1 ): 1002 | 1003 | l = l2 1004 | 1005 | if ( abs ( e[l] ) <= epsx ): 1006 | skip = True 1007 | break 1008 | 1009 | if ( 0 < l ): 1010 | if ( abs ( q[l-1] ) <= epsx ): 1011 | break 1012 | # 1013 | # Cancellation of E(L) if 1 < L. 1014 | # 1015 | if ( not skip ): 1016 | 1017 | c = 0.0 1018 | s = 1.0 1019 | 1020 | for i in range ( l, k + 1 ): 1021 | 1022 | f = s * e[i] 1023 | e[i] = c * e[i] 1024 | 1025 | if ( abs ( f ) <= epsx ): 1026 | break 1027 | 1028 | g = q[i] 1029 | # 1030 | # q(i) = h = sqrt(g*g + f*f). 1031 | # 1032 | h = r8_hypot ( f, g ) 1033 | 1034 | q[i] = h 1035 | 1036 | if ( h == 0.0 ): 1037 | g = 1.0 1038 | h = 1.0 1039 | 1040 | c = g / h 1041 | s = - f / h 1042 | # 1043 | # Test for convergence for this index K. 1044 | # 1045 | z = q[k] 1046 | 1047 | if ( l == k ): 1048 | if ( z < 0.0 ): 1049 | q[k] = - z 1050 | for i1 in range ( 0, n ): 1051 | a[i1,k] = - a[i1,k] 1052 | break 1053 | # 1054 | # Shift from bottom 2*2 minor. 1055 | # 1056 | x = q[l] 1057 | y = q[k-1] 1058 | g = e[k-1] 1059 | h = e[k] 1060 | f = ( ( y - z ) * ( y + z ) + ( g - h ) * ( g + h ) ) / ( 2.0 * h * y ) 1061 | 1062 | g = r8_hypot ( f, 1.0 ) 1063 | 1064 | if ( f < 0.0 ): 1065 | temp = f - g 1066 | else: 1067 | temp = f + g 1068 | 1069 | f = ( ( x - z ) * ( x + z ) + h * ( y / temp - h ) ) / x 1070 | # 1071 | # Next QR transformation. 1072 | # 1073 | c = 1.0 1074 | s = 1.0 1075 | 1076 | for i in range ( l + 1, k + 1 ): 1077 | 1078 | g = e[i] 1079 | y = q[i] 1080 | h = s * g 1081 | g = g * c 1082 | 1083 | z = r8_hypot ( f, h ) 1084 | 1085 | e[i-1] = z 1086 | 1087 | if ( z == 0.0 ): 1088 | f = 1.0 1089 | z = 1.0 1090 | 1091 | c = f / z 1092 | s = h / z 1093 | f = x * c + g * s 1094 | g = - x * s + g * c 1095 | h = y * s 1096 | y = y * c 1097 | 1098 | for j in range ( 0, n ): 1099 | x = a[j,i-1] 1100 | z = a[j,i] 1101 | a[j,i-1] = x * c + z * s 1102 | a[j,i] = - x * s + z * c 1103 | 1104 | z = r8_hypot ( f, h ) 1105 | 1106 | q[i-1] = z 1107 | 1108 | if ( z == 0.0 ): 1109 | f = 1.0 1110 | z = 1.0 1111 | 1112 | c = f / z 1113 | s = h / z 1114 | f = c * g + s * y 1115 | x = - s * g + c * y 1116 | 1117 | e[l] = 0.0 1118 | e[k] = f 1119 | q[k] = x 1120 | 1121 | return a, q 1122 | 1123 | def minfit_test ( ): 1124 | 1125 | #*****************************************************************************80 1126 | # 1127 | ## MINFIT_TEST tests MINFIT, which is a sort of SVD computation. 1128 | # 1129 | # Licensing: 1130 | # 1131 | # This code is distributed under the GNU LGPL license. 1132 | # 1133 | # Modified: 1134 | # 1135 | # 02 August 2016 1136 | # 1137 | # Author: 1138 | # 1139 | # John Burkardt 1140 | # 1141 | import numpy as np 1142 | import platform 1143 | 1144 | n = 5 1145 | 1146 | print ( '' ) 1147 | print ( 'MINFIT_TEST' ) 1148 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 1149 | print ( ' MINFIT computes part of the SVD of a matrix A.' ) 1150 | print ( ' SVD: A = U * D * V\'' ) 1151 | print ( ' MINFIT is given A, and returns the diagonal D' ) 1152 | print ( ' and the orthogonal matrix V.' ) 1153 | 1154 | a = np.zeros ( [ n, n ] ) 1155 | 1156 | for i in range ( 0, n ): 1157 | a[i,i] = 2.0 1158 | 1159 | for i in range ( 0, n - 1 ): 1160 | a[i,i+1] = -1.0 1161 | 1162 | for i in range ( 1, n ): 1163 | a[i,i-1] = -1.0 1164 | 1165 | r8mat_print ( n, n, a, ' The matrix A:' ) 1166 | # 1167 | # Numpy's EPS function is not easy to find! 1168 | # 1169 | eps = r8_epsilon ( ) 1170 | 1171 | tol = np.sqrt ( eps ) 1172 | 1173 | a, d = minfit ( n, tol, a ) 1174 | 1175 | r8mat_print ( n, n, a, ' The vector V:' ) 1176 | 1177 | r8vec_print ( n, d, ' The singular values D:' ) 1178 | # 1179 | # Because A is positive definite symmetric, the "missing" matrix V = U. 1180 | # 1181 | print ( '' ) 1182 | print ( ' Because A is positive definite symmetric,' ) 1183 | print ( ' we can reconstruct it as A = V * D * V\'' ) 1184 | 1185 | a2 = np.zeros ( [ n, n ] ) 1186 | 1187 | for i in range ( 0, n ): 1188 | for j in range ( 0, n ): 1189 | for k in range ( 0, n ): 1190 | a2[i,j] = a2[i,j] + a[i,k] * d[k] * a[j,k] 1191 | 1192 | r8mat_print ( n, n, a2, ' The product A2 = V * D * V\'' ) 1193 | # 1194 | # Terminate. 1195 | # 1196 | print ( '' ) 1197 | print ( 'MINFIT_TEST:' ) 1198 | print ( ' Normal end of execution.' ) 1199 | return 1200 | 1201 | def minny ( n, jsearch, nits, d2, x1, f1, fk, f, x, t, h, v, q0, q1, \ 1202 | nl, nf, dmin, ldt, fx, qa, qb, qc, qd0, qd1 ): 1203 | 1204 | #*****************************************************************************80 1205 | # 1206 | ## MINNY minimizes a scalar function of N variables along a line. 1207 | # 1208 | # Discussion: 1209 | # 1210 | # MINNY minimizes F along the line from X in the direction V(*,J) unless 1211 | # J is less than 1, when a quadratic search is made in the plane 1212 | # defined by Q0, Q1 and X. 1213 | # 1214 | # If FK = true, then F1 is FLIN(X1). Otherwise X1 and F1 are ignored 1215 | # on entry unless final FX is greater than F1. 1216 | # 1217 | # This function was modified by removing the common blocks 1218 | # and the use of labeled statements, 28 July 2016. 1219 | # 1220 | # Licensing: 1221 | # 1222 | # This code is distributed under the GNU LGPL license. 1223 | # 1224 | # Modified: 1225 | # 1226 | # 03 August 2016 1227 | # 1228 | # Author: 1229 | # 1230 | # Original FORTRAN77 version by Richard Brent. 1231 | # Python version by John Burkardt. 1232 | # 1233 | # Reference: 1234 | # 1235 | # Richard Brent, 1236 | # Algorithms for Minimization with Derivatives, 1237 | # Prentice Hall, 1973, 1238 | # Reprinted by Dover, 2002. 1239 | # 1240 | # Parameters: 1241 | # 1242 | # Input, integer N, the number of variables. 1243 | # 1244 | # Input, integer JSEARCH, indicates the kind of search. 1245 | # If JSEARCH is a legal column index, linear search in direction of V(*,J). 1246 | # Otherwise, the search is parabolic, based on X, Q0 and Q1. 1247 | # 1248 | # Input, integer NITS, the maximum number of times the interval 1249 | # may be halved to retry the calculation. 1250 | # 1251 | # Input/output, real D2, is either zero, or an approximation to 1252 | # the value of (1/2) times the second derivative of F. 1253 | # 1254 | # Input/output, real X1, on entry, an estimate of the 1255 | # distance from X to the minimum along V(*,J), or, if J = 0, a curve. 1256 | # On output, the distance between X and the minimizer that was found. 1257 | # 1258 | # Input/output, real F1, ? 1259 | # 1260 | # Input, logical FK if FK is TRUE, then on input F1 contains 1261 | # the value FLIN(X1). 1262 | # 1263 | # Input, real F ( X, N ), the function to be minimized. 1264 | # 1265 | # Input/output, real X(N), ? 1266 | # 1267 | # Input, real T, ? 1268 | # 1269 | # Input, real H, ? 1270 | # 1271 | # Input, real V(N,N), a matrix whose columns are direction 1272 | # vectors along which the function may be minimized. 1273 | # 1274 | # Input, real Q0(N), an auxiliary point used to define 1275 | # a curve through X. 1276 | # 1277 | # Input, real Q1(N), an auxiliary point used to define 1278 | # a curve through X. 1279 | # 1280 | # Input/output, integer NL, the number of linear searches. 1281 | # 1282 | # Input/output, integer NF, the number of function evaluations. 1283 | # 1284 | # Input, real DMIN, an estimate for the smallest eigenvalue. 1285 | # 1286 | # Input, real LDT, the length of the step. 1287 | # 1288 | # Input/output, real FX, the value of F(X,N). 1289 | # 1290 | # Input/output, real QA, QB, QC, ? 1291 | # 1292 | # Input, real QD0, QD1, ?. 1293 | # 1294 | import numpy as np 1295 | 1296 | machep = r8_epsilon ( ) 1297 | small = machep ** 2 1298 | m2 = np.sqrt ( machep ) 1299 | m4 = np.sqrt ( m2 ) 1300 | sf1 = f1 1301 | sx1 = x1 1302 | k = 0 1303 | xm = 0.0 1304 | fm = fx 1305 | f0 = fx 1306 | dz = ( d2 < machep ) 1307 | # 1308 | # Find the step size. 1309 | # 1310 | s = np.linalg.norm ( x ) 1311 | 1312 | if ( dz ): 1313 | temp = dmin 1314 | else: 1315 | temp = d2 1316 | 1317 | t2 = m4 * np.sqrt ( abs ( fx ) / temp + s * ldt ) + m2 * ldt 1318 | s = m4 * s + t 1319 | if ( dz and s < t2 ): 1320 | t2 = s 1321 | 1322 | t2 = max ( t2, small ) 1323 | t2 = min ( t2, 0.01 * h ) 1324 | 1325 | if ( fk and f1 <= fm ): 1326 | xm = x1 1327 | fm = f1 1328 | 1329 | if ( ( not fk ) or abs ( x1 ) < t2 ): 1330 | 1331 | if ( 0.0 <= x1 ): 1332 | temp = 1.0 1333 | else: 1334 | temp = - 1.0 1335 | 1336 | x1 = temp * t2 1337 | 1338 | f1, nf, qa, qb, qc = flin ( n, jsearch, x1, f, x, nf, v, \ 1339 | q0, q1, qd0, qd1, qa, qb, qc ) 1340 | 1341 | if ( f1 <= fm ): 1342 | xm = x1 1343 | fm = f1 1344 | # 1345 | # Evaluate FLIN at another point and estimate the second derivative. 1346 | # 1347 | while ( True ): 1348 | 1349 | if ( dz ): 1350 | 1351 | if ( f1 <= f0 ): 1352 | x2 = 2.0 * x1 1353 | else: 1354 | x2 = - x1 1355 | 1356 | f2, nf, qa, qb, qc = flin ( n, jsearch, x2, f, x, nf, v, \ 1357 | q0, q1, qd0, qd1, qa, qb, qc ) 1358 | 1359 | if ( f2 <= fm ): 1360 | xm = x2 1361 | fm = f2 1362 | 1363 | d2 = ( x2 * ( f1 - f0 ) - x1 * ( f2 - f0 ) ) \ 1364 | / ( ( x1 * x2 ) * ( x1 - x2 ) ) 1365 | # 1366 | # Estimate the first derivative at 0. 1367 | # 1368 | d1 = ( f1 - f0 ) / x1 - x1 * d2 1369 | dz = True 1370 | # 1371 | # Predict the minimum. 1372 | # 1373 | if ( d2 <= small ): 1374 | 1375 | if ( 0.0 <= d1 ): 1376 | x2 = - h 1377 | else: 1378 | x2 = h 1379 | 1380 | else: 1381 | 1382 | x2 = ( - 0.5 * d1 ) / d2 1383 | 1384 | if ( h < abs ( x2 ) ): 1385 | 1386 | if ( x2 <= 0.0 ): 1387 | x2 = - h 1388 | else: 1389 | x2 = h 1390 | # 1391 | # Evaluate F at the predicted minimum. 1392 | # 1393 | ok = True 1394 | 1395 | while ( True ): 1396 | 1397 | f2, nf, qa, qb, qc = flin ( n, jsearch, x2, f, x, nf, v, \ 1398 | q0, q1, qd0, qd1, qa, qb, qc ) 1399 | 1400 | if ( nits <= k or f2 <= f0 ): 1401 | break 1402 | 1403 | k = k + 1 1404 | 1405 | if ( f0 < f1 and 0.0 < x1 * x2 ): 1406 | ok = False 1407 | break 1408 | 1409 | x2 = 0.5 * x2 1410 | 1411 | if ( ok ): 1412 | break 1413 | # 1414 | # Increment the one-dimensional search counter. 1415 | # 1416 | nl = nl + 1 1417 | 1418 | if ( fm < f2 ): 1419 | x2 = xm 1420 | else: 1421 | fm = f2 1422 | # 1423 | # Get a new estimate of the second derivative. 1424 | # 1425 | if ( small < abs ( x2 * ( x2 - x1 ) ) ): 1426 | d2 = ( x2 * ( f1 - f0 ) - x1 * ( fm - f0 ) ) / ( ( x1 * x2 ) * ( x1 - x2 ) ) 1427 | else: 1428 | if ( 0 < k ): 1429 | d2 = 0.0 1430 | 1431 | d2 = max ( d2, small ) 1432 | 1433 | x1 = x2 1434 | fx = fm 1435 | 1436 | if ( sf1 < fx ): 1437 | fx = sf1 1438 | x1 = sx1 1439 | # 1440 | # Update X for linear but not parabolic search. 1441 | # 1442 | if ( 0 <= jsearch ): 1443 | x[0:n] = x[0:n] + x1 * v[0:n,jsearch] 1444 | 1445 | return d2, x1, f1, x, nl, nf, fx, qa, qb, qc 1446 | 1447 | def praxis ( t0, h0, n, prin, x, f ): 1448 | 1449 | #*****************************************************************************80 1450 | # 1451 | ## PRAXIS seeks an N-dimensional minimizer X of a scalar function F(X). 1452 | # 1453 | # Discussion: 1454 | # 1455 | # PRAXIS returns the minimum of the function F(X,N) of N variables 1456 | # using the principal axis method. The gradient of the function is 1457 | # not required. 1458 | # 1459 | # The approximating quadratic form is 1460 | # 1461 | # Q(x') = F(x,n) + (1/2) * (x'-x)' * A * (x'-x) 1462 | # 1463 | # where X is the best estimate of the minimum and 1464 | # 1465 | # A = inverse(V') * D * inverse(V) 1466 | # 1467 | # V(*,*) is the matrix of search directions 1468 | # D(*) is the array of second differences. 1469 | # 1470 | # If F(X) has continuous second derivatives near X0, then A will tend 1471 | # to the hessian of F at X0 as X approaches X0. 1472 | # 1473 | # Licensing: 1474 | # 1475 | # This code is distributed under the GNU LGPL license. 1476 | # 1477 | # Modified: 1478 | # 1479 | # 03 August 2016 1480 | # 1481 | # Author: 1482 | # 1483 | # Original FORTRAN77 version by Richard Brent. 1484 | # Python version by John Burkardt. 1485 | # 1486 | # Reference: 1487 | # 1488 | # Richard Brent, 1489 | # Algorithms for Minimization with Derivatives, 1490 | # Prentice Hall, 1973, 1491 | # Reprinted by Dover, 2002. 1492 | # 1493 | # Parameters: 1494 | # 1495 | # Input, real T0, is a tolerance. PRAXIS attempts to return 1496 | # praxis = f(x) such that if X0 is the true local minimum near X, then 1497 | # norm ( x - x0 ) < T0 + sqrt ( EPSILON ( X ) ) * norm ( X ), 1498 | # where EPSILON ( X ) is the machine precision for X. 1499 | # 1500 | # Input, real H0, is the maximum step size. H0 should be 1501 | # set to about the maximum distance from the initial guess to the minimum. 1502 | # If H0 is set too large or too small, the initial rate of 1503 | # convergence may be slow. 1504 | # 1505 | # Input, integer N, the number of variables. 1506 | # 1507 | # Input, integer PRIN, controls printing intermediate results. 1508 | # 0, nothing is printed. 1509 | # 1, F is printed after every n+1 or n+2 linear minimizations. 1510 | # final X is printed, but intermediate X is printed only 1511 | # if N is at most 4. 1512 | # 2, the scale factors and the principal values of the approximating 1513 | # quadratic form are also printed. 1514 | # 3, X is also printed after every few linear minimizations. 1515 | # 4, the principal vectors of the approximating quadratic form are 1516 | # also printed. 1517 | # 1518 | # Input/output, real X(N), is an array containing on entry a 1519 | # guess of the point of minimum, on return the estimated point of minimum. 1520 | # 1521 | # Input, real F ( X, N ), the function to be minimized. 1522 | # 1523 | # Output, real PRAXIS, the function value at the minimizer. 1524 | # 1525 | # Local parameters: 1526 | # 1527 | # Local, real DMIN, an estimate for the smallest eigenvalue. 1528 | # 1529 | # Local, real FX, the value of F(X,N). 1530 | # 1531 | # Local, logical ILLC, is TRUE if the system is ill-conditioned. 1532 | # 1533 | # Local, real LDT, the length of the step. 1534 | # 1535 | # Local, integer NF, the number of function evaluations. 1536 | # 1537 | # Local, integer NL, the number of linear searches. 1538 | # 1539 | import numpy as np 1540 | # 1541 | # Initialization. 1542 | # 1543 | machep = r8_epsilon ( ) 1544 | small = machep * machep 1545 | vsmall = small * small 1546 | large = 1.0 / small 1547 | vlarge = 1.0 / vsmall 1548 | m2 = np.sqrt ( machep ) 1549 | m4 = np.sqrt ( m2 ) 1550 | # 1551 | # Heuristic numbers: 1552 | # 1553 | # If the axes may be badly scaled (which is to be avoided if 1554 | # possible), then set SCBD = 10. Otherwise set SCBD = 1. 1555 | # 1556 | # If the problem is known to be ill-conditioned, initialize ILLC = true. 1557 | # 1558 | # KTM is the number of iterations without improvement before the 1559 | # algorithm terminates. KTM = 4 is very cautious usually KTM = 1 1560 | # is satisfactory. 1561 | # 1562 | scbd = 1.0 1563 | illc = False 1564 | ktm = 1 1565 | 1566 | if ( illc ): 1567 | ldfac = 0.1 1568 | else: 1569 | ldfac = 0.01 1570 | 1571 | kt = 0 1572 | nl = 0 1573 | nf = 1 1574 | fx = f ( x, n ) 1575 | qf1 = fx 1576 | t = small + abs ( t0 ) 1577 | t2 = t 1578 | dmin = small 1579 | h = h0 1580 | h = max ( h, 100.0 * t ) 1581 | ldt = h 1582 | # 1583 | # The initial set of search directions V is the identity matrix. 1584 | # 1585 | v = np.zeros ( [ n, n ] ) 1586 | for i in range ( 0, n ): 1587 | v[i,i] = 1.0 1588 | 1589 | d = np.zeros ( n ) 1590 | y = np.zeros ( n ) 1591 | z = np.zeros ( n ) 1592 | qa = 0.0 1593 | qb = 0.0 1594 | qc = 0.0 1595 | qd0 = 0.0 1596 | qd1 = 0.0 1597 | q0 = x.copy ( ) 1598 | q1 = x.copy ( ) 1599 | 1600 | if ( 0 < prin ): 1601 | print2 ( n, x, prin, fx, nf, nl ) 1602 | # 1603 | # The main loop starts here. 1604 | # 1605 | while ( True ): 1606 | 1607 | sf = d[0] 1608 | d[0] = 0.0 1609 | # 1610 | # Minimize along the first direction V(*,1). 1611 | # 1612 | jsearch = 0 1613 | nits = 2 1614 | d2 = d[0] 1615 | s = 0.0 1616 | value = fx 1617 | fk = False 1618 | 1619 | d2, s, value, x, nl, nf, fx, qa, qb, qc = minny ( n, jsearch, nits, \ 1620 | d2, s, value, fk, f, x, t, h, v, q0, q1, nl, nf, dmin, ldt, \ 1621 | fx, qa, qb, qc, qd0, qd1 ) 1622 | 1623 | d[0] = d2 1624 | 1625 | if ( s <= 0.0 ): 1626 | for i1 in range ( 0, n ): 1627 | v[i1,0] = - v[i1,0] 1628 | 1629 | if ( sf <= 0.9 * d[0] or d[0] <= 0.9 * sf ): 1630 | d[1:n] = 0.0 1631 | # 1632 | # The inner loop starts here. 1633 | # 1634 | for k in range ( 2, n + 1 ): 1635 | 1636 | y = x.copy ( ) 1637 | 1638 | sf = fx 1639 | 1640 | if ( 0 < kt ): 1641 | illc = True 1642 | 1643 | while ( True ): 1644 | 1645 | kl = k 1646 | df = 0.0 1647 | # 1648 | # A random step follows, to avoid resolution valleys. 1649 | # 1650 | if ( illc ): 1651 | 1652 | for j in range ( 0, n ): 1653 | r = np.random.rand ( 1 ) 1654 | s = ( 0.1 * ldt + t2 * 10.0 ** kt ) * ( r - 0.5 ) 1655 | z[j] = s 1656 | x[0:n] = x[0:n] + s * v[0:n,j] 1657 | 1658 | fx = f ( x, n ) 1659 | nf = nf + 1 1660 | # 1661 | # Minimize along the "non-conjugate" directions V(*,K),...,V(*,N). 1662 | # 1663 | for k2 in range ( k, n + 1 ): 1664 | 1665 | sl = fx 1666 | 1667 | jsearch = k2 - 1 1668 | nits = 2 1669 | d2 = d[k2-1] 1670 | s = 0.0 1671 | value = fx 1672 | fk = False 1673 | 1674 | d2, s, value, x, nl, nf, fx, qa, qb, qc = minny ( n, jsearch, nits, \ 1675 | d2, s, value, fk, f, x, t, h, v, q0, q1, nl, nf, dmin, ldt, \ 1676 | fx, qa, qb, qc, qd0, qd1 ) 1677 | 1678 | d[k2-1] = d2 1679 | 1680 | if ( illc ): 1681 | s = d[k2-1] * ( ( s + z[k2-1] ) ** 2 ) 1682 | else: 1683 | s = sl - fx 1684 | 1685 | if ( df <= s ): 1686 | df = s 1687 | kl = k2 1688 | # 1689 | # If there was not much improvement on the first try, set 1690 | # ILLC = true and start the inner loop again. 1691 | # 1692 | if ( illc ): 1693 | break 1694 | 1695 | if ( abs ( 100.0 * machep * fx ) <= df ): 1696 | break 1697 | 1698 | illc = True 1699 | 1700 | if ( k == 2 and 1 < prin ): 1701 | r8vec_print ( n, d, ' The second difference array:' ) 1702 | # 1703 | # Minimize along the "conjugate" directions V(*,1),...,V(*,K-1). 1704 | # 1705 | for k2 in range ( 1, k ): 1706 | 1707 | jsearch = k2 - 1 1708 | nits = 2 1709 | d2 = d[k2-1] 1710 | s = 0.0 1711 | value = fx 1712 | fk = False 1713 | 1714 | d2, s, value, x, nl, nf, fx, qa, qb, qc = minny ( n, jsearch, nits, \ 1715 | d2, s, value, fk, f, x, t, h, v, q0, q1, nl, nf, dmin, ldt, \ 1716 | fx, qa, qb, qc, qd0, qd1 ) 1717 | 1718 | d[k2-1] = d2 1719 | 1720 | f1 = fx 1721 | fx = sf 1722 | 1723 | for i in range ( 0, n ): 1724 | temp = x[i] 1725 | x[i] = y[i] 1726 | y[i] = temp - y[i] 1727 | 1728 | lds = np.linalg.norm ( y ) 1729 | # 1730 | # Discard direction V(*,kl). 1731 | # 1732 | # If no random step was taken, V(*,KL) is the "non-conjugate" 1733 | # direction along which the greatest improvement was made. 1734 | # 1735 | if ( small < lds ): 1736 | 1737 | for j in range ( kl - 1, k - 1, -1 ): 1738 | v[0:n,j] = v[0:n,j-1] 1739 | d[j] = d[j-1] 1740 | 1741 | d[k-1] = 0.0 1742 | 1743 | v[0:n,k-1] = y[0:n] / lds 1744 | # 1745 | # Minimize along the new "conjugate" direction V(*,k), which is 1746 | # the normalized vector: (new x) - (old x). 1747 | # 1748 | jsearch = k - 1 1749 | nits = 4 1750 | d2 = d[k-1] 1751 | value = f1 1752 | fk = True 1753 | 1754 | d2, lds, value, x, nl, nf, fx, qa, qb, qc = minny ( n, jsearch, nits, \ 1755 | d2, lds, value, fk, f, x, t, h, v, q0, q1, nl, nf, dmin, ldt, \ 1756 | fx, qa, qb, qc, qd0, qd1 ) 1757 | 1758 | d[k-1] = d2 1759 | 1760 | if ( lds <= 0.0 ): 1761 | lds = - lds 1762 | v[0:n,k-1] = - v[0:n,k-1] 1763 | 1764 | ldt = ldfac * ldt 1765 | ldt = max ( ldt, lds ) 1766 | 1767 | if ( 0 < prin ): 1768 | print2 ( n, x, prin, fx, nf, nl ) 1769 | 1770 | t2 = m2 * np.linalg.norm ( x ) + t 1771 | # 1772 | # See whether the length of the step taken since starting the 1773 | # inner loop exceeds half the tolerance. 1774 | # 1775 | if ( 0.5 * t2 < ldt ): 1776 | kt = - 1 1777 | 1778 | kt = kt + 1 1779 | 1780 | if ( ktm < kt ): 1781 | 1782 | if ( 0 < prin ): 1783 | r8vec_print ( n, x, ' X:' ) 1784 | 1785 | value = fx 1786 | 1787 | return value, x 1788 | # 1789 | # The inner loop ends here. 1790 | # 1791 | # Try quadratic extrapolation in case we are in a curved valley. 1792 | # 1793 | x, q0, q1, nl, nf, fx, qf1, qa, qb, qc, qd0, qd1 = quad ( \ 1794 | n, f, x, t, h, v, q0, q1, nl, nf, dmin, ldt, fx, qf1, qa, qb, qc, qd0, qd1 ) 1795 | 1796 | for j in range ( 0, n ): 1797 | d[j] = 1.0 / np.sqrt ( d[j] ) 1798 | 1799 | dn = max ( d ) 1800 | 1801 | if ( 3 < prin ): 1802 | r8mat_print ( n, n, v, ' The new direction vectors:' ) 1803 | 1804 | for j in range ( 0, n ): 1805 | v[0:n,j] = ( d[j] / dn ) * v[0:n,j] 1806 | # 1807 | # Scale the axes to try to reduce the condition number. 1808 | # 1809 | if ( 1.0 < scbd ): 1810 | 1811 | for i in range ( 0, n ): 1812 | s = 0.0 1813 | for j in range ( 0, n ): 1814 | s = s + v[i,j] ** 2 1815 | s = np.sqrt ( s ) 1816 | z[i] = max ( m4, s ) 1817 | 1818 | s = min ( z ) 1819 | 1820 | for i in range ( 0, n ): 1821 | 1822 | sl = s / z[i] 1823 | z[i] = 1.0 / sl 1824 | 1825 | if ( scbd < z[i] ): 1826 | sl = 1.0 / scbd 1827 | z[i] = scbd 1828 | 1829 | v[i,0:n] = sl * v[i,0:n] 1830 | # 1831 | # Calculate a new set of orthogonal directions before repeating 1832 | # the main loop. 1833 | # 1834 | # Transpose V for MINFIT: 1835 | # 1836 | v = np.transpose ( v ) 1837 | # 1838 | # Call MINFIT to find the singular value decomposition of V. 1839 | # 1840 | # This gives the principal values and principal directions of the 1841 | # approximating quadratic form without squaring the condition number. 1842 | # 1843 | v, d = minfit ( n, vsmall, v ) 1844 | # 1845 | # Unscale the axes. 1846 | # 1847 | if ( 1.0 < scbd ): 1848 | 1849 | for i in range ( 0, n ): 1850 | v[i,0:n] = z[i] * v[i,0:n] 1851 | 1852 | for j in range ( 0, n ): 1853 | 1854 | s = 0.0 1855 | for i1 in range ( 0, n ): 1856 | s = x + v[i1,j] ** 2 1857 | s = sqrt ( s ) 1858 | 1859 | d[j] = s * d[j] 1860 | v[0:n,j] = v[0:n,j] / s 1861 | 1862 | for i in range ( 0, n ): 1863 | 1864 | dni = dn * d[i] 1865 | 1866 | if ( large < dni ): 1867 | d[i] = vsmall 1868 | elif ( dni < small ): 1869 | d[i] = vlarge 1870 | else: 1871 | d[i] = 1.0 / dni ** 2 1872 | # 1873 | # Sort the singular values and singular vectors. 1874 | # 1875 | d, v = svsort ( n, d, v ) 1876 | # 1877 | # Determine the smallest eigenvalue. 1878 | # 1879 | dmin = max ( d[n-1], small ) 1880 | # 1881 | # The ratio of the smallest to largest eigenvalue determines whether 1882 | # the system is ill conditioned. 1883 | # 1884 | if ( dmin < m2 * d[0] ): 1885 | illc = True 1886 | else: 1887 | illc = False 1888 | 1889 | if ( 1 < prin ): 1890 | 1891 | if ( 1.0 < scbd ): 1892 | r8vec_print ( n, z, ' The scale factors:' ) 1893 | 1894 | r8vec_print ( n, d, ' Principal values of the quadratic form:' ) 1895 | 1896 | if ( 3 < prin ): 1897 | r8mat_print ( n, n, v, ' The principal axes:' ) 1898 | # 1899 | # The main loop ends here. 1900 | # 1901 | if ( 0 < prin ): 1902 | r8vec_print ( n, x, ' X:' ) 1903 | 1904 | value = fx 1905 | 1906 | return value, x 1907 | 1908 | def print2 ( n, x, prin, fx, nf, nl ): 1909 | 1910 | #*****************************************************************************80 1911 | # 1912 | ## PRINT2 prints certain data about the progress of the iteration. 1913 | # 1914 | # Licensing: 1915 | # 1916 | # This code is distributed under the GNU LGPL license. 1917 | # 1918 | # Modified: 1919 | # 1920 | # 02 August 2016 1921 | # 1922 | # Author: 1923 | # 1924 | # Original FORTRAN77 version by Richard Brent. 1925 | # Python version by John Burkardt. 1926 | # 1927 | # Reference: 1928 | # 1929 | # Richard Brent, 1930 | # Algorithms for Minimization with Derivatives, 1931 | # Prentice Hall, 1973, 1932 | # Reprinted by Dover, 2002. 1933 | # 1934 | # Parameters: 1935 | # 1936 | # Input, integer N, the number of variables. 1937 | # 1938 | # Input, real X(N), the current estimate of the minimizer. 1939 | # 1940 | # Input, integer PRIN, the user-specifed print level. 1941 | # 0, nothing is printed. 1942 | # 1, F is printed after every n+1 or n+2 linear minimizations. 1943 | # final X is printed, but intermediate X is printed only 1944 | # if N is at most 4. 1945 | # 2, the scale factors and the principal values of the approximating 1946 | # quadratic form are also printed. 1947 | # 3, X is also printed after every few linear minimizations. 1948 | # 4, the principal vectors of the approximating quadratic form are 1949 | # also printed. 1950 | # 1951 | # Input, real FX, the smallest value of F(X) found so far. 1952 | # 1953 | # Input, integer NF, the number of function evaluations. 1954 | # 1955 | # Input, integer NL, the number of linear searches. 1956 | # 1957 | print ( '' ) 1958 | print ( ' Linear searches %d' % ( nl ) ) 1959 | print ( ' Function evaluations %d' % ( nf ) ) 1960 | print ( ' The function value FX = %g' % ( fx ) ) 1961 | 1962 | if ( n <= 4 or 2 < prin ): 1963 | r8vec_print ( n, x, ' X:' ) 1964 | 1965 | return 1966 | 1967 | def quad ( n, f, x, t, h, v, q0, q1, nl, nf, dmin, ldt, fx, qf1, qa, qb, \ 1968 | qc, qd0, qd1 ): 1969 | 1970 | #*****************************************************************************80 1971 | # 1972 | ## QUAD seeks to minimize the scalar function F along a particular curve. 1973 | # 1974 | # Discussion: 1975 | # 1976 | # The minimizer to be sought is required to lie on a curve defined 1977 | # by Q0, Q1 and X. 1978 | # 1979 | # Licensing: 1980 | # 1981 | # This code is distributed under the GNU LGPL license. 1982 | # 1983 | # Modified: 1984 | # 1985 | # 01 August 2016 1986 | # 1987 | # Author: 1988 | # 1989 | # Original FORTRAN77 version by Richard Brent. 1990 | # Python version by John Burkardt. 1991 | # 1992 | # Reference: 1993 | # 1994 | # Richard Brent, 1995 | # Algorithms for Minimization with Derivatives, 1996 | # Prentice Hall, 1973, 1997 | # Reprinted by Dover, 2002. 1998 | # 1999 | # Parameters: 2000 | # 2001 | # Input, integer N, the number of variables. 2002 | # 2003 | # Input, real F ( x, n ), the function. 2004 | # 2005 | # Input/output, real X(N), ? 2006 | # 2007 | # Input, real T, ? 2008 | # 2009 | # Input, rea H, ? 2010 | # 2011 | # Input, real V(N,N), the matrix of search directions. 2012 | # 2013 | # Input/output, real Q0(N), an auxiliary point used to define 2014 | # a curve through X. 2015 | # 2016 | # Input/output, real Q1(N), an auxiliary point used to define 2017 | # a curve through X. 2018 | # 2019 | # Input/output, integer NL, the number of linear searches. 2020 | # 2021 | # Input/output, integer NF, the number of function evaluations. 2022 | # 2023 | # Input, real DMIN, an estimate for the smallest eigenvalue. 2024 | # 2025 | # Input, real LDT, the length of the step. 2026 | # 2027 | # Input/output, real FX, the value of F(X,N). 2028 | # 2029 | # Input/output, real QF1, QA, QB, QC, QD0, QD1, ? 2030 | # 2031 | import numpy as np 2032 | 2033 | temp = fx 2034 | fx = qf1 2035 | qf1 = temp 2036 | 2037 | temp = x 2038 | x = q1 2039 | q1 = temp 2040 | 2041 | qd1 = np.linalg.norm ( x - q1 ) 2042 | 2043 | l = qd1 2044 | s = 0.0 2045 | 2046 | if ( qd0 <= 0.0 or qd1 <= 0.0 or nl < 3 * n * n ): 2047 | 2048 | fx = qf1 2049 | qa = 0.0 2050 | qb = 0.0 2051 | qc = 1.0 2052 | 2053 | else: 2054 | 2055 | jsearch = -1 2056 | nits = 2 2057 | value = qf1 2058 | fk = True 2059 | 2060 | s, l, value, x, nl, nf, fx, qa, qb, qc = minny ( n, jsearch, nits, \ 2061 | s, l, value, fk, f, x, t, h, v, q0, q1, nl, nf, dmin, ldt, \ 2062 | fx, qa, qb, qc, qd0, qd1 ) 2063 | 2064 | qa = l * ( l - qd1 ) / ( qd0 + qd1 ) / qd0 2065 | qb = - ( l + qd0 ) * ( l - qd1 ) / qd1 / qd0 2066 | qc = ( l + qd0 ) * l / qd1 / ( qd0 + qd1 ) 2067 | 2068 | qd0 = qd1 2069 | 2070 | xnew = np.zeros ( n ) 2071 | xnew[0:n] = qa * q0[0:n] + qb * x[0:n] + qc * q1[0:n] 2072 | 2073 | q0[0:n] = x[0:n] 2074 | x[0:n] = xnew[0:n] 2075 | 2076 | return x, q0, q1, nl, nf, fx, qf1, qa, qb, qc, qd0, qd1 2077 | 2078 | def svsort ( n, d, v ): 2079 | 2080 | #*****************************************************************************80 2081 | # 2082 | ## SVSORT descending sorts singular values D and adjusts V. 2083 | # 2084 | # Discussion: 2085 | # 2086 | # A simple bubble sort is used on D. 2087 | # 2088 | # Licensing: 2089 | # 2090 | # This code is distributed under the GNU LGPL license. 2091 | # 2092 | # Modified: 2093 | # 2094 | # 01 August 2016 2095 | # 2096 | # Author: 2097 | # 2098 | # Original FORTRAN77 version by Richard Brent. 2099 | # Python version by John Burkardt. 2100 | # 2101 | # Reference: 2102 | # 2103 | # Richard Brent, 2104 | # Algorithms for Minimization with Derivatives, 2105 | # Prentice Hall, 1973, 2106 | # Reprinted by Dover, 2002. 2107 | # 2108 | # Parameters: 2109 | # 2110 | # Input, integer N, the length of D, and the order of V. 2111 | # 2112 | # Input/output, real D(N), the vector to be sorted. 2113 | # On output, the entries of D are in descending order. 2114 | # 2115 | # Input/output, real V(N,N), an N by N array to be adjusted 2116 | # as D is sorted. In particular, if the value that was in D(I) on input is 2117 | # moved to D(J) on output, then the input column V(*,I) is moved to 2118 | # the output column V(*,J). 2119 | # 2120 | for j in range ( 0, n - 1 ): 2121 | 2122 | j3 = j 2123 | for j2 in range ( j + 1, n ): 2124 | if ( d[j3] < d[j2] ): 2125 | j3 = j2 2126 | 2127 | t = d[j] 2128 | d[j] = d[j3] 2129 | d[j3] = t 2130 | 2131 | for i in range ( 0, n ): 2132 | t = v[i,j] 2133 | v[i,j] = v[i,j3] 2134 | v[i,j3] = t 2135 | 2136 | return d, v 2137 | 2138 | def svsort_test ( ): 2139 | 2140 | #*****************************************************************************80 2141 | # 2142 | ## SVSORT_TEST tests SVSORT, which sorts singular value information. 2143 | # 2144 | # Licensing: 2145 | # 2146 | # This code is distributed under the GNU LGPL license. 2147 | # 2148 | # Modified: 2149 | # 2150 | # 01 August 2016 2151 | # 2152 | # Author: 2153 | # 2154 | # John Burkardt 2155 | # 2156 | import numpy as np 2157 | import platform 2158 | 2159 | n = 5 2160 | 2161 | print ( '' ) 2162 | print ( 'SVSORT_TEST' ) 2163 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 2164 | print ( ' SVSORT sorts a vector D, and the corresponding columns' ) 2165 | print ( ' of a matrix V.' ) 2166 | 2167 | d = np.random.rand ( n ) 2168 | 2169 | v = np.zeros ( [ n, n ] ) 2170 | 2171 | for i in range ( 0, n ): 2172 | for j in range ( 0, n ): 2173 | v[i,j] = 10 * ( i + 1 ) + ( j + 1 ) 2174 | 2175 | print ( '' ) 2176 | print ( ' First row = entries of D.' ) 2177 | print ( ' Corresponding columns of V below.' ) 2178 | print ( '' ) 2179 | for j in range ( 0, n ): 2180 | print ( '%14.6g' % ( d[j] ) ), 2181 | print ( '' ) 2182 | print ( '' ) 2183 | for i in range ( 0, n ): 2184 | for j in range ( 0, n ): 2185 | print ( '%14.6g' % ( v[i,j] ) ), 2186 | print ( '' ) 2187 | 2188 | d, v = svsort ( n, d, v ) 2189 | 2190 | print ( '' ) 2191 | print ( ' After sorting D and rearranging V:' ) 2192 | print ( '' ) 2193 | for j in range ( 0, n ): 2194 | print ( '%14.6g' % ( d[j] ) ), 2195 | print ( '' ) 2196 | print ( '' ) 2197 | for i in range ( 0, n ): 2198 | for j in range ( 0, n ): 2199 | print ( '%14.6g' % ( v[i,j] ) ), 2200 | print ( '' ) 2201 | # 2202 | # Terminate. 2203 | # 2204 | print ( '' ) 2205 | print ( 'SVSORT_TEST:' ) 2206 | print ( ' Normal end of execution.' ) 2207 | return 2208 | 2209 | def praxis_test ( ): 2210 | 2211 | #*****************************************************************************80 2212 | # 2213 | ## PRAXIS_TEST tests the PRAXIS library. 2214 | # 2215 | # Licensing: 2216 | # 2217 | # This code is distributed under the GNU LGPL license. 2218 | # 2219 | # Modified: 2220 | # 2221 | # 04 August 2016 2222 | # 2223 | # Author: 2224 | # 2225 | # John Burkardt 2226 | # 2227 | import platform 2228 | 2229 | print ( '' ) 2230 | print ( 'PRAXIS_TEST' ) 2231 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 2232 | print ( ' Test the PRAXIS library.' ) 2233 | # 2234 | # Minimization tests. 2235 | # 2236 | beale_test ( ) 2237 | box_test ( ) 2238 | chebyquad_test ( ) 2239 | cube_test ( ) 2240 | helix_test ( ) 2241 | hilbert_test ( ) 2242 | powell3d_test ( ) 2243 | rosenbrock_test ( ) 2244 | singular_test ( ) 2245 | tridiagonal_test ( ) 2246 | watson_test ( ) 2247 | wood_test ( ) 2248 | # 2249 | # Utility tests. 2250 | # 2251 | minfit_test ( ) 2252 | svsort_test ( ) 2253 | # 2254 | # Terminate. 2255 | # 2256 | print ( '' ) 2257 | print ( 'PRAXIS_TEST:' ) 2258 | print ( ' Normal end of execution.' ) 2259 | return 2260 | 2261 | def r8_epsilon ( ): 2262 | 2263 | #*****************************************************************************80 2264 | # 2265 | ## R8_EPSILON returns the R8 roundoff unit. 2266 | # 2267 | # Discussion: 2268 | # 2269 | # The roundoff unit is a number R which is a power of 2 with the 2270 | # property that, to the precision of the computer's arithmetic, 2271 | # 1 < 1 + R 2272 | # but 2273 | # 1 = ( 1 + R / 2 ) 2274 | # 2275 | # Licensing: 2276 | # 2277 | # This code is distributed under the GNU LGPL license. 2278 | # 2279 | # Modified: 2280 | # 2281 | # 03 June 2013 2282 | # 2283 | # Author: 2284 | # 2285 | # John Burkardt 2286 | # 2287 | # Parameters: 2288 | # 2289 | # Output, real VALUE, the roundoff unit. 2290 | # 2291 | value = 2.220446049250313E-016 2292 | 2293 | return value 2294 | 2295 | def r8_epsilon_test ( ): 2296 | 2297 | #*****************************************************************************80 2298 | # 2299 | ## R8_EPSILON_TEST tests R8_EPSILON. 2300 | # 2301 | # Licensing: 2302 | # 2303 | # This code is distributed under the GNU LGPL license. 2304 | # 2305 | # Modified: 2306 | # 2307 | # 01 September 2012 2308 | # 2309 | # Author: 2310 | # 2311 | # John Burkardt 2312 | # 2313 | import platform 2314 | 2315 | print ( '' ) 2316 | print ( 'R8_EPSILON_TEST' ) 2317 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 2318 | print ( ' R8_EPSILON produces the R8 roundoff unit.' ) 2319 | print ( '' ) 2320 | 2321 | r = r8_epsilon ( ) 2322 | print ( ' R = R8_EPSILON() = %e' % ( r ) ) 2323 | 2324 | s = ( 1.0 + r ) - 1.0 2325 | print ( ' ( 1 + R ) - 1 = %e' % ( s ) ) 2326 | 2327 | s = ( 1.0 + ( r / 2.0 ) ) - 1.0 2328 | print ( ' ( 1 + (R/2) ) - 1 = %e' % ( s ) ) 2329 | # 2330 | # Terminate. 2331 | # 2332 | print ( '' ) 2333 | print ( 'R8_EPSILON_TEST' ) 2334 | print ( ' Normal end of execution.' ) 2335 | return 2336 | 2337 | def r8_hypot ( x, y ): 2338 | 2339 | #*****************************************************************************80 2340 | # 2341 | ## R8_HYPOT returns the value of sqrt ( X^2 + Y^2 ). 2342 | # 2343 | # Licensing: 2344 | # 2345 | # This code is distributed under the GNU LGPL license. 2346 | # 2347 | # Modified: 2348 | # 2349 | # 13 January 2016 2350 | # 2351 | # Author: 2352 | # 2353 | # John Burkardt 2354 | # 2355 | # Parameters: 2356 | # 2357 | # Input, real X, Y, the arguments. 2358 | # 2359 | # Output, real VALUE, the value of sqrt ( X^2 + Y^2 ). 2360 | # 2361 | import numpy as np 2362 | 2363 | if ( abs ( x ) < abs ( y ) ): 2364 | a = abs ( y ) 2365 | b = abs ( x ) 2366 | else: 2367 | a = abs ( x ) 2368 | b = abs ( y ) 2369 | # 2370 | # A contains the larger value. 2371 | # 2372 | if ( a == 0.0 ): 2373 | value = 0.0 2374 | else: 2375 | value = a * np.sqrt ( 1.0 + ( b / a ) ** 2 ) 2376 | 2377 | return value 2378 | 2379 | def r8_hypot_test ( ): 2380 | 2381 | #*****************************************************************************80 2382 | # 2383 | ## R8_HYPOT_TEST tests R8_HYPOT. 2384 | # 2385 | # Licensing: 2386 | # 2387 | # This code is distributed under the GNU LGPL license. 2388 | # 2389 | # Modified: 2390 | # 2391 | # 13 January 2016 2392 | # 2393 | # Author: 2394 | # 2395 | # John Burkardt 2396 | # 2397 | import numpy as np 2398 | import platform 2399 | 2400 | print ( '' ) 2401 | print ( 'R8_HYPOT_TEST' ) 2402 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 2403 | print ( ' R8_HYPOT returns an accurate value for sqrt(A^2+B^2).' ) 2404 | print ( '' ) 2405 | print ( ' A B R8_HYPOT sqrt(A^2+B^2)' ) 2406 | print ( '' ) 2407 | 2408 | b = 2.0 2409 | 2410 | for i in range ( 0, 20 ): 2411 | a = 1.0 2412 | b = b / 2.0 2413 | c = r8_hypot ( a, b ) 2414 | d = np.sqrt ( a ** 2 + b ** 2 ) 2415 | 2416 | print ( ' %12g %12g %24.16g %24.16g' % ( a, b, c, d ) ) 2417 | # 2418 | # Terminate. 2419 | # 2420 | print ( '' ) 2421 | print ( 'R8_HYPOT_TEST' ) 2422 | print ( ' Normal end of execution.' ) 2423 | return 2424 | 2425 | def r8mat_print ( m, n, a, title ): 2426 | 2427 | #*****************************************************************************80 2428 | # 2429 | ## R8MAT_PRINT prints an R8MAT. 2430 | # 2431 | # Licensing: 2432 | # 2433 | # This code is distributed under the GNU LGPL license. 2434 | # 2435 | # Modified: 2436 | # 2437 | # 31 August 2014 2438 | # 2439 | # Author: 2440 | # 2441 | # John Burkardt 2442 | # 2443 | # Parameters: 2444 | # 2445 | # Input, integer M, the number of rows in A. 2446 | # 2447 | # Input, integer N, the number of columns in A. 2448 | # 2449 | # Input, real A(M,N), the matrix. 2450 | # 2451 | # Input, string TITLE, a title. 2452 | # 2453 | r8mat_print_some ( m, n, a, 0, 0, m - 1, n - 1, title ) 2454 | 2455 | return 2456 | 2457 | def r8mat_print_test ( ): 2458 | 2459 | #*****************************************************************************80 2460 | # 2461 | ## R8MAT_PRINT_TEST tests R8MAT_PRINT. 2462 | # 2463 | # Licensing: 2464 | # 2465 | # This code is distributed under the GNU LGPL license. 2466 | # 2467 | # Modified: 2468 | # 2469 | # 10 February 2015 2470 | # 2471 | # Author: 2472 | # 2473 | # John Burkardt 2474 | # 2475 | import numpy as np 2476 | import platform 2477 | 2478 | print ( '' ) 2479 | print ( 'R8MAT_PRINT_TEST' ) 2480 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 2481 | print ( ' R8MAT_PRINT prints an R8MAT.' ) 2482 | 2483 | m = 4 2484 | n = 6 2485 | v = np.array ( [ \ 2486 | [ 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 ], 2487 | [ 21.0, 22.0, 23.0, 24.0, 25.0, 26.0 ], 2488 | [ 31.0, 32.0, 33.0, 34.0, 35.0, 36.0 ], 2489 | [ 41.0, 42.0, 43.0, 44.0, 45.0, 46.0 ] ], dtype = np.float64 ) 2490 | r8mat_print ( m, n, v, ' Here is an R8MAT:' ) 2491 | # 2492 | # Terminate. 2493 | # 2494 | print ( '' ) 2495 | print ( 'R8MAT_PRINT_TEST:' ) 2496 | print ( ' Normal end of execution.' ) 2497 | return 2498 | 2499 | def r8mat_print_some ( m, n, a, ilo, jlo, ihi, jhi, title ): 2500 | 2501 | #*****************************************************************************80 2502 | # 2503 | ## R8MAT_PRINT_SOME prints out a portion of an R8MAT. 2504 | # 2505 | # Licensing: 2506 | # 2507 | # This code is distributed under the GNU LGPL license. 2508 | # 2509 | # Modified: 2510 | # 2511 | # 10 February 2015 2512 | # 2513 | # Author: 2514 | # 2515 | # John Burkardt 2516 | # 2517 | # Parameters: 2518 | # 2519 | # Input, integer M, N, the number of rows and columns of the matrix. 2520 | # 2521 | # Input, real A(M,N), an M by N matrix to be printed. 2522 | # 2523 | # Input, integer ILO, JLO, the first row and column to print. 2524 | # 2525 | # Input, integer IHI, JHI, the last row and column to print. 2526 | # 2527 | # Input, string TITLE, a title. 2528 | # 2529 | incx = 5 2530 | 2531 | print ( '' ) 2532 | print ( title ) 2533 | 2534 | if ( m <= 0 or n <= 0 ): 2535 | print ( '' ) 2536 | print ( ' (None)' ) 2537 | return 2538 | 2539 | for j2lo in range ( max ( jlo, 0 ), min ( jhi + 1, n ), incx ): 2540 | 2541 | j2hi = j2lo + incx - 1 2542 | j2hi = min ( j2hi, n ) 2543 | j2hi = min ( j2hi, jhi ) 2544 | 2545 | print ( '' ) 2546 | print ( ' Col: ', end = '' ) 2547 | 2548 | for j in range ( j2lo, j2hi + 1 ): 2549 | print ( '%7d ' % ( j ), end = '' ) 2550 | 2551 | print ( '' ) 2552 | print ( ' Row' ) 2553 | 2554 | i2lo = max ( ilo, 0 ) 2555 | i2hi = min ( ihi, m ) 2556 | 2557 | for i in range ( i2lo, i2hi + 1 ): 2558 | 2559 | print ( '%7d :' % ( i ), end = '' ) 2560 | 2561 | for j in range ( j2lo, j2hi + 1 ): 2562 | print ( '%12g ' % ( a[i,j] ), end = '' ) 2563 | 2564 | print ( '' ) 2565 | 2566 | return 2567 | 2568 | def r8mat_print_some_test ( ): 2569 | 2570 | #*****************************************************************************80 2571 | # 2572 | ## R8MAT_PRINT_SOME_TEST tests R8MAT_PRINT_SOME. 2573 | # 2574 | # Licensing: 2575 | # 2576 | # This code is distributed under the GNU LGPL license. 2577 | # 2578 | # Modified: 2579 | # 2580 | # 31 October 2014 2581 | # 2582 | # Author: 2583 | # 2584 | # John Burkardt 2585 | # 2586 | import numpy as np 2587 | import platform 2588 | 2589 | print ( '' ) 2590 | print ( 'R8MAT_PRINT_SOME_TEST' ) 2591 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 2592 | print ( ' R8MAT_PRINT_SOME prints some of an R8MAT.' ) 2593 | 2594 | m = 4 2595 | n = 6 2596 | v = np.array ( [ \ 2597 | [ 11.0, 12.0, 13.0, 14.0, 15.0, 16.0 ], 2598 | [ 21.0, 22.0, 23.0, 24.0, 25.0, 26.0 ], 2599 | [ 31.0, 32.0, 33.0, 34.0, 35.0, 36.0 ], 2600 | [ 41.0, 42.0, 43.0, 44.0, 45.0, 46.0 ] ], dtype = np.float64 ) 2601 | r8mat_print_some ( m, n, v, 0, 3, 2, 5, ' Here is an R8MAT:' ) 2602 | # 2603 | # Terminate. 2604 | # 2605 | print ( '' ) 2606 | print ( 'R8MAT_PRINT_SOME_TEST:' ) 2607 | print ( ' Normal end of execution.' ) 2608 | return 2609 | 2610 | def r8vec_print ( n, a, title ): 2611 | 2612 | #*****************************************************************************80 2613 | # 2614 | ## R8VEC_PRINT prints an R8VEC. 2615 | # 2616 | # Licensing: 2617 | # 2618 | # This code is distributed under the GNU LGPL license. 2619 | # 2620 | # Modified: 2621 | # 2622 | # 31 August 2014 2623 | # 2624 | # Author: 2625 | # 2626 | # John Burkardt 2627 | # 2628 | # Parameters: 2629 | # 2630 | # Input, integer N, the dimension of the vector. 2631 | # 2632 | # Input, real A(N), the vector to be printed. 2633 | # 2634 | # Input, string TITLE, a title. 2635 | # 2636 | print ( '' ) 2637 | print ( title ) 2638 | print ( '' ) 2639 | for i in range ( 0, n ): 2640 | print ( '%6d: %12g' % ( i, a[i] ) ) 2641 | 2642 | def r8vec_print_test ( ): 2643 | 2644 | #*****************************************************************************80 2645 | # 2646 | ## R8VEC_PRINT_TEST tests R8VEC_PRINT. 2647 | # 2648 | # Licensing: 2649 | # 2650 | # This code is distributed under the GNU LGPL license. 2651 | # 2652 | # Modified: 2653 | # 2654 | # 29 October 2014 2655 | # 2656 | # Author: 2657 | # 2658 | # John Burkardt 2659 | # 2660 | import numpy as np 2661 | import platform 2662 | 2663 | print ( '' ) 2664 | print ( 'R8VEC_PRINT_TEST' ) 2665 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 2666 | print ( ' R8VEC_PRINT prints an R8VEC.' ) 2667 | 2668 | n = 4 2669 | v = np.array ( [ 123.456, 0.000005, -1.0E+06, 3.14159265 ], dtype = np.float64 ) 2670 | r8vec_print ( n, v, ' Here is an R8VEC:' ) 2671 | # 2672 | # Terminate. 2673 | # 2674 | print ( '' ) 2675 | print ( 'R8VEC_PRINT_TEST:' ) 2676 | print ( ' Normal end of execution.' ) 2677 | return 2678 | 2679 | def rosenbrock_f ( x, n ): 2680 | 2681 | #*****************************************************************************80 2682 | # 2683 | ## ROSENBROCK_F evaluates the Rosenbrock function. 2684 | # 2685 | # Licensing: 2686 | # 2687 | # This code is distributed under the GNU LGPL license. 2688 | # 2689 | # Modified: 2690 | # 2691 | # 04 August 2016 2692 | # 2693 | # Author: 2694 | # 2695 | # John Burkardt 2696 | # 2697 | # Parameters: 2698 | # 2699 | # Input, real X(N), the evaluation point. 2700 | # 2701 | # Input, integer N, the number of variables. 2702 | # 2703 | # Output, real VALUE, the function value. 2704 | # 2705 | value = 0.0 2706 | 2707 | for j in range ( 0, n ): 2708 | if ( ( j % 2 ) == 0 ): 2709 | value = value + ( 1.0 - x[j] ) ** 2 2710 | else: 2711 | value = value + 100.0 * ( x[j] - x[j-1] ** 2 ) ** 2 2712 | 2713 | return value 2714 | 2715 | def rosenbrock_test ( ): 2716 | 2717 | #*****************************************************************************80 2718 | # 2719 | ## ROSENBROCK_TEST calls PRAXIS for the Rosenbrock function. 2720 | # 2721 | # Licensing: 2722 | # 2723 | # This code is distributed under the GNU LGPL license. 2724 | # 2725 | # Modified: 2726 | # 2727 | # 03 August 2016 2728 | # 2729 | # Author: 2730 | # 2731 | # John Burkardt 2732 | # 2733 | import numpy as np 2734 | import platform 2735 | 2736 | n = 2 2737 | 2738 | print ( '' ) 2739 | print ( 'ROSENBROCK_TEST' ) 2740 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 2741 | print ( ' The Rosenbrock function.' ) 2742 | 2743 | t0 = 0.00001 2744 | h0 = 1.0 2745 | prin = 0 2746 | 2747 | x = np.array ( [ -1.2, 1.0 ] ) 2748 | 2749 | r8vec_print ( n, x, ' Initial point:' ) 2750 | 2751 | print ( ' Function value = %g' % ( rosenbrock_f ( x, n ) ) ) 2752 | 2753 | pr, x = praxis ( t0, h0, n, prin, x, rosenbrock_f ) 2754 | 2755 | r8vec_print ( n, x, ' Computed minimizer:' ) 2756 | 2757 | print ( ' Function value = %g' % ( rosenbrock_f ( x, n ) ) ) 2758 | # 2759 | # Terminate. 2760 | # 2761 | print ( '' ) 2762 | print ( 'ROSENBROCK_TEST:' ) 2763 | print ( ' Normal end of execution.' ) 2764 | return 2765 | 2766 | def singular_f ( x, n ): 2767 | 2768 | #*****************************************************************************80 2769 | # 2770 | ## SINGULAR_F evaluates the Powell Singular function. 2771 | # 2772 | # Licensing: 2773 | # 2774 | # This code is distributed under the GNU LGPL license. 2775 | # 2776 | # Modified: 2777 | # 2778 | # 02 August 2016 2779 | # 2780 | # Author: 2781 | # 2782 | # John Burkardt 2783 | # 2784 | # Parameters: 2785 | # 2786 | # Input, real X(N), the evaluation point. 2787 | # 2788 | # Input, integer N, the number of variables. 2789 | # 2790 | # Output, real VALUE, the function value. 2791 | # 2792 | value = 0.0 2793 | 2794 | for j in range ( 0, n, 4 ): 2795 | 2796 | if ( j + 1 <= n - 1 ): 2797 | xjp1 = x[j+1] 2798 | else: 2799 | xjp1 = 0.0 2800 | 2801 | if ( j + 2 <= n - 1 ): 2802 | xjp2 = x[j+2] 2803 | else: 2804 | xjp2 = 0.0 2805 | 2806 | if ( j + 3 <= n - 1 ): 2807 | xjp3 = x[j+3] 2808 | else: 2809 | xjp3 = 0.0 2810 | 2811 | f1 = x[j] + 10.0 * xjp1 2812 | 2813 | if ( j + 1 <= n - 1 ): 2814 | f2 = xjp2 - xjp3 2815 | else: 2816 | f2 = 0.0 2817 | 2818 | if ( j + 2 <= n - 1 ): 2819 | f3 = xjp1 - 2.0 * xjp2 2820 | else: 2821 | f3 = 0.0 2822 | 2823 | if ( j + 3 <= n - 1 ): 2824 | f4 = x[j] - xjp3 2825 | else: 2826 | f4 = 0.0 2827 | 2828 | value = value \ 2829 | + f1 ** 2 \ 2830 | + 5.0 * f2 ** 2 \ 2831 | + f3 ** 4 \ 2832 | + 10.0 * f4 ** 4 2833 | 2834 | return value 2835 | 2836 | def singular_test ( ): 2837 | 2838 | #*****************************************************************************80 2839 | # 2840 | ## SINGULAR_TEST calls PRAXIS for the Powell Singular function. 2841 | # 2842 | # Licensing: 2843 | # 2844 | # This code is distributed under the GNU LGPL license. 2845 | # 2846 | # Modified: 2847 | # 2848 | # 02 August 2016 2849 | # 2850 | # Author: 2851 | # 2852 | # John Burkardt 2853 | # 2854 | import numpy as np 2855 | import platform 2856 | 2857 | n = 4 2858 | 2859 | print ( '' ) 2860 | print ( 'SINGULAR_TEST' ) 2861 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 2862 | print ( ' The Powell Singular function.' ) 2863 | 2864 | t0 = 0.00001 2865 | h0 = 1.0 2866 | prin = 0 2867 | 2868 | x = np.array ( [ 3.0, -1.0, 0.0, 1.0 ] ) 2869 | 2870 | r8vec_print ( n, x, ' Initial point:' ) 2871 | 2872 | print ( ' Function value = %g' % ( singular_f ( x, n ) ) ) 2873 | 2874 | pr, x = praxis ( t0, h0, n, prin, x, singular_f ) 2875 | 2876 | r8vec_print ( n, x, ' Computed minimizer:' ) 2877 | 2878 | print ( ' Function value = %g' % ( singular_f ( x, n ) ) ) 2879 | # 2880 | # Terminate. 2881 | # 2882 | print ( '' ) 2883 | print ( 'SINGULAR_TEST:' ) 2884 | print ( ' Normal end of execution.' ) 2885 | return 2886 | 2887 | def timestamp ( ): 2888 | 2889 | #*****************************************************************************80 2890 | # 2891 | ## TIMESTAMP prints the date as a timestamp. 2892 | # 2893 | # Licensing: 2894 | # 2895 | # This code is distributed under the GNU LGPL license. 2896 | # 2897 | # Modified: 2898 | # 2899 | # 06 April 2013 2900 | # 2901 | # Author: 2902 | # 2903 | # John Burkardt 2904 | # 2905 | # Parameters: 2906 | # 2907 | # None 2908 | # 2909 | import time 2910 | 2911 | t = time.time ( ) 2912 | print ( time.ctime ( t ) ) 2913 | 2914 | return None 2915 | 2916 | def timestamp_test ( ): 2917 | 2918 | #*****************************************************************************80 2919 | # 2920 | ## TIMESTAMP_TEST tests TIMESTAMP. 2921 | # 2922 | # Licensing: 2923 | # 2924 | # This code is distributed under the GNU LGPL license. 2925 | # 2926 | # Modified: 2927 | # 2928 | # 03 December 2014 2929 | # 2930 | # Author: 2931 | # 2932 | # John Burkardt 2933 | # 2934 | # Parameters: 2935 | # 2936 | # None 2937 | # 2938 | import platform 2939 | 2940 | print ( '' ) 2941 | print ( 'TIMESTAMP_TEST:' ) 2942 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 2943 | print ( ' TIMESTAMP prints a timestamp of the current date and time.' ) 2944 | print ( '' ) 2945 | 2946 | timestamp ( ) 2947 | # 2948 | # Terminate. 2949 | # 2950 | print ( '' ) 2951 | print ( 'TIMESTAMP_TEST:' ) 2952 | print ( ' Normal end of execution.' ) 2953 | return 2954 | 2955 | def tridiagonal_f ( x, n ): 2956 | 2957 | #*****************************************************************************80 2958 | # 2959 | ## TRIDIAGONAL_F evaluates the tridiagonal function. 2960 | # 2961 | # Licensing: 2962 | # 2963 | # This code is distributed under the GNU LGPL license. 2964 | # 2965 | # Modified: 2966 | # 2967 | # 03 August 2016 2968 | # 2969 | # Author: 2970 | # 2971 | # John Burkardt 2972 | # 2973 | # Parameters: 2974 | # 2975 | # Input, real X(N), the evaluation point. 2976 | # 2977 | # Input, integer N, the number of variables. 2978 | # 2979 | # Output, real VALUE, the function value. 2980 | # 2981 | value = x[0] ** 2 + 2.0 * sum ( x[1:n] ** 2 ) 2982 | 2983 | for i in range ( 0, n - 1 ): 2984 | value = value - 2.0 * x[i] * x[i+1] 2985 | 2986 | value = value - 2.0 * x[0] 2987 | 2988 | return value 2989 | 2990 | def tridiagonal_test ( ): 2991 | 2992 | #*****************************************************************************80 2993 | # 2994 | ## TRIDIAGONAL_TEST calls PRAXIS for the Tridiagonal function. 2995 | # 2996 | # Licensing: 2997 | # 2998 | # This code is distributed under the GNU LGPL license. 2999 | # 3000 | # Modified: 3001 | # 3002 | # 03 August 2016 3003 | # 3004 | # Author: 3005 | # 3006 | # John Burkardt 3007 | # 3008 | import numpy as np 3009 | import platform 3010 | 3011 | n = 4 3012 | 3013 | print ( '' ) 3014 | print ( 'TRIDIAGONAL_TEST' ) 3015 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 3016 | print ( ' The Tridiagonal function.' ) 3017 | 3018 | t0 = 0.00001 3019 | h0 = 8.0 3020 | prin = 0 3021 | 3022 | x = np.zeros ( n ) 3023 | 3024 | r8vec_print ( n, x, ' Initial point:' ) 3025 | 3026 | print ( ' Function value = %g' % ( tridiagonal_f ( x, n ) ) ) 3027 | 3028 | pr, x = praxis ( t0, h0, n, prin, x, tridiagonal_f ) 3029 | 3030 | r8vec_print ( n, x, ' Computed minimizer:' ) 3031 | 3032 | print ( ' Function value = %g' % ( tridiagonal_f ( x, n ) ) ) 3033 | # 3034 | # Terminate. 3035 | # 3036 | print ( '' ) 3037 | print ( 'TRIDIAGONAL_TEST:' ) 3038 | print ( ' Normal end of execution.' ) 3039 | return 3040 | 3041 | def watson_f ( x, n ): 3042 | 3043 | #*****************************************************************************80 3044 | # 3045 | ## WATSON_F evaluates the Watson function. 3046 | # 3047 | # Licensing: 3048 | # 3049 | # This code is distributed under the GNU LGPL license. 3050 | # 3051 | # Modified: 3052 | # 3053 | # 02 August 2016 3054 | # 3055 | # Author: 3056 | # 3057 | # John Burkardt 3058 | # 3059 | # Parameters: 3060 | # 3061 | # Input, real X(N), the evaluation point. 3062 | # 3063 | # Input, integer N, the number of variables. 3064 | # 3065 | # Output, real VALUE, the function value. 3066 | # 3067 | value = 0.0 3068 | 3069 | for i in range ( 0, 29 ): 3070 | 3071 | s1 = 0.0 3072 | d = 1.0 3073 | for j in range ( 1, n ): 3074 | s1 = s1 + j * d * x[j] 3075 | d = d * ( i + 1 ) / 29.0 3076 | 3077 | s2 = 0.0 3078 | d = 1.0 3079 | for j in range ( 0, n ): 3080 | s2 = s2 + d * x[j] 3081 | d = d * ( i + 1 ) / 29.0 3082 | 3083 | value = value + ( s1 - s2 * s2 - 1.0 ) ** 2 3084 | 3085 | value = value + x[0] ** 2 + ( x[1] - x[0] ** 2 - 1.0 ) ** 2 3086 | 3087 | return value 3088 | 3089 | def watson_test ( ): 3090 | 3091 | #*****************************************************************************80 3092 | # 3093 | ## WATSON_TEST calls PRAXIS for the Watson function. 3094 | # 3095 | # Licensing: 3096 | # 3097 | # This code is distributed under the GNU LGPL license. 3098 | # 3099 | # Modified: 3100 | # 3101 | # 02 August 2016 3102 | # 3103 | # Author: 3104 | # 3105 | # John Burkardt 3106 | # 3107 | import numpy as np 3108 | import platform 3109 | 3110 | n = 6 3111 | 3112 | print ( '' ) 3113 | print ( 'WATSON_TEST' ) 3114 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 3115 | print ( ' The Watson function.' ) 3116 | 3117 | t0 = 0.00001 3118 | h0 = 1.0 3119 | prin = 0 3120 | 3121 | x = np.zeros ( n ) 3122 | 3123 | r8vec_print ( n, x, ' Initial point:' ) 3124 | 3125 | print ( ' Function value = %g' % ( watson_f ( x, n ) ) ) 3126 | 3127 | pr, x = praxis ( t0, h0, n, prin, x, watson_f ) 3128 | 3129 | r8vec_print ( n, x, ' Computed minimizer:' ) 3130 | 3131 | print ( ' Function value = %g' % ( watson_f ( x, n ) ) ) 3132 | # 3133 | # Terminate. 3134 | # 3135 | print ( '' ) 3136 | print ( 'WATSON_TEST:' ) 3137 | print ( ' Normal end of execution.' ) 3138 | return 3139 | 3140 | def wood_f ( x, n ): 3141 | 3142 | #*****************************************************************************80 3143 | # 3144 | ## WOOD_F evaluates the Wood function. 3145 | # 3146 | # Licensing: 3147 | # 3148 | # This code is distributed under the GNU LGPL license. 3149 | # 3150 | # Modified: 3151 | # 3152 | # 02 August 2016 3153 | # 3154 | # Author: 3155 | # 3156 | # John Burkardt 3157 | # 3158 | # Parameters: 3159 | # 3160 | # Input, real X(N), the evaluation point. 3161 | # 3162 | # Input, integer N, the number of variables. 3163 | # 3164 | # Output, real VALUE, the function value. 3165 | # 3166 | f1 = x[1] - x[0] ** 2 3167 | f2 = 1.0 - x[0] 3168 | f3 = x[3] - x[2] ** 2 3169 | f4 = 1.0 - x[2] 3170 | f5 = x[1] + x[3] - 2.0 3171 | f6 = x[1] - x[3] 3172 | 3173 | value = \ 3174 | 100.0 * f1 ** 2 \ 3175 | + f2 ** 2 \ 3176 | + 90.0 * f3 ** 2 \ 3177 | + f4 ** 2 \ 3178 | + 10.0 * f5 ** 2 \ 3179 | + 0.1 * f6 ** 2 3180 | 3181 | return value 3182 | 3183 | def wood_test ( ): 3184 | 3185 | #*****************************************************************************80 3186 | # 3187 | ## WOOD_TEST calls PRAXIS for the Wood function. 3188 | # 3189 | # Licensing: 3190 | # 3191 | # This code is distributed under the GNU LGPL license. 3192 | # 3193 | # Modified: 3194 | # 3195 | # 02 August 2016 3196 | # 3197 | # Author: 3198 | # 3199 | # John Burkardt 3200 | # 3201 | import numpy as np 3202 | import platform 3203 | 3204 | n = 4 3205 | 3206 | print ( '' ) 3207 | print ( 'WOOD_TEST' ) 3208 | print ( ' Python version: %s' % ( platform.python_version ( ) ) ) 3209 | print ( ' The Wood function.' ) 3210 | 3211 | t0 = 0.00001 3212 | h0 = 10.0 3213 | prin = 0 3214 | 3215 | x = np.array ( [ -3.0, -1.0, -3.0, -1.0 ] ) 3216 | 3217 | r8vec_print ( n, x, ' Initial point:' ) 3218 | 3219 | print ( ' Function value = %g' % ( wood_f ( x, n ) ) ) 3220 | 3221 | pr, x = praxis ( t0, h0, n, prin, x, wood_f ) 3222 | 3223 | r8vec_print ( n, x, ' Computed minimizer:' ) 3224 | 3225 | print ( ' Function value = %g' % ( wood_f ( x, n ) ) ) 3226 | # 3227 | # Terminate. 3228 | # 3229 | print ( '' ) 3230 | print ( 'WOOD_TEST:' ) 3231 | print ( ' Normal end of execution.' ) 3232 | return 3233 | 3234 | if ( __name__ == '__main__' ): 3235 | timestamp ( ) 3236 | praxis_test ( ) 3237 | timestamp ( ) 3238 | 3239 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Sagfree elastic MPM Demo 2 | ================ 3 | 4 | [Jerry Hsu](https://chichenghsu.com/), 5 | [Nghia Truong](https://www.linkedin.com/in/nghia-truong502/), 6 | [Cem Yuksel](http://www.cemyuksel.com/), 7 | [Kui Wu](https://kuiwuchn.github.io/) 8 | 9 | A General Two-Stage Initialization for Sag-Free Deformable Simulations 10 | 11 | *ACM Transactions on Graphics (Proceedings of SIGGRAPH 2022), 41, 4, 2022* 12 | 13 | This is a Python implementation of initializating sag-free MPM simulation (https://graphics.cs.utah.edu/research/projects/sag-free-simulations/). 14 | 15 | ![Screenshot](demo_nosagfree.gif) 16 | 17 | Naive initialization 18 | 19 | ![Screenshot](demo_sagfree.gif) 20 | 21 | Sag-Free initialization 22 | 23 | Usage 24 | -------------------- 25 | 26 | Turn on the sag-free initialization by setting USE_SAGFREE_INIT as 1 in line34. 27 | 28 | Dependencies 29 | -------------------- 30 | 31 | This demo depends on [Taichi](https://github.com/taichi-dev/taichi). You may follow its [documentation](https://docs.taichi.graphics/) for installation, or simply type `pip install taichi` under a Python 3 environment. 32 | This demo is tested under Taichi 1.0.4. 33 | 34 | Run the Demo 35 | -------------------- 36 | 37 | `python SagfreeElasticBeam.py` 38 | 39 | 40 | BibTex Citation 41 | ---------------------- 42 | ``` 43 | @article{Hsu2022, 44 | author = {Jerry Hsu and Nghia Truong and Cem Yuksel and Kui Wu}, 45 | title = {A General Two-Stage Initialization for Sag-Free Deformable Simulations}, 46 | journal = {ACM Transactions on Graphics (Proceedings of SIGGRAPH 2022)}, 47 | year = {2022}, 48 | month = {07}, 49 | volume = {41}, 50 | number = {4}, 51 | pages = {64:1--64:13}, 52 | articleno = {64}, 53 | numpages = {13}, 54 | location = {Vancouver, Canada}, 55 | url = {https://doi.org/10.1145/3528223.3530165}, 56 | doi = {10.1145/3528223.3530165}, 57 | issn = {0730-0301}, 58 | publisher = {ACM Press}, 59 | address = {New York, NY, USA}, 60 | } 61 | ``` 62 | --------------------------------------------------------------------------------