@@ -321,3 +321,148 @@ end
321
321
function NonlinearLeastSquaresProblem (f, u0, p = NullParameters (); kwargs... )
322
322
return NonlinearLeastSquaresProblem (NonlinearFunction (f), u0, p; kwargs... )
323
323
end
324
+
325
+ @doc doc"""
326
+ SCCNonlinearProblem(probs, explicitfuns!)
327
+
328
+ Defines an SCC-split nonlinear system to be solved iteratively.
329
+
330
+ ## Mathematical Specification of an SCC-Split Nonlinear Problem
331
+
332
+ An SCC-Split Nonlinear Problem is a system of nonlinear equations
333
+
334
+ ```math
335
+ f(u,p) = 0
336
+ ```
337
+
338
+ with the special property that its Jacobian is in block-lower-triangular
339
+ form. In this form, the nonlinear problem can be decomposed into a system
340
+ of nonlinear systems.
341
+
342
+ ```math
343
+ f_1(u_1,p) = 0
344
+ f_2(u_2,u_1,p) = 0
345
+ f_3(u_3,u_2,u_1,p) = 0
346
+ \v dots
347
+ f_n(u_n,\l dots,u_3,u_2,u_1,p) = 0
348
+ ```
349
+
350
+ Splitting the system in this form can have multiple advantages, including:
351
+
352
+ * Improved numerical stability and robustness of the solving process
353
+ * Improved performance due to using smaller Jacobians
354
+
355
+ The SCC-Split Nonlinear Problem is the ordered collection of nonlinear systems
356
+ to solve in order solve the system in the optimized split form.
357
+
358
+ ## Representation
359
+
360
+ The representation of the SCCNonlinearProblem is via an ordered collection
361
+ of `NonlinearProblem`s, `probs`, with an attached explicit function for pre-processing
362
+ a cache. This can be interpreted as follows:
363
+
364
+ ```math
365
+ p_1 = g_1(u,p)
366
+ f_1(u_1,p_1) = 0
367
+ p_2 = g_2(u,p)
368
+ f_2(u_2,u_1,p_2) = 0
369
+ p_3 = g_3(u,p)
370
+ f_3(u_3,u_2,u_1,p_3) = 0
371
+ \v dots
372
+ p_n = g_n(u,p)
373
+ f_n(u_n,\l dots,u_3,u_2,u_1,p_n) = 0
374
+ ```
375
+
376
+ where ``g_i`` is `explicitfuns![i]`. In a computational sense, `explictfuns!`
377
+ is instead a mutating function `explictfuns` which
378
+ updates the values of prob.probs[i] using the previous solutions `sols[i-1]`
379
+ and below.
380
+
381
+ !!! warn
382
+ For the purposes of differentiation, it's assumed that `explictfuns!` does
383
+ not modify tunable parameters!
384
+
385
+ !!! warn
386
+ While `explictfuns![i]` could in theory use `sols[i+1]` in its computation,
387
+ these values will not be updated. It is thus the contract of the interface
388
+ to not use those values except for as caches to be overriden.
389
+
390
+ !!! note
391
+ prob.probs[i].p can be aliased with each other as a performance / memory
392
+ optimization. If they are aliased before the construction of the `probs`
393
+ the runtime guarantees the aliasing behavior is kept.
394
+
395
+ ## Example
396
+
397
+ For the following nonlinear problem:
398
+
399
+ ```julia
400
+ function f(du,u,p)
401
+ du[1] = cos(u[2]) - u[1]
402
+ du[2] = sin(u[1] + u[2]) + u[2]
403
+ du[3] = 2u[4] + u[3] + 1.0
404
+ du[4] = u[5]^2 + u[4]
405
+ du[5] = u[3]^2 + u[5]
406
+ du[6] = u[1] + u[2] + u[3] + u[4] + u[5] + 2.0u[6] + 2.5u[7] + 1.5u[8]
407
+ du[7] = u[1] + u[2] + u[3] + 2.0u[4] + u[5] + 4.0u[6] - 1.5u[7] + 1.5u[8]
408
+ du[8] = u[1] + 2.0u[2] + 3.0u[3] + 5.0u[4] + 6.0u[5] + u[6] - u[7] - u[8]
409
+ end
410
+ prob = NonlinearProblem(f, zeros(8))
411
+ sol = solve(prob)
412
+ ```
413
+
414
+ The split SCC form is:
415
+
416
+ ```julia
417
+ cache = zeros(3)
418
+
419
+ function f1(du,u,cache)
420
+ du[1] = cos(u[2]) - u[1]
421
+ du[2] = sin(u[1] + u[2]) + u[2]
422
+ end
423
+ explicitfun1(cache,sols) = nothing
424
+ prob1 = NonlinearProblem(NonlinearFunction{true, SciMLBase.NoSpecialize}(f1), zeros(2), cache)
425
+ sol1 = solve(prob1, NewtonRaphson())
426
+
427
+ function f2(du,u,cache)
428
+ du[1] = 2u[2] + u[1] + 1.0
429
+ du[2] = u[3]^2 + u[2]
430
+ du[3] = u[1]^2 + u[3]
431
+ end
432
+ explicitfun2(cache,sols) = nothing
433
+ prob2 = NonlinearProblem(NonlinearFunction{true, SciMLBase.NoSpecialize}(f2), zeros(3), cache)
434
+ sol2 = solve(prob2, NewtonRaphson())
435
+
436
+ function f3(du,u,cache)
437
+ du[1] = cache[1] + 2.0u[1] + 2.5u[2] + 1.5u[3]
438
+ du[2] = cache[2] + 4.0u[1] - 1.5u[2] + 1.5u[3]
439
+ du[3] = cache[3] + + u[1] - u[2] - u[3]
440
+ end
441
+ prob3 = NonlinearProblem(NonlinearFunction{true, SciMLBase.NoSpecialize}(f3), zeros(3), cache)
442
+ function explicitfun3(cache,sols)
443
+ cache[1] = sols[1][1] + sols[1][2] + sols[2][1] + sols[2][2] + sols[2][3]
444
+ cache[2] = sols[1][1] + sols[1][2] + sols[2][1] + 2.0sols[2][2] + sols[2][3]
445
+ cache[3] = sols[1][1] + 2.0sols[1][2] + 3.0sols[2][1] + 5.0sols[2][2] + 6.0sols[2][3]
446
+ end
447
+ explicitfun3(cache,[sol1,sol2])
448
+ sol3 = solve(prob3, NewtonRaphson())
449
+ manualscc = [sol1; sol2; sol3]
450
+
451
+ sccprob = SciMLBase.SCCNonlinearProblem([prob1,prob2,prob3], SciMLBase.Void{Any}.([explicitfun1,explicitfun2,explicitfun3]))
452
+ ```
453
+
454
+ Note that this example aliases the parameters together for a memory-reduced representation.
455
+
456
+ ## Problem Type
457
+
458
+ ### Constructors
459
+
460
+ ### Fields
461
+
462
+ * `probs`: the collection of problems to solve
463
+ * `explictfuns!`: the explicit functions for mutating the parameter set
464
+ """
465
+ mutable struct SCCNonlinearProblem{P, E}
466
+ probs:: P
467
+ explictfuns!:: E
468
+ end
0 commit comments