Added Levenberg-Marquardt algorithm and svd Golub-Kahan #513

Merged
margarita0303 merged 35 commits from dev into dev 2023-06-19 16:11:59 +03:00
7 changed files with 197 additions and 144 deletions
Showing only changes of commit e8dafad6c5 - Show all commits

View File

@ -12,7 +12,8 @@ import space.kscience.kmath.tensors.LevenbergMarquardt.funcDifficultForLm
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.div
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.lm
import space.kscience.kmath.tensors.core.LMInput
import space.kscience.kmath.tensors.core.levenbergMarquardt
import kotlin.math.roundToInt
fun main() {
@ -39,9 +40,7 @@ fun main() {
var t = t_example
val y_dat = y_hat
val weight = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { 1.0 / Nparams * 1.0 - 0.085 }
).as2D()
val weight = 1.0 / Nparams * 1.0 - 0.085
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
).as2D()
@ -52,8 +51,7 @@ fun main() {
val opts = doubleArrayOf(3.0, 10000.0, 1e-6, 1e-6, 1e-6, 1e-6, 1e-2, 11.0, 9.0, 1.0)
// val opts = doubleArrayOf(3.0, 10000.0, 1e-6, 1e-6, 1e-6, 1e-6, 1e-3, 11.0, 9.0, 1.0)
val result = DoubleTensorAlgebra.lm(
::funcDifficultForLm,
val inputData = LMInput(::funcDifficultForLm,
p_init.as2D(),
t,
y_dat,
@ -61,10 +59,14 @@ fun main() {
dp,
p_min.as2D(),
p_max.as2D(),
opts,
opts[1].toInt(),
doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
doubleArrayOf(opts[6], opts[7], opts[8]),
opts[9].toInt(),
10,
1
)
1)
val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
println("Parameters:")
for (i in 0 until result.resultParameters.shape.component1()) {

View File

@ -12,14 +12,13 @@ import space.kscience.kmath.tensors.LevenbergMarquardt.funcDifficultForLm
import space.kscience.kmath.tensors.LevenbergMarquardt.funcEasyForLm
import space.kscience.kmath.tensors.LevenbergMarquardt.getStartDataForFuncEasy
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.lm
import space.kscience.kmath.tensors.core.LMInput
import space.kscience.kmath.tensors.core.levenbergMarquardt
import kotlin.math.roundToInt
fun main() {
val startedData = getStartDataForFuncEasy()
val result = DoubleTensorAlgebra.lm(
::funcEasyForLm,
val inputData = LMInput(::funcEasyForLm,
DoubleTensorAlgebra.ones(ShapeND(intArrayOf(4, 1))).as2D(),
startedData.t,
startedData.y_dat,
@ -27,10 +26,14 @@ fun main() {
startedData.dp,
startedData.p_min,
startedData.p_max,
startedData.opts,
startedData.opts[1].toInt(),
doubleArrayOf(startedData.opts[2], startedData.opts[3], startedData.opts[4], startedData.opts[5]),
doubleArrayOf(startedData.opts[6], startedData.opts[7], startedData.opts[8]),
startedData.opts[9].toInt(),
10,
startedData.example_number
)
startedData.example_number)
val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
println("Parameters:")
for (i in 0 until result.resultParameters.shape.component1()) {

View File

@ -12,7 +12,8 @@ import space.kscience.kmath.tensors.LevenbergMarquardt.funcMiddleForLm
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.div
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.lm
import space.kscience.kmath.tensors.core.LMInput
import space.kscience.kmath.tensors.core.levenbergMarquardt
import kotlin.math.roundToInt
fun main() {
val NData = 100
@ -38,9 +39,7 @@ fun main() {
var t = t_example
val y_dat = y_hat
val weight = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { 1.0 }
).as2D()
val weight = 1.0
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
).as2D()
@ -50,8 +49,7 @@ fun main() {
p_min = p_min.div(1.0 / 50.0)
val opts = doubleArrayOf(3.0, 7000.0, 1e-5, 1e-5, 1e-5, 1e-5, 1e-5, 11.0, 9.0, 1.0)
val result = DoubleTensorAlgebra.lm(
::funcMiddleForLm,
val inputData = LMInput(::funcMiddleForLm,
p_init.as2D(),
t,
y_dat,
@ -59,10 +57,14 @@ fun main() {
dp,
p_min.as2D(),
p_max.as2D(),
opts,
opts[1].toInt(),
doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
doubleArrayOf(opts[6], opts[7], opts[8]),
opts[9].toInt(),
10,
1
)
1)
val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
println("Parameters:")
for (i in 0 until result.resultParameters.shape.component1()) {

View File

@ -11,7 +11,8 @@ import space.kscience.kmath.nd.*
import space.kscience.kmath.tensors.LevenbergMarquardt.StartDataLm
import space.kscience.kmath.tensors.core.BroadcastDoubleTensorAlgebra.zeros
import space.kscience.kmath.tensors.core.DoubleTensorAlgebra
import space.kscience.kmath.tensors.core.lm
import space.kscience.kmath.tensors.core.LMInput
import space.kscience.kmath.tensors.core.levenbergMarquardt
import kotlin.random.Random
import kotlin.reflect.KFunction3
@ -31,20 +32,23 @@ fun streamLm(lm_func: KFunction3<MutableStructure2D<Double>, MutableStructure2D<
var steps = numberOfLaunches
val isEndless = (steps <= 0)
val inputData = LMInput(lm_func,
p_init,
t,
y_dat,
weight,
dp,
p_min,
p_max,
opts[1].toInt(),
doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
doubleArrayOf(opts[6], opts[7], opts[8]),
opts[9].toInt(),
10,
example_number)
while (isEndless || steps > 0) {
val result = DoubleTensorAlgebra.lm(
lm_func,
p_init,
t,
y_dat,
weight,
dp,
p_min,
p_max,
opts,
10,
example_number
)
val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
emit(result.resultParameters)
delay(launchFrequencyInMs)
p_init = result.resultParameters

View File

@ -24,7 +24,7 @@ public data class StartDataLm (
var p_init: MutableStructure2D<Double>,
var t: MutableStructure2D<Double>,
var y_dat: MutableStructure2D<Double>,
var weight: MutableStructure2D<Double>,
var weight: Double,
var dp: MutableStructure2D<Double>,
var p_min: MutableStructure2D<Double>,
var p_max: MutableStructure2D<Double>,
@ -113,9 +113,7 @@ fun getStartDataForFuncDifficult(): StartDataLm {
var t = t_example
val y_dat = y_hat
val weight = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { 1.0 / Nparams * 1.0 - 0.085 }
).as2D()
val weight = 1.0 / Nparams * 1.0 - 0.085
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
).as2D()
@ -154,9 +152,7 @@ fun getStartDataForFuncMiddle(): StartDataLm {
}
var t = t_example
val y_dat = y_hat
val weight = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { 1.0 }
).as2D()
val weight = 1.0
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
).as2D()
@ -202,9 +198,7 @@ fun getStartDataForFuncEasy(): StartDataLm {
ShapeND(intArrayOf(100, 1)), lm_matx_y_dat
).as2D()
val weight = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { 4.0 }
).as2D()
val weight = 4.0
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }

View File

@ -19,21 +19,21 @@ import kotlin.math.pow
import kotlin.reflect.KFunction3
/**
* Type of convergence achieved as a result of executing the Levenberg-Marquardt algorithm
* Type of convergence achieved as a result of executing the Levenberg-Marquardt algorithm.
*
* InGradient: gradient convergence achieved
* (max(J^T W dy) < epsilon1 = opts[2],
* (max(J^T W dy) < epsilon1,
* where J - Jacobi matrix (dy^/dp) for the current approximation y^,
* W - weight matrix from input, dy = (y - y^(p)))
* W - weight matrix from input, dy = (y - y^(p))).
* InParameters: convergence in parameters achieved
* (max(h_i / p_i) < epsilon2 = opts[3],
* where h_i - offset for parameter p_i on the current iteration)
* (max(h_i / p_i) < epsilon2,
* where h_i - offset for parameter p_i on the current iteration).
* InReducedChiSquare: chi-squared convergence achieved
* (chi squared value divided by (m - n + 1) < epsilon2 = opts[4],
* where n - number of parameters, m - amount of points
* NoConvergence: the maximum number of iterations has been reached without reaching any convergence
* (chi squared value divided by (m - n + 1) < epsilon2,
* where n - number of parameters, m - amount of points).
* NoConvergence: the maximum number of iterations has been reached without reaching any convergence.
*/
public enum class TypeOfConvergence{
public enum class TypeOfConvergence {
InGradient,
InParameters,
InReducedChiSquare,
@ -41,14 +41,14 @@ public enum class TypeOfConvergence{
}
/**
* Class for the data obtained as a result of the execution of the Levenberg-Marquardt algorithm
* The data obtained as a result of the execution of the Levenberg-Marquardt algorithm.
*
* iterations: number of completed iterations
* funcCalls: the number of evaluations of the input function during execution
* resultChiSq: chi squared value on final parameters
* resultLambda: final lambda parameter used to calculate the offset
* resultParameters: final parameters
* typeOfConvergence: type of convergence
* iterations: number of completed iterations.
* funcCalls: the number of evaluations of the input function during execution.
* resultChiSq: chi squared value on final parameters.
* resultLambda: final lambda parameter used to calculate the offset.
* resultParameters: final parameters.
* typeOfConvergence: type of convergence.
*/
public data class LMResultInfo (
var iterations:Int,
@ -59,26 +59,65 @@ public data class LMResultInfo (
var typeOfConvergence: TypeOfConvergence,
)
public fun DoubleTensorAlgebra.lm(
func: KFunction3<MutableStructure2D<Double>, MutableStructure2D<Double>, Int, MutableStructure2D<Double>>,
pInput: MutableStructure2D<Double>, tInput: MutableStructure2D<Double>, yDatInput: MutableStructure2D<Double>,
weightInput: MutableStructure2D<Double>, dpInput: MutableStructure2D<Double>, pMinInput: MutableStructure2D<Double>,
pMaxInput: MutableStructure2D<Double>, optsInput: DoubleArray, nargin: Int, exampleNumber: Int): LMResultInfo {
/**
* Input data for the Levenberg-Marquardt function.
*
* func: function of n independent variables x, m parameters an example number,
* rotating a vector of n values y, in which each of the y_i is calculated at its x_i with the given parameters.
* startParameters: starting parameters.
* independentVariables: independent variables, for each of which the real value is known.
* realValues: real values obtained with given independent variables but unknown parameters.
* weight: measurement error for realValues (denominator in each term of sum of weighted squared errors).
* pDelta: delta when calculating the derivative with respect to parameters.
* minParameters: the lower bound of parameter values.
* maxParameters: upper limit of parameter values.
* maxIterations: maximum allowable number of iterations.
* epsilons: epsilon1 - convergence tolerance for gradient,
* epsilon2 - convergence tolerance for parameters,
* epsilon3 - convergence tolerance for reduced chi-square,
* epsilon4 - determines acceptance of a step.
* lambdas: lambda0 - starting lambda value for parameter offset count,
* lambdaUp - factor for increasing lambda,
* lambdaDown - factor for decreasing lambda.
* updateType: 1: Levenberg-Marquardt lambda update,
* 2: Quadratic update,
* 3: Nielsen's lambda update equations.
* nargin: a value that determines which options to use by default
* (<5 - use weight by default, <6 - use pDelta by default, <7 - use minParameters by default,
* <8 - use maxParameters by default, <9 - use updateType by default).
* exampleNumber: a parameter for a function with which you can choose its behavior.
*/
public data class LMInput (
var func: KFunction3<MutableStructure2D<Double>, MutableStructure2D<Double>, Int, MutableStructure2D<Double>>,
var startParameters: MutableStructure2D<Double>,
var independentVariables: MutableStructure2D<Double>,
var realValues: MutableStructure2D<Double>,
var weight: Double,
var pDelta: MutableStructure2D<Double>,
var minParameters: MutableStructure2D<Double>,
var maxParameters: MutableStructure2D<Double>,
var maxIterations: Int,
var epsilons: DoubleArray,
var lambdas: DoubleArray,
var updateType: Int,
var nargin: Int,
var exampleNumber: Int
)
public fun DoubleTensorAlgebra.levenbergMarquardt(inputData: LMInput): LMResultInfo {
val resultInfo = LMResultInfo(0, 0, 0.0,
0.0, pInput, TypeOfConvergence.NoConvergence)
0.0, inputData.startParameters, TypeOfConvergence.NoConvergence)
val eps = 2.2204e-16
val settings = LMSettings(0, 0, exampleNumber)
val settings = LMSettings(0, 0, inputData.exampleNumber)
settings.funcCalls = 0 // running count of function evaluations
var p = pInput
val t = tInput
var p = inputData.startParameters
val t = inputData.independentVariables
val Npar = length(p) // number of parameters
val Npnt = length(yDatInput) // number of data points
val Npnt = length(inputData.realValues) // number of data points
var pOld = zeros(ShapeND(intArrayOf(Npar, 1))).as2D() // previous set of parameters
var yOld = zeros(ShapeND(intArrayOf(Npnt, 1))).as2D() // previous model, y_old = y_hat(t;p_old)
var X2 = 1e-3 / eps // a really big initial Chi-sq value
@ -86,50 +125,55 @@ public fun DoubleTensorAlgebra.lm(
var J = zeros(ShapeND(intArrayOf(Npnt, Npar))).as2D() // Jacobian matrix
val DoF = Npnt - Npar // statistical degrees of freedom
var weight = weightInput
if (nargin < 5) {
weight = fromArray(ShapeND(intArrayOf(1, 1)), doubleArrayOf((yDatInput.transpose().dot(yDatInput)).as1D()[0])).as2D()
var weight = fromArray(ShapeND(intArrayOf(1, 1)), doubleArrayOf(inputData.weight)).as2D()
if (inputData.nargin < 5) {
weight = fromArray(ShapeND(intArrayOf(1, 1)), doubleArrayOf((inputData.realValues.transpose().dot(inputData.realValues)).as1D()[0])).as2D()
}
var dp = dpInput
if (nargin < 6) {
var dp = inputData.pDelta
if (inputData.nargin < 6) {
dp = fromArray(ShapeND(intArrayOf(1, 1)), doubleArrayOf(0.001)).as2D()
}
var pMin = pMinInput
if (nargin < 7) {
pMin = p
pMin.abs()
pMin = pMin.div(-100.0).as2D()
var minParameters = inputData.minParameters
if (inputData.nargin < 7) {
minParameters = p
minParameters.abs()
minParameters = minParameters.div(-100.0).as2D()
}
var pMax = pMaxInput
if (nargin < 8) {
pMax = p
pMax.abs()
pMax = pMax.div(100.0).as2D()
var maxParameters = inputData.maxParameters
if (inputData.nargin < 8) {
maxParameters = p
maxParameters.abs()
maxParameters = maxParameters.div(100.0).as2D()
}
var opts = optsInput
if (nargin < 10) {
opts = doubleArrayOf(3.0, 10.0 * Npar, 1e-3, 1e-3, 1e-1, 1e-1, 1e-2, 11.0, 9.0, 1.0)
var maxIterations = inputData.maxIterations
var epsilon1 = inputData.epsilons[0] // convergence tolerance for gradient
var epsilon2 = inputData.epsilons[1] // convergence tolerance for parameters
var epsilon3 = inputData.epsilons[2] // convergence tolerance for Chi-square
var epsilon4 = inputData.epsilons[3] // determines acceptance of a L-M step
var lambda0 = inputData.lambdas[0] // initial value of damping paramter, lambda
var lambdaUpFac = inputData.lambdas[1] // factor for increasing lambda
var lambdaDnFac = inputData.lambdas[2] // factor for decreasing lambda
var updateType = inputData.updateType // 1: Levenberg-Marquardt lambda update
// 2: Quadratic update
// 3: Nielsen's lambda update equations
if (inputData.nargin < 9) {
maxIterations = 10 * Npar
epsilon1 = 1e-3
epsilon2 = 1e-3
epsilon3 = 1e-1
epsilon4 = 1e-1
lambda0 = 1e-2
lambdaUpFac = 11.0
lambdaDnFac = 9.0
updateType = 1
}
val prnt = opts[0] // >1 intermediate results; >2 plots
val maxIterations = opts[1].toInt() // maximum number of iterations
val epsilon1 = opts[2] // convergence tolerance for gradient
val epsilon2 = opts[3] // convergence tolerance for parameters
val epsilon3 = opts[4] // convergence tolerance for Chi-square
val epsilon4 = opts[5] // determines acceptance of a L-M step
val lambda0 = opts[6] // initial value of damping paramter, lambda
val lambdaUpFac = opts[7] // factor for increasing lambda
val lambdaDnFac = opts[8] // factor for decreasing lambda
val updateType = opts[9].toInt() // 1: Levenberg-Marquardt lambda update
// 2: Quadratic update
// 3: Nielsen's lambda update equations
pMin = makeColumn(pMin)
pMax = makeColumn(pMax)
minParameters = makeColumn(minParameters)
maxParameters = makeColumn(maxParameters)
if (length(makeColumn(dp)) == 1) {
dp = ones(ShapeND(intArrayOf(Npar, 1))).div(1 / dp[0, 0]).as2D()
@ -146,7 +190,7 @@ public fun DoubleTensorAlgebra.lm(
}
// initialize Jacobian with finite difference calculation
var lmMatxAns = lmMatx(func, t, pOld, yOld, 1, J, p, yDatInput, weight, dp, settings)
var lmMatxAns = lmMatx(inputData.func, t, pOld, yOld, 1, J, p, inputData.realValues, weight, dp, settings)
var JtWJ = lmMatxAns[0]
var JtWdy = lmMatxAns[1]
X2 = lmMatxAns[2][0, 0]
@ -189,9 +233,9 @@ public fun DoubleTensorAlgebra.lm(
}
var pTry = (p + h).as2D() // update the [idx] elements
pTry = smallestElementComparison(largestElementComparison(pMin, pTry.as2D()), pMax) // apply constraints
pTry = smallestElementComparison(largestElementComparison(minParameters, pTry.as2D()), maxParameters) // apply constraints
var deltaY = yDatInput.minus(evaluateFunction(func, t, pTry, exampleNumber)) // residual error using p_try
var deltaY = inputData.realValues.minus(evaluateFunction(inputData.func, t, pTry, inputData.exampleNumber)) // residual error using p_try
for (i in 0 until deltaY.shape.component1()) { // floating point error; break
for (j in 0 until deltaY.shape.component2()) {
@ -214,9 +258,9 @@ public fun DoubleTensorAlgebra.lm(
val alpha = JtWdy.transpose().dot(h) / ((X2Try.minus(X2)).div(2.0).plus(2 * JtWdy.transpose().dot(h)))
h = h.dot(alpha)
pTry = p.plus(h).as2D() // update only [idx] elements
pTry = smallestElementComparison(largestElementComparison(pMin, pTry), pMax) // apply constraints
pTry = smallestElementComparison(largestElementComparison(minParameters, pTry), maxParameters) // apply constraints
deltaY = yDatInput.minus(evaluateFunction(func, t, pTry, exampleNumber)) // residual error using p_try
deltaY = inputData.realValues.minus(evaluateFunction(inputData.func, t, pTry, inputData.exampleNumber)) // residual error using p_try
settings.funcCalls += 1
X2Try = deltaY.as2D().transpose().dot(deltaY.times(weight)) // Chi-squared error criteria
@ -242,7 +286,7 @@ public fun DoubleTensorAlgebra.lm(
yOld = yHat.copyToTensor().as2D()
p = makeColumn(pTry) // accept p_try
lmMatxAns = lmMatx(func, t, pOld, yOld, dX2.toInt(), J, p, yDatInput, weight, dp, settings)
lmMatxAns = lmMatx(inputData.func, t, pOld, yOld, dX2.toInt(), J, p, inputData.realValues, weight, dp, settings)
// decrease lambda ==> Gauss-Newton method
JtWJ = lmMatxAns[0]
@ -268,7 +312,7 @@ public fun DoubleTensorAlgebra.lm(
} else { // it IS NOT better
X2 = X2Old // do not accept p_try
if (settings.iteration % (2 * Npar) == 0) { // rank-1 update of Jacobian
lmMatxAns = lmMatx(func, t, pOld, yOld, -1, J, p, yDatInput, weight, dp, settings)
lmMatxAns = lmMatx(inputData.func, t, pOld, yOld, -1, J, p, inputData.realValues, weight, dp, settings)
JtWJ = lmMatxAns[0]
JtWdy = lmMatxAns[1]
yHat = lmMatxAns[3]
@ -292,14 +336,13 @@ public fun DoubleTensorAlgebra.lm(
}
}
if (prnt > 1) {
val chiSq = X2 / DoF
resultInfo.iterations = settings.iteration
resultInfo.funcCalls = settings.funcCalls
resultInfo.resultChiSq = chiSq
resultInfo.resultLambda = lambda
resultInfo.resultParameters = p
}
val chiSq = X2 / DoF
resultInfo.iterations = settings.iteration
resultInfo.funcCalls = settings.funcCalls
resultInfo.resultChiSq = chiSq
resultInfo.resultLambda = lambda
resultInfo.resultParameters = p
if (abs(JtWdy).max() < epsilon1 && settings.iteration > 2) {
resultInfo.typeOfConvergence = TypeOfConvergence.InGradient

View File

@ -105,9 +105,7 @@ class TestLmAlgorithm {
ShapeND(intArrayOf(100, 1)), lm_matx_y_dat
).as2D()
val weight = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { 4.0 }
).as2D()
val weight = 4.0
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
@ -123,7 +121,12 @@ class TestLmAlgorithm {
val opts = doubleArrayOf(3.0, 100.0, 1e-3, 1e-3, 1e-1, 1e-1, 1e-2, 11.0, 9.0, 1.0)
val result = lm(::funcEasyForLm, p_init, t, y_dat, weight, dp, p_min, p_max, opts, 10, example_number)
val inputData = LMInput(::funcEasyForLm, p_init, t, y_dat, weight, dp, p_min, p_max, opts[1].toInt(),
doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
doubleArrayOf(opts[6], opts[7], opts[8]),
opts[9].toInt(), 10, example_number)
val result = levenbergMarquardt(inputData)
assertEquals(13, result.iterations)
assertEquals(31, result.funcCalls)
assertEquals(0.9131368192633, (result.resultChiSq * 1e13).roundToLong() / 1e13)
@ -168,9 +171,7 @@ class TestLmAlgorithm {
var t = t_example
val y_dat = y_hat
val weight = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { 1.0 }
).as2D()
val weight = 1.0
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
).as2D()
@ -180,8 +181,7 @@ class TestLmAlgorithm {
p_min = p_min.div(1.0 / 50.0)
val opts = doubleArrayOf(3.0, 7000.0, 1e-5, 1e-5, 1e-5, 1e-5, 1e-5, 11.0, 9.0, 1.0)
val result = DoubleTensorAlgebra.lm(
::funcMiddleForLm,
val inputData = LMInput(::funcMiddleForLm,
p_init.as2D(),
t,
y_dat,
@ -189,10 +189,14 @@ class TestLmAlgorithm {
dp,
p_min.as2D(),
p_max.as2D(),
opts,
opts[1].toInt(),
doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
doubleArrayOf(opts[6], opts[7], opts[8]),
opts[9].toInt(),
10,
1
)
1)
val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
}
@Test
@ -220,9 +224,7 @@ class TestLmAlgorithm {
var t = t_example
val y_dat = y_hat
val weight = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { 1.0 / Nparams * 1.0 - 0.085 }
).as2D()
val weight = 1.0 / Nparams * 1.0 - 0.085
val dp = BroadcastDoubleTensorAlgebra.fromArray(
ShapeND(intArrayOf(1, 1)), DoubleArray(1) { -0.01 }
).as2D()
@ -232,8 +234,7 @@ class TestLmAlgorithm {
p_min = p_min.div(1.0 / 50.0)
val opts = doubleArrayOf(3.0, 7000.0, 1e-2, 1e-3, 1e-2, 1e-2, 1e-2, 11.0, 9.0, 1.0)
val result = DoubleTensorAlgebra.lm(
::funcDifficultForLm,
val inputData = LMInput(::funcDifficultForLm,
p_init.as2D(),
t,
y_dat,
@ -241,9 +242,13 @@ class TestLmAlgorithm {
dp,
p_min.as2D(),
p_max.as2D(),
opts,
opts[1].toInt(),
doubleArrayOf(opts[2], opts[3], opts[4], opts[5]),
doubleArrayOf(opts[6], opts[7], opts[8]),
opts[9].toInt(),
10,
1
)
1)
val result = DoubleTensorAlgebra.levenbergMarquardt(inputData)
}
}