// AddtoRhs adds the essential bcs / constraints terms to the augmented fb vector func (o EssentialBcs) AddToRhs(fb []float64, sol *Solution) { // skip if there are no constraints if len(o.Bcs) == 0 { return } // add -At*λ to fb la.SpMatTrVecMulAdd(fb, -1, o.Am, sol.L) // fb += -1 * At * λ // assemble -rc = c - A*y into fb ny := len(sol.Y) for i, c := range o.Bcs { fb[ny+i] = c.Fcn.F(sol.T, nil) } la.SpMatVecMulAdd(fb[ny:], -1, o.Am, sol.Y) // fb += -1 * A * y }
// Solve solves linear programming problem func (o *LinIpm) Solve(verbose bool) (err error) { // starting point AAt := la.MatAlloc(o.Nl, o.Nl) // A*Aᵀ d := make([]float64, o.Nl) // inv(AAt) * b e := make([]float64, o.Nl) // A * c la.SpMatMatTrMul(AAt, 1, o.A) // AAt := A*Aᵀ la.SpMatVecMul(e, 1, o.A, o.C) // e := A * c la.SPDsolve2(d, o.L, AAt, o.B, e) // d := inv(AAt) * b and L := inv(AAt) * e la.SpMatTrVecMul(o.X, 1, o.A, d) // x := Aᵀ * d la.VecCopy(o.S, 1, o.C) // s := c la.SpMatTrVecMulAdd(o.S, -1, o.A, o.L) // s -= Aᵀλ xmin := o.X[0] smin := o.S[0] for i := 1; i < o.Nx; i++ { xmin = min(xmin, o.X[i]) smin = min(smin, o.S[i]) } δx := max(-1.5*xmin, 0) δs := max(-1.5*smin, 0) var xdots, xsum, ssum float64 for i := 0; i < o.Nx; i++ { o.X[i] += δx o.S[i] += δs xdots += o.X[i] * o.S[i] xsum += o.X[i] ssum += o.S[i] } δx = 0.5 * xdots / ssum δs = 0.5 * xdots / xsum for i := 0; i < o.Nx; i++ { o.X[i] += δx o.S[i] += δs } // constants for linear solver symmetric := false timing := false // auxiliary I := o.Nx + o.Nl // control variables var μ, σ float64 // μ and σ var xrmin float64 // min{ x_i / (-Δx_i) } (x_ratio_minimum) var srmin float64 // min{ s_i / (-Δs_i) } (s_ratio_minimum) var αpa float64 // α_prime_affine var αda float64 // α_dual_affine var μaff float64 // μ_affine var ctx, btl float64 // cᵀx and bᵀl // message if verbose { io.Pf("%3s%16s%16s\n", "it", "f(x)", "error") } // perform iterations it := 0 for it = 0; it < o.NmaxIt; it++ { // compute residual la.SpMatTrVecMul(o.Rx, 1, o.A, o.L) // rx := Aᵀλ la.SpMatVecMul(o.Rl, 1, o.A, o.X) // rλ := A x ctx, btl, μ = 0, 0, 0 for i := 0; i < o.Nx; i++ { o.Rx[i] += o.S[i] - o.C[i] o.Rs[i] = o.X[i] * o.S[i] ctx += o.C[i] * o.X[i] μ += o.X[i] * o.S[i] } for i := 0; i < o.Nl; i++ { o.Rl[i] -= o.B[i] btl += o.B[i] * o.L[i] } μ /= float64(o.Nx) // check convergence lerr := math.Abs(ctx-btl) / (1.0 + math.Abs(ctx)) if verbose { fx := la.VecDot(o.C, o.X) io.Pf("%3d%16.8e%16.8e\n", it, fx, lerr) } if lerr < o.Tol { break } // assemble Jacobian o.J.Start() o.J.PutCCMatAndMatT(o.A) for i := 0; i < o.Nx; i++ { o.J.Put(i, I+i, 1.0) o.J.Put(I+i, i, o.S[i]) o.J.Put(I+i, I+i, o.X[i]) } // solve linear system if it == 0 { err = o.Lis.InitR(o.J, symmetric, false, timing) if err != nil { return } } err = o.Lis.Fact() if err != nil { return } err = o.Lis.SolveR(o.Mdy, o.R, false) // mdy := inv(J) * R if err != nil { return } // control variables xrmin, srmin = o.calc_min_ratios() αpa = min(1, xrmin) αda = min(1, srmin) μaff = 0 for i := 0; i < o.Nx; i++ { μaff += (o.X[i] - αpa*o.Mdx[i]) * (o.S[i] - αda*o.Mds[i]) } μaff /= float64(o.Nx) σ = math.Pow(μaff/μ, 3) // update residual for i := 0; i < o.Nx; i++ { o.Rs[i] += o.Mdx[i]*o.Mds[i] - σ*μ } // solve linear system again err = o.Lis.SolveR(o.Mdy, o.R, false) // mdy := inv(J) * R if err != nil { return } // step lengths xrmin, srmin = o.calc_min_ratios() αpa = min(1, 0.99*xrmin) αda = min(1, 0.99*srmin) // update for i := 0; i < o.Nx; i++ { o.X[i] -= αpa * o.Mdx[i] o.S[i] -= αda * o.Mds[i] } for i := 0; i < o.Nl; i++ { o.L[i] -= αda * o.Mdl[i] } } // check convergence if it == o.NmaxIt { err = chk.Err("iterations did not converge") } return }