// startingStepSize implements the algorithm for estimating the starting step // size as described in: // - Hairer, E., Wanner, G., Nørsett, S.: Solving Ordinary Differential // Equations I: Nonstiff Problems. Springer Berlin Heidelberg (1993) func startingStepSize(rhs Function, init, tmp *State, weight Weighting, w []float64, order float64, s *Settings) float64 { // Store 1 / (rtol * |Y_i| + atol) into w. weight(init.Y, w) d0 := s.Norm(init.Y, w) d1 := s.Norm(init.YDot, w) var h0 float64 if math.Min(d0, d1) < 1e-5 { h0 = 1e-6 } else { // Make the increment of an explicit Euler step small compared to the // size of the initial value. h0 = 0.01 * d0 / d1 } // Perform one explicit Euler step. floats.AddScaledTo(tmp.Y, init.Y, h0, init.YDot) // Evaluate the right-hand side f(init.Time+h, tmp.Y). rhs(tmp.YDot, init.Time+h0, tmp.Y) // Estimate the second derivative of the solution. floats.Sub(tmp.YDot, init.YDot) d2 := s.Norm(tmp.YDot, w) / h0 var h1 float64 if math.Max(d1, d2) < 1e-15 { h1 = math.Max(1e-6, 1e-3*h0) } else { h1 = math.Pow(0.01/math.Max(d1, d2), 1/(order+1)) } return math.Min(100*h0, h1) }
func fitnessRMSE(ind, targ *imgut.Image) float64 { // Images to vector dataInd := imgut.ToSlice(ind) dataTarg := imgut.ToSlice(targ) // (root mean square) error floats.Sub(dataInd, dataTarg) // (root mean) square error floats.Mul(dataInd, dataInd) // (root) mean square error totErr := floats.Sum(dataInd) return math.Sqrt(totErr / float64(len(dataInd))) }
func MakeFitMSE(targetImage *imgut.Image) func(*imgut.Image) float64 { dataTarg := imgut.ToSliceChans(targetImage, "R") return func(indImage *imgut.Image) float64 { // Get data dataImg := imgut.ToSliceChans(indImage, "R") // Difference (X - Y) floats.Sub(dataImg, dataTarg) // Squared (X - Y)^2 floats.Mul(dataImg, dataImg) // Summation return floats.Sum(dataImg) / float64(len(dataImg)) } }
func MakeFitLinScale(targetImage *imgut.Image) func(*imgut.Image) float64 { // Pre-compute image to slice of floats dataTarg := imgut.ToSlice(targetImage) // Pre-compute average avgt := floats.Sum(dataTarg) / float64(len(dataTarg)) return func(indImage *imgut.Image) float64 { // Images to vector dataInd := imgut.ToSlice(indImage) // Compute average pixels avgy := floats.Sum(dataInd) / float64(len(dataInd)) // Difference y - avgy y_avgy := make([]float64, len(dataInd)) copy(y_avgy, dataInd) floats.AddConst(-avgy, y_avgy) // Difference t - avgt t_avgt := make([]float64, len(dataTarg)) copy(t_avgt, dataTarg) floats.AddConst(-avgt, t_avgt) // Multuplication (t - avgt)(y - avgy) floats.Mul(t_avgt, y_avgy) // Summation numerator := floats.Sum(t_avgt) // Square (y - avgy)^2 floats.Mul(y_avgy, y_avgy) denomin := floats.Sum(y_avgy) // Compute b-value b := numerator / denomin // Compute a-value a := avgt - b*avgy // Compute now the scaled RMSE, using y' = a + b*y floats.Scale(b, dataInd) // b*y floats.AddConst(a, dataInd) // a + b*y floats.Sub(dataInd, dataTarg) // (a + b * y - t) floats.Mul(dataInd, dataInd) // (a + b * y - t)^2 total := floats.Sum(dataInd) // Sum(...) return math.Sqrt(total / float64(len(dataInd))) } }
func (lbfgs *Lbfgs) Iterate(loc *multi.Location, obj *uni.Objective, grad *multi.Gradient, fun optimize.MultiObjGrad) (status.Status, error) { counter := lbfgs.counter q := lbfgs.q a := lbfgs.a b := lbfgs.b rhoHist := lbfgs.rhoHist sHist := lbfgs.sHist yHist := lbfgs.yHist gamma_k := lbfgs.gamma_k tmp := lbfgs.tmp p_k := lbfgs.p_k s_k := lbfgs.s_k y_k := lbfgs.y_k z := lbfgs.z // Calculate search direction for i, val := range grad.Curr() { q[i] = val } for i := counter - 1; i >= 0; i-- { a[i] = rhoHist[i] * floats.Dot(sHist[i], q) copy(tmp, yHist[i]) floats.Scale(a[i], tmp) floats.Sub(q, tmp) } for i := lbfgs.NumStore - 1; i >= counter; i-- { a[i] = rhoHist[i] * floats.Dot(sHist[i], q) copy(tmp, yHist[i]) floats.Scale(a[i], tmp) //fmt.Println(q) //fmt.Println(tmp) floats.Sub(q, tmp) } // Assume H_0 is the identity times gamma_k copy(z, q) floats.Scale(gamma_k, z) // Second loop for update, going oldest to newest for i := counter; i < lbfgs.NumStore; i++ { b[i] = rhoHist[i] * floats.Dot(yHist[i], z) copy(tmp, sHist[i]) floats.Scale(a[i]-b[i], tmp) floats.Add(z, tmp) } for i := 0; i < counter; i++ { b[i] = rhoHist[i] * floats.Dot(yHist[i], z) copy(tmp, sHist[i]) floats.Scale(a[i]-b[i], tmp) floats.Add(z, tmp) } lbfgs.a = a lbfgs.b = b copy(p_k, z) floats.Scale(-1, p_k) normP_k := floats.Norm(p_k, 2) // Perform line search -- need to find some way to implement this, especially bookkeeping function values linesearchResult, err := linesearch.Linesearch(fun, lbfgs.LinesearchMethod, lbfgs.LinesearchSettings, lbfgs.Wolfe, p_k, loc.Curr(), obj.Curr(), grad.Curr()) // In the future add a check to switch to a different linesearcher? if err != nil { return status.LinesearchFailure, err } x_kp1 := linesearchResult.Loc f_kp1 := linesearchResult.Obj g_kp1 := linesearchResult.Grad alpha_k := linesearchResult.Step // Update hessian estimate copy(s_k, p_k) floats.Scale(alpha_k, s_k) copy(y_k, g_kp1) floats.Sub(y_k, grad.Curr()) skDotYk := floats.Dot(s_k, y_k) // Bookkeep the results stepSize := alpha_k * normP_k lbfgs.step.AddToHist(stepSize) lbfgs.step.SetCurr(stepSize) loc.SetCurr(x_kp1) //lbfgs.loc.AddToHist(x_kp1) //fmt.Println(lbfgs.loc.GetHist()) obj.SetCurr(f_kp1) grad.SetCurr(g_kp1) copy(sHist[counter], s_k) copy(yHist[counter], y_k) rhoHist[counter] = 1 / skDotYk lbfgs.gamma_k = skDotYk / floats.Dot(y_k, y_k) lbfgs.counter += 1 if lbfgs.counter == lbfgs.NumStore { lbfgs.counter = 0 } return status.Continue, nil }
// findInitialBasic finds an initial basic solution, and returns the basic // indices, ab, and xb. func findInitialBasic(A mat64.Matrix, b []float64) ([]int, *mat64.Dense, []float64, error) { m, n := A.Dims() basicIdxs := findLinearlyIndependent(A) if len(basicIdxs) != m { return nil, nil, nil, ErrSingular } // It may be that this linearly independent basis is also a feasible set. If // so, the Phase I problem can be avoided. ab := extractColumns(A, basicIdxs) xb, err := initializeFromBasic(ab, b) if err == nil { return basicIdxs, ab, xb, nil } // This set was not feasible. Instead the "Phase I" problem must be solved // to find an initial feasible set of basis. // // Method: Construct an LP whose optimal solution is a feasible solution // to the original LP. // 1) Introduce an artificial variable x_{n+1}. // 2) Let x_j be the most negative element of x_b (largest constraint violation). // 3) Add the artificial variable to A with: // a_{n+1} = b - \sum_{i in basicIdxs} a_i + a_j // swap j with n+1 in the basicIdxs. // 4) Define a new LP: // minimize x_{n+1} // subject to [A A_{n+1}][x_1 ... x_{n+1}] = b // x, x_{n+1} >= 0 // 5) Solve this LP. If x_{n+1} != 0, then the problem is infeasible, otherwise // the found basis can be used as an initial basis for phase II. // // The extra column in Step 3 is defined such that the vector of 1s is an // initial feasible solution. // Find the largest constraint violator. // Compute a_{n+1} = b - \sum{i in basicIdxs}a_i + a_j. j is in basicIDx, so // instead just subtract the basicIdx columns that are not minIDx. minIdx := floats.MinIdx(xb) aX1 := make([]float64, m) copy(aX1, b) col := make([]float64, m) for i, v := range basicIdxs { if i == minIdx { continue } mat64.Col(col, v, A) floats.Sub(aX1, col) } // Construct the new LP. // aNew = [A, a_{n+1}] // bNew = b // cNew = 1 for x_{n+1} aNew := mat64.NewDense(m, n+1, nil) aNew.Copy(A) aNew.SetCol(n, aX1) basicIdxs[minIdx] = n // swap minIdx with n in the basic set. c := make([]float64, n+1) c[n] = 1 // Solve the Phase 2 linear program. _, xOpt, newBasic, err := simplex(basicIdxs, c, aNew, b, 1e-10) if err != nil { return nil, nil, nil, errors.New(fmt.Sprintf("lp: error finding feasible basis: %s", err)) } // If n+1 is part of the solution basis then the problem is infeasible. If // not, then the problem is feasible and newBasic is an initial feasible // solution. if math.Abs(xOpt[n]) > phaseIZeroTol { return nil, nil, nil, ErrInfeasible } // The value is zero. First, see if it's not in the basis (feasible solution). basicIdx := -1 basicMap := make(map[int]struct{}) for i, v := range newBasic { if v == n { basicIdx = i } basicMap[v] = struct{}{} xb[i] = xOpt[v] } if basicIdx == -1 { // Not in the basis. ab = extractColumns(A, newBasic) return newBasic, ab, xb, nil } // The value is zero, but it's in the basis. See if swapping in another column // finds a feasible solution. for i := range xOpt { if _, inBasic := basicMap[i]; inBasic { continue } newBasic[basicIdx] = i ab := extractColumns(A, newBasic) xb, err := initializeFromBasic(ab, b) if err == nil { return newBasic, ab, xb, nil } } return nil, nil, nil, ErrInfeasible }