func solve_problem(fnkey string, problem int) (opt *goga.Optimiser) { // GA parameters opt = new(goga.Optimiser) opt.Default() // options for report opt.RptFmtF = "%.4f" opt.RptFmtX = "%.3f" opt.RptFmtFdev = "%.1e" opt.RptWordF = "\\beta" opt.HistFmt = "%.2f" opt.HistNdig = 3 opt.HistDelFmin = 0.005 opt.HistDelFmax = 0.005 // FORM data var lsft LSF_T var vars rnd.Variables // simple problem or FEM sim if fnkey == "simple" { opt.Read("ga-simple.json") opt.ProbNum = problem lsft, vars = get_simple_data(opt) fnkey += io.Sf("-%d", opt.ProbNum) io.Pf("\n----------------------------------- simple problem %d --------------------------------\n", opt.ProbNum) } else { opt.Read("ga-" + fnkey + ".json") lsft, vars = get_femsim_data(opt, fnkey) io.Pf("\n----------------------------------- femsim %s --------------------------------\n", fnkey) } // set limits nx := len(vars) opt.FltMin = make([]float64, nx) opt.FltMax = make([]float64, nx) for i, dat := range vars { opt.FltMin[i] = dat.Min opt.FltMax[i] = dat.Max } // log input var buf bytes.Buffer io.Ff(&buf, "%s", opt.LogParams()) io.WriteFileVD("/tmp/gosl", fnkey+".log", &buf) // initialise distributions err := vars.Init() if err != nil { chk.Panic("cannot initialise distributions:\n%v", err) } // plot distributions if opt.PlotSet1 { io.Pf(". . . . . . . . plot distributions . . . . . . . .\n") np := 201 for i, dat := range vars { plt.SetForEps(0.75, 250) dat.PlotPdf(np, "'b-',lw=2,zorder=1000") //plt.AxisXrange(dat.Min, dat.Max) plt.SetXnticks(15) plt.SaveD("/tmp/sims", io.Sf("distr-%s-%d.eps", fnkey, i)) } return } // objective function nf := 1 var ng, nh int var fcn goga.MinProb_t var obj goga.ObjFunc_t switch opt.Strategy { // argmin_x{ β(y(x)) | lsf(x) ≤ 0 } // f ← sqrt(y dot y) // g ← -lsf(x) ≥ 0 // h ← out-of-range in case Transform fails case 0: ng, nh = 1, 1 fcn = func(f, g, h, x []float64, ξ []int, cpu int) { // original and normalised variables h[0] = 0 y, invalid := vars.Transform(x) if invalid { h[0] = 1 return } // objective value f[0] = math.Sqrt(la.VecDot(y, y)) // β // inequality constraint lsf, failed := lsft(x, cpu) g[0] = -lsf h[0] = failed } // argmin_x{ β(y(x)) | lsf(x) = 0 } // f ← sqrt(y dot y) // h0 ← lsf(x) // h1 ← out-of-range in case Transform fails case 1: ng, nh = 0, 2 fcn = func(f, g, h, x []float64, ξ []int, cpu int) { // original and normalised variables h[0], h[1] = 0, 0 y, invalid := vars.Transform(x) if invalid { h[0], h[1] = 1, 1 return } // objective value f[0] = math.Sqrt(la.VecDot(y, y)) // β // equality constraint lsf, failed := lsft(x, cpu) h[0] = lsf h[1] = failed // induce minmisation of h0 //f[0] += math.Abs(lsf) } case 2: opt.Nova = 1 opt.Noor = 2 obj = func(sol *goga.Solution, cpu int) { // clear out-of-range values sol.Oor[0] = 0 // invalid transformation or FEM failed sol.Oor[1] = 0 // g(x) ≤ 0 was violated // original and normalised variables x := sol.Flt y, invalid := vars.Transform(x) if invalid { sol.Oor[0] = goga.INF sol.Oor[1] = goga.INF return } // objective value sol.Ova[0] = math.Sqrt(la.VecDot(y, y)) // β // inequality constraint lsf, failed := lsft(x, cpu) sol.Oor[0] = failed sol.Oor[1] = fun.Ramp(lsf) } default: chk.Panic("strategy %d is not available", opt.Strategy) } // initialise optimiser opt.Init(goga.GenTrialSolutions, obj, fcn, nf, ng, nh) // solve io.Pf(". . . . . . . . running . . . . . . . .\n") opt.RunMany("", "") goga.StatF(opt, 0, true) io.Pfblue2("Tsys = %v\n", opt.SysTimeAve) // check goga.CheckFront0(opt, true) // results sols := goga.GetFeasible(opt.Solutions) if len(sols) > 0 { goga.SortByOva(sols, 0) best := sols[0] io.Pforan("x = %.6f\n", best.Flt) io.Pforan("xref = %.6f\n", opt.RptXref) io.Pforan("β = %v (%v)\n", best.Ova[0], opt.RptFref[0]) } return }
// Solve solves non-linear problem f(x) == 0 func (o *NlSolver) Solve(x []float64, silent bool) (err error) { // compute scaling vector la.VecScaleAbs(o.scal, o.atol, o.rtol, x) // scal := Atol + Rtol*abs(x) // evaluate function @ x err = o.Ffcn(o.fx, x) // fx := f(x) o.NFeval, o.NJeval = 1, 0 if err != nil { return } // show message if !silent { o.msg("", 0, 0, 0, true, false) } // iterations var Ldx, Ldx_prev, Θ float64 // RMS norm of delta x, convergence rate var fx_max float64 var nfv int for o.It = 0; o.It < o.MaxIt; o.It++ { // check convergence on f(x) fx_max = la.VecLargest(o.fx, 1.0) // den = 1.0 if fx_max < o.ftol { if !silent { o.msg("fx_max(ini)", o.It, Ldx, fx_max, false, true) } break } // show message if !silent { o.msg("", o.It, Ldx, fx_max, false, false) } // output if o.Out != nil { o.Out(x) } // evaluate Jacobian @ x if o.It == 0 || !o.CteJac { if o.useDn { err = o.JfcnDn(o.J, x) } else { if o.numJ { err = Jacobian(&o.Jtri, o.Ffcn, x, o.fx, o.w, false) o.NFeval += o.neq } else { err = o.JfcnSp(&o.Jtri, x) } } o.NJeval += 1 if err != nil { return } } // dense solution if o.useDn { // invert matrix err = la.MatInvG(o.Ji, o.J, 1e-10) if err != nil { return chk.Err(_nls_err1, err.Error()) } // solve linear system (compute mdx) and compute lin-search data o.φ = 0.0 for i := 0; i < o.neq; i++ { o.mdx[i], o.dφdx[i] = 0.0, 0.0 for j := 0; j < o.neq; j++ { o.mdx[i] += o.Ji[i][j] * o.fx[j] // mdx = inv(J) * fx o.dφdx[i] += o.J[j][i] * o.fx[j] // dφdx = tra(J) * fx } o.φ += o.fx[i] * o.fx[i] } o.φ *= 0.5 // sparse solution } else { // init sparse solver if o.It == 0 { symmetric, verbose, timing := false, false, false err := o.lis.InitR(&o.Jtri, symmetric, verbose, timing) if err != nil { return chk.Err(_nls_err9, err.Error()) } } // factorisation (must be done for all iterations) o.lis.Fact() // solve linear system => compute mdx o.lis.SolveR(o.mdx, o.fx, false) // mdx = inv(J) * fx false => !sumToRoot // compute lin-search data if o.Lsearch { o.φ = 0.5 * la.VecDot(o.fx, o.fx) la.SpTriMatTrVecMul(o.dφdx, &o.Jtri, o.fx) // dφdx := transpose(J) * fx } } //io.Pforan("φ = %v\n", o.φ) //io.Pforan("dφdx = %v\n", o.dφdx) // update x Ldx = 0.0 for i := 0; i < o.neq; i++ { o.x0[i] = x[i] x[i] -= o.mdx[i] Ldx += (o.mdx[i] / o.scal[i]) * (o.mdx[i] / o.scal[i]) } Ldx = math.Sqrt(Ldx / float64(o.neq)) // calculate fx := f(x) @ update x err = o.Ffcn(o.fx, x) o.NFeval += 1 if err != nil { return } // check convergence on f(x) => avoid line-search if converged already fx_max = la.VecLargest(o.fx, 1.0) // den = 1.0 if fx_max < o.ftol { if !silent { o.msg("fx_max", o.It, Ldx, fx_max, false, true) } break } // check convergence on Ldx if Ldx < o.fnewt { if !silent { o.msg("Ldx", o.It, Ldx, fx_max, false, true) } break } // call line-search => update x and fx if o.Lsearch { nfv, err = LineSearch(x, o.fx, o.Ffcn, o.mdx, o.x0, o.dφdx, o.φ, o.LsMaxIt, true) o.NFeval += nfv if err != nil { return chk.Err(_nls_err2, err.Error()) } Ldx = 0.0 for i := 0; i < o.neq; i++ { Ldx += ((x[i] - o.x0[i]) / o.scal[i]) * ((x[i] - o.x0[i]) / o.scal[i]) } Ldx = math.Sqrt(Ldx / float64(o.neq)) fx_max = la.VecLargest(o.fx, 1.0) // den = 1.0 if Ldx < o.fnewt { if !silent { o.msg("Ldx(linsrch)", o.It, Ldx, fx_max, false, true) } break } } // check convergence rate if o.It > 0 && o.ChkConv { Θ = Ldx / Ldx_prev if Θ > 0.99 { return chk.Err(_nls_err3, Θ, Ldx, Ldx_prev) } } Ldx_prev = Ldx } // output if o.Out != nil { o.Out(x) } // check convergence if o.It == o.MaxIt { err = chk.Err(_nls_err4, o.It) } return }
func Test_geninvs01(tst *testing.T) { //verbose() chk.PrintTitle("geninvs01") // coefficients for smp invariants smp_a := -1.0 smp_b := 0.5 smp_β := 1e-1 // derivative values become too high with smp_ϵ := 1e-1 // small β and ϵ @ zero // constants for checking derivatives dver := chk.Verbose dtol := 1e-6 dtol2 := 1e-6 // run tests nd := test_nd for idxA := 0; idxA < len(test_nd); idxA++ { //for idxA := 10; idxA < 11; idxA++ { // tensor and eigenvalues A := test_AA[idxA] a := M_Alloc2(nd[idxA]) Ten2Man(a, A) L := make([]float64, 3) M_EigenValsNum(L, a) // SMP derivs and SMP director dndL := la.MatAlloc(3, 3) dNdL := make([]float64, 3) d2ndLdL := utl.Deep3alloc(3, 3, 3) N := make([]float64, 3) F := make([]float64, 3) G := make([]float64, 3) m := SmpDerivs1(dndL, dNdL, N, F, G, L, smp_a, smp_b, smp_β, smp_ϵ) SmpDerivs2(d2ndLdL, L, smp_a, smp_b, smp_β, smp_ϵ, m, N, F, G, dNdL, dndL) n := make([]float64, 3) SmpUnitDirector(n, m, N) // SMP invariants p, q, err := GenInvs(L, n, smp_a) if err != nil { chk.Panic("SmpInvs failed:\n%v", err) } // output io.PfYel("\n\ntst # %d ###################################################################################\n", idxA) io.Pfblue2("L = %v\n", L) io.Pforan("n = %v\n", n) io.Pforan("p = %v\n", p) io.Pforan("q = %v\n", q) // check invariants tvec := make([]float64, 3) GenTvec(tvec, L, n) proj := make([]float64, 3) // projection of tvec along n tdn := la.VecDot(tvec, n) // tvec dot n for i := 0; i < 3; i++ { proj[i] = tdn * n[i] } norm_proj := la.VecNorm(proj) norm_tvec := la.VecNorm(tvec) q_ := GENINVSQEPS + math.Sqrt(norm_tvec*norm_tvec-norm_proj*norm_proj) io.Pforan("proj = %v\n", proj) io.Pforan("norm(proj) = %v == p\n", norm_proj) chk.Scalar(tst, "p", 1e-14, math.Abs(p), norm_proj) chk.Scalar(tst, "q", 1e-13, q, q_) // dt/dL var tmp float64 N_tmp := make([]float64, 3) n_tmp := make([]float64, 3) tvec_tmp := make([]float64, 3) dtdL := la.MatAlloc(3, 3) GenTvecDeriv1(dtdL, L, n, dndL) for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDirector(N_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) GenTvec(tvec_tmp, L, n_tmp) L[j] = tmp return tvec_tmp[i] }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("dt/dL[%d][%d]", i, j), dtol, dtdL[i][j], dnum, dver) } } // d²t/dLdL io.Pfpink("\nd²t/dLdL\n") dNdL_tmp := make([]float64, 3) dndL_tmp := la.MatAlloc(3, 3) dtdL_tmp := la.MatAlloc(3, 3) for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { for k := 0; k < 3; k++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[k] = L[k], x m_tmp := SmpDerivs1(dndL_tmp, dNdL_tmp, N_tmp, F, G, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) GenTvecDeriv1(dtdL_tmp, L, n_tmp, dndL_tmp) L[k] = tmp return dtdL_tmp[i][j] }, L[k], 1e-6) dana := GenTvecDeriv2(i, j, k, L, dndL, d2ndLdL[i][j][k]) chk.AnaNum(tst, io.Sf("d²t[%d]/dL[%d]dL[%d]", i, j, k), dtol2, dana, dnum, dver) } } } // change tolerance dtol_tmp := dtol switch idxA { case 5, 11: dtol = 1e-5 case 12: dtol = 0.0013 } // first order derivatives dpdL := make([]float64, 3) dqdL := make([]float64, 3) p_, q_, err := GenInvsDeriv1(dpdL, dqdL, L, n, dndL, smp_a) if err != nil { chk.Panic("%v", err) } chk.Scalar(tst, "p", 1e-17, p, p_) chk.Scalar(tst, "q", 1e-17, q, q_) var ptmp, qtmp float64 io.Pfpink("\ndp/dL\n") for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDirector(N_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) ptmp, _, err = GenInvs(L, n_tmp, smp_a) if err != nil { chk.Panic("DerivCentral: SmpInvs failed:\n%v", err) } L[j] = tmp return ptmp }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("dp/dL[%d]", j), dtol, dpdL[j], dnum, dver) } io.Pfpink("\ndq/dL\n") for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDirector(N_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) _, qtmp, err = GenInvs(L, n_tmp, smp_a) if err != nil { chk.Panic("DerivCentral: SmpInvs failed:\n%v", err) } L[j] = tmp return qtmp }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("dq/dL[%d]", j), dtol, dqdL[j], dnum, dver) } // recover tolerance dtol = dtol_tmp // change tolerance io.Pforan("dtol2 = %v\n", dtol2) dtol2_tmp := dtol2 switch idxA { case 5: dtol2 = 1e-5 case 10: dtol2 = 0.72 case 11: dtol2 = 1e-5 case 12: dtol2 = 544 } // second order derivatives dpdL_tmp := make([]float64, 3) dqdL_tmp := make([]float64, 3) d2pdLdL := la.MatAlloc(3, 3) d2qdLdL := la.MatAlloc(3, 3) GenInvsDeriv2(d2pdLdL, d2qdLdL, L, n, dpdL, dqdL, p, q, dndL, d2ndLdL, smp_a) io.Pfpink("\nd²p/dLdL\n") for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDerivs1(dndL_tmp, dNdL_tmp, N_tmp, F, G, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) GenInvsDeriv1(dpdL_tmp, dqdL_tmp, L, n_tmp, dndL_tmp, smp_a) L[j] = tmp return dpdL_tmp[i] }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("d²p/dL[%d][%d]", i, j), dtol2, d2pdLdL[i][j], dnum, dver) } } io.Pfpink("\nd²q/dLdL\n") for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDerivs1(dndL_tmp, dNdL_tmp, N_tmp, F, G, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) GenInvsDeriv1(dpdL_tmp, dqdL_tmp, L, n_tmp, dndL_tmp, smp_a) L[j] = tmp return dqdL_tmp[i] }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("d²q/dL[%d][%d]", i, j), dtol2, d2qdLdL[i][j], dnum, dver) } } // recover tolerance dtol2 = dtol2_tmp } }
// 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 }