// PlotAll plot all functions func (o FuncsData) PlotAll(pd *PlotFdata, dirout, fnkey string) { ext := "png" if pd.Eps { ext = "eps" } fn := io.Sf("functions-%s.%s", fnkey, ext) plt.Reset() for k, f := range o { if utl.StrIndexSmall(pd.Skip, f.Name) >= 0 { continue } save := (k == len(o)-1) args := io.Sf("label='%s', clip_on=0", f.Name) ff := o.Get(f.Name) if ff != nil { if pd.WithTxt { x := pd.Ti y := ff.F(x, nil) plt.Text(x, y, io.Sf("%g", y), "fontsize=8") x = pd.Tf y = ff.F(x, nil) plt.Text(x, y, io.Sf("%g", y), "fontsize=8, ha='right'") } fun.PlotT(ff, dirout, fn, pd.Ti, pd.Tf, nil, pd.Np, args, pd.WithG, pd.WithH, save, false, nil) } } }
// DrawCtrl2d draws control net func (o *Nurbs) DrawCtrl2d(ids bool, args, idargs string) { if len(idargs) == 0 { idargs = "color='r', size=7" } switch o.gnd { // curve case 1: xa := make([]float64, o.n[0]) ya := make([]float64, o.n[0]) j, k := 0, 0 for i := 0; i < o.n[0]; i++ { xa[i] = o.Q[i][j][k][0] / o.Q[i][j][k][3] ya[i] = o.Q[i][j][k][1] / o.Q[i][j][k][3] } plt.Plot(xa, ya, "'k.--', clip_on=0"+args) if ids { for i := 0; i < o.n[0]; i++ { x := o.Q[i][j][k][0] / o.Q[i][j][k][3] y := o.Q[i][j][k][1] / o.Q[i][j][k][3] plt.Text(x, y, io.Sf("%d", i), idargs) } } // surface case 2: xa := make([]float64, o.n[1]) ya := make([]float64, o.n[1]) k := 0 for i := 0; i < o.n[0]; i++ { for j := 0; j < o.n[1]; j++ { xa[j] = o.Q[i][j][k][0] / o.Q[i][j][k][3] ya[j] = o.Q[i][j][k][1] / o.Q[i][j][k][3] } plt.Plot(xa, ya, "'k.--', clip_on=0"+args) } xb := make([]float64, o.n[0]) yb := make([]float64, o.n[0]) for j := 0; j < o.n[1]; j++ { for i := 0; i < o.n[0]; i++ { xb[i] = o.Q[i][j][k][0] / o.Q[i][j][k][3] yb[i] = o.Q[i][j][k][1] / o.Q[i][j][k][3] } plt.Plot(xb, yb, "'k.--', clip_on=0"+args) } if ids { for i := 0; i < o.n[0]; i++ { for j := 0; j < o.n[1]; j++ { x := o.Q[i][j][k][0] / o.Q[i][j][k][3] y := o.Q[i][j][k][1] / o.Q[i][j][k][3] l := i + j*o.n[0] plt.Text(x, y, io.Sf("%d", l), idargs) } } } } }
func main() { // GA parameters C := goga.ReadConfParams("tsp-simple.json") rnd.Init(C.Seed) // location / coordinates of stations locations := [][]float64{ {60, 200}, {180, 200}, {80, 180}, {140, 180}, {20, 160}, {100, 160}, {200, 160}, {140, 140}, {40, 120}, {100, 120}, {180, 100}, {60, 80}, {120, 80}, {180, 60}, {20, 40}, {100, 40}, {200, 40}, {20, 20}, {60, 20}, {160, 20}, } nstations := len(locations) C.SetIntOrd(nstations) C.CalcDerived() // objective value function C.OvaOor = func(ind *goga.Individual, idIsland, time int, report *bytes.Buffer) { L := locations ids := ind.Ints dist := 0.0 for i := 1; i < nstations; i++ { a, b := ids[i-1], ids[i] dist += math.Sqrt(math.Pow(L[b][0]-L[a][0], 2.0) + math.Pow(L[b][1]-L[a][1], 2.0)) } a, b := ids[nstations-1], ids[0] dist += math.Sqrt(math.Pow(L[b][0]-L[a][0], 2.0) + math.Pow(L[b][1]-L[a][1], 2.0)) ind.Ovas[0] = dist return } // evolver nova, noor := 1, 0 evo := goga.NewEvolver(nova, noor, C) evo.Run() // results io.Pfgreen("best = %v\n", evo.Best.Ints) io.Pfgreen("best OVA = %v (871.117353844847)\n\n", evo.Best.Ovas[0]) // plot travelling salesman path if C.DoPlot { plt.SetForEps(1, 300) X, Y := make([]float64, nstations), make([]float64, nstations) for k, id := range evo.Best.Ints { X[k], Y[k] = locations[id][0], locations[id][1] plt.PlotOne(X[k], Y[k], "'r.', ms=5, clip_on=0, zorder=20") plt.Text(X[k], Y[k], io.Sf("%d", id), "fontsize=7, clip_on=0, zorder=30") } plt.Plot(X, Y, "'b-', clip_on=0, zorder=10") plt.Plot([]float64{X[0], X[nstations-1]}, []float64{Y[0], Y[nstations-1]}, "'b-', clip_on=0, zorder=10") plt.Equal() plt.AxisRange(10, 210, 10, 210) plt.Gll("$x$", "$y$", "") plt.SaveD("/tmp/goga", "test_evo04.eps") } }
// PlotRosette plots rosette in octahedral plane func PlotRosette(r float64, full, ref bool, withtext bool, fsz float64) { // constants cr := 1.0 cf := 0.2 if full { cf = cr } l1 := []float64{0.0, cr * r} // line: 1 end points l2 := []float64{-cf * r * math.Cos(math.Pi/6.0), -cf * r * math.Sin(math.Pi/6.0)} // line: 2 end points l3 := []float64{cf * r * math.Cos(math.Pi/6.0), -cf * r * math.Sin(math.Pi/6.0)} // line: 3 end points l4 := []float64{-cr * r * math.Cos(math.Pi/6.0), cr * r * math.Sin(math.Pi/6.0)} // line: 4 = neg 1 end points lo := []float64{-cr * r * math.Cos(math.Pi/3.0), cr * r * math.Sin(math.Pi/3.0)} // line: origin of cylindrical system // main lines plt.Plot([]float64{0.0, l1[0]}, []float64{0.0, l1[1]}, "'k-', color='grey', zorder=0") plt.Plot([]float64{0.0, l2[0]}, []float64{0.0, l2[1]}, "'k-', color='grey', zorder=0") plt.Plot([]float64{0.0, l3[0]}, []float64{0.0, l3[1]}, "'k-', color='grey', zorder=0") // reference plt.Plot([]float64{0.0, l4[0]}, []float64{0.0, l4[1]}, "'--', color='grey', zorder=-1") if full { plt.Plot([]float64{0.0, -l4[0]}, []float64{0.0, l4[1]}, "'--', color='grey', zorder=-1") plt.Plot([]float64{0.0, 0.0}, []float64{0.0, -l1[1]}, "'--', color='grey', zorder=-1") } if ref { plt.Plot([]float64{0.0, lo[0]}, []float64{0.0, lo[1]}, "'--', color='grey', zorder=-1") if full { plt.Plot([]float64{0.0, -lo[0]}, []float64{0.0, lo[1]}, "'--', color='grey', zorder=-1") plt.Plot([]float64{-cr * r, cr * r}, []float64{0.0, 0.0}, "'--', color='grey', zorder=-1") } } // text if withtext { plt.Text(l1[0], l1[1], "$-\\sigma_1,\\\\theta=+30^\\circ$", io.Sf("ha='center', fontsize=%g", fsz)) plt.Text(l2[0], l2[1], "$-\\sigma_3$", io.Sf("ha='right', fontsize=%g", fsz)) plt.Text(l3[0], l3[1], "$-\\sigma_2$", io.Sf("ha='left', fontsize=%g", fsz)) plt.Text(lo[0], lo[1], "$\\\\theta=0^\\circ$", io.Sf("ha='center', fontsize=%g", fsz)) plt.Text(l4[0], l4[1], "$\\\\theta=-30^\\circ$", io.Sf("ha='center', fontsize=%g", fsz)) } plt.Equal() }
// FrechetPlotCoef plots coefficients for Frechet parameter's estimation func FrechetPlotCoef(dirout, fn string, amin, amax float64) { np := 201 A := utl.LinSpace(amin, amax, np) X := make([]float64, np) Y := make([]float64, np) var dist DistFrechet for i := 0; i < np; i++ { dist.Init(&VarData{L: 0, A: A[i]}) X[i] = 1.0 / A[i] μ := dist.Mean() σ2 := dist.Variance() δ2 := σ2 / (μ * μ) Y[i] = 1.0 + δ2 } k := np - 1 plt.Plot(X, Y, "'b-'") plt.Text(X[k], Y[k], io.Sf("(%.4f,%.4f)", X[k], Y[k]), "") plt.Text(X[0], Y[0], io.Sf("(%.4f,%.4f)", X[0], Y[0]), "ha='right'") plt.Gll("$1/\\alpha$", "$1+\\delta^2$", "") plt.SaveD(dirout, fn) }
func Test_invs05(tst *testing.T) { //verbose() chk.PrintTitle("invs05") if SAVEPLOT { plt.Reset() plt.SetForPng(1, 500, 125) PlotRosette(1.1, true, true, true, 7) } addtoplot := func(σa, σb float64, σ []float64) { plt.PlotOne(σa, σb, "'ro', ms=5") plt.Text(σa, σb, io.Sf("$\\sigma_{123}=(%g,%g,%g)$", σ[0], σ[1], σ[2]), "size=8") } dotest := func(σ []float64, σacor, σbcor, σccor, θcor, tolσ float64) { w := M_w(σ) θ2 := math.Asin(w) * 180.0 / (3.0 * math.Pi) θ3 := M_θ(σ) σa, σb, σc := L2O(σ[0], σ[1], σ[2]) σ0, σ1, σ2 := O2L(σa, σb, σc) σI, σA := make([]float64, 3), []float64{σa, σb, σc} la.MatVecMul(σI, 1, O2Lmat(), σA) // σI := L * σA io.Pf("σa σb σc = %v %v %v\n", σa, σb, σc) io.Pf("w = %v\n", w) io.Pf("θ2, θ3 = %v, %v\n", θ2, θ3) chk.Scalar(tst, "σa", 1e-17, σa, σacor) chk.Scalar(tst, "σb", 1e-17, σb, σbcor) chk.Scalar(tst, "σc", 1e-17, σc, σccor) chk.Scalar(tst, "σ0", tolσ, σ0, σ[0]) chk.Scalar(tst, "σ1", tolσ, σ1, σ[1]) chk.Scalar(tst, "σ2", tolσ, σ2, σ[2]) chk.Scalar(tst, "σI0", tolσ, σI[0], σ[0]) chk.Scalar(tst, "σI1", tolσ, σI[1], σ[1]) chk.Scalar(tst, "σI2", tolσ, σI[2], σ[2]) chk.Scalar(tst, "θ2", 1e-6, θ2, θcor) chk.Scalar(tst, "θ3", 1e-17, θ3, θ2) addtoplot(σa, σb, σ) } dotest([]float64{-1, 0, 0, 0}, 0, 2.0/SQ6, 1.0/SQ3, 30, 1e-15) dotest([]float64{0, -1, 0, 0}, 1.0/SQ2, -1.0/SQ6, 1.0/SQ3, 30, 1e-15) dotest([]float64{0, 0, -1, 0}, -1.0/SQ2, -1.0/SQ6, 1.0/SQ3, 30, 1e-15) if SAVEPLOT { plt.Gll("$\\sigma_a$", "$\\sigma_b$", "") plt.Equal() plt.SaveD("/tmp/gosl", "fig_invs05.png") } }
// PlotStar plots star with normalised OVAs func (o *Optimiser) PlotStar() { nf := o.Nf dθ := 2.0 * math.Pi / float64(nf) θ0 := 0.0 if nf == 3 { θ0 = -math.Pi / 6.0 } for _, ρ := range []float64{0.25, 0.5, 0.75, 1.0} { plt.Circle(0, 0, ρ, "ec='gray',lw=0.5,zorder=5") } arrowM, textM := 1.1, 1.15 for i := 0; i < nf; i++ { θ := θ0 + float64(i)*dθ xi, yi := 0.0, 0.0 xf, yf := arrowM*math.Cos(θ), arrowM*math.Sin(θ) plt.Arrow(xi, yi, xf, yf, "sc=10,st='->',lw=0.7,zorder=10,clip_on=0") plt.PlotOne(xf, yf, "'k+', ms=0") xf, yf = textM*math.Cos(θ), textM*math.Sin(θ) plt.Text(xf, yf, io.Sf("%d", i), "size=6,zorder=10,clip_on=0") } X, Y := make([]float64, nf+1), make([]float64, nf+1) clr := false neg := false step := 1 count := 0 colors := []string{"m", "orange", "g", "r", "b", "k"} var ρ float64 for i, sol := range o.Solutions { if sol.Feasible() && sol.FrontId == 0 && i%step == 0 { for j := 0; j < nf; j++ { if neg { ρ = 1.0 - sol.Ova[j]/(o.RptFmax[j]-o.RptFmin[j]) } else { ρ = sol.Ova[j] / (o.RptFmax[j] - o.RptFmin[j]) } θ := θ0 + float64(j)*dθ X[j], Y[j] = ρ*math.Cos(θ), ρ*math.Sin(θ) } X[nf], Y[nf] = X[0], Y[0] if clr { j := count % len(colors) plt.Plot(X, Y, io.Sf("'k-',color='%s',markersize=3,clip_on=0", colors[j])) } else { plt.Plot(X, Y, "'r-',marker='.',markersize=3,clip_on=0") } count++ } } plt.Equal() plt.AxisOff() }
func draw_truss(dat *FemData, key string, A *goga.Solution, lef, bot, wid, hei float64) (weight, deflection float64) { gap := 0.1 plt.PyCmds(io.Sf(` from pylab import axes, setp, sca ax_current = gca() ax_new = axes([%g, %g, %g, %g], axisbg='#dcdcdc') setp(ax_new, xticks=[0,720], yticks=[0,360]) axis('equal') axis('off') `, lef, bot, wid, hei)) _, _, weight, deflection, _, _, _ = dat.RunFEM(A.Int, A.Flt, 1, false) plt.PyCmds("sca(ax_current)\n") plt.PlotOne(weight, deflection, "'g*', zorder=1000, clip_on=0") plt.Text(weight, deflection+gap, key, "") return }
// Draw2d draws bins' grid func (o *Bins) Draw2d(withtxt bool) { // horizontal lines x := []float64{o.Xi[0], o.Xi[0] + o.L[0] + o.S} y := make([]float64, 2) for j := 0; j < o.N[1]+1; j++ { y[0] = o.Xi[1] + float64(j)*o.S y[1] = y[0] plt.Plot(x, y, "'-', color='#4f3677', clip_on=0") } // vertical lines y[0] = o.Xi[1] y[1] = o.Xi[1] + o.L[1] + o.S for i := 0; i < o.N[0]+1; i++ { x[0] = o.Xi[0] + float64(i)*o.S x[1] = x[0] plt.Plot(x, y, "'k-', color='#4f3677', clip_on=0") } // plot items for _, bin := range o.All { if bin == nil { continue } for _, entry := range bin.Entries { plt.PlotOne(entry.X[0], entry.X[1], "'r.', clip_on=0") } } // labels if withtxt { for j := 0; j < o.N[1]; j++ { for i := 0; i < o.N[0]; i++ { idx := i + j*o.N[0] x := o.Xi[0] + float64(i)*o.S + 0.02*o.S y := o.Xi[1] + float64(j)*o.S + 0.02*o.S plt.Text(x, y, io.Sf("%d", idx), "size=7") } } } // setup plt.Equal() plt.AxisRange(o.Xi[0]-0.1, o.Xf[0]+o.S+0.1, o.Xi[1]-0.1, o.Xf[1]+o.S+0.1) }
// DrawElem2D draws element (non-zero span) func (o *Nurbs) DrawElem2D(span []int, npts int, ids bool, args, idargs string) { if len(idargs) == 0 { idargs = "color='b', va='top', size=8" } switch o.gnd { // curve case 1: umin, umax := o.b[0].T[span[0]], o.b[0].T[span[1]] o.draw_edge2d(umin, umax, 0.0, 0, npts, args) if ids { c := o.Point([]float64{umin}) plt.Text(c[0], c[1], io.Sf("(%d)", span[0]), idargs) if span[1] == o.b[0].m-o.p[0]-1 { c := o.Point([]float64{umax}) plt.Text(c[0], c[1], io.Sf("(%d)", span[1]), idargs) } } // surface case 2: umin, umax := o.b[0].T[span[0]], o.b[0].T[span[1]] vmin, vmax := o.b[1].T[span[2]], o.b[1].T[span[3]] o.draw_edge2d(umin, umax, vmin, 0, npts, args) o.draw_edge2d(umin, umax, vmax, 0, npts, args) o.draw_edge2d(vmin, vmax, umin, 1, npts, args) o.draw_edge2d(vmin, vmax, umax, 1, npts, args) if ids { c := o.Point([]float64{umin, vmin}) plt.Text(c[0], c[1], io.Sf("(%d,%d)", span[0], span[2]), idargs) c = o.Point([]float64{umin, vmax}) plt.Text(c[0], c[1], io.Sf("(%d,%d)", span[0], span[3]), idargs) c = o.Point([]float64{umax, vmin}) plt.Text(c[0], c[1], io.Sf("(%d,%d)", span[1], span[2]), idargs) c = o.Point([]float64{umax, vmax}) plt.Text(c[0], c[1], io.Sf("(%d,%d)", span[1], span[3]), idargs) } } }
func Test_hyperelast01(tst *testing.T) { //verbose() chk.PrintTitle("hyperelast01") var m HyperElast1 m.Init(2, false, []*fun.Prm{ &fun.Prm{N: "kap", V: 0.05}, &fun.Prm{N: "kapb", V: 20.0}, &fun.Prm{N: "G0", V: 10000}, &fun.Prm{N: "pr", V: 2.0}, &fun.Prm{N: "pt", V: 10.0}, }) io.Pforan("m = %+v\n", m) pr := m.pr pt := m.pt np := 21 Ev := utl.LinSpace(0, -0.2, np) P := make([]float64, np) Q := make([]float64, np) X := make([]float64, np) for j, ed := range []float64{0, 0.05, 0.1, 0.15, 0.2} { for i, ev := range Ev { P[i], Q[i] = m.Calc_pq(ev, ed) X[i] = math.Log(1.0 + (P[i]+pt)/pr) } slope := (Ev[0] - Ev[np-1]) / (X[np-1] - X[0]) xm := (X[0] + X[np-1]) / 2.0 ym := (Ev[0]+Ev[np-1])/2.0 - float64(j)*0.01 plt.Subplot(3, 2, 1) plt.Plot(P, Ev, io.Sf("label='$\\\\varepsilon_d=%g$'", ed)) plt.PlotOne(P[0], Ev[0], "'ro', clip_on=0") plt.Gll("$p$", "$\\varepsilon_v$", "") plt.Subplot(3, 2, 3) plt.Plot(X, Ev, "") plt.PlotOne(X[0], Ev[0], "'ro', clip_on=0") plt.Text(xm, ym, io.Sf("slope=%g", slope), "") plt.Gll("$x=\\log{[1+(p+p_t)/p_r]}$", "$\\varepsilon_v$", "") plt.Subplot(3, 2, 5) plt.Plot(Q, Ev, "") plt.PlotOne(Q[0], Ev[0], "'ro', clip_on=0") plt.Gll("$q$", "$\\varepsilon_v$", "") } Ed := utl.LinSpace(0, -0.2, np) for j, ev := range []float64{0, -0.05, -0.1, -0.15, -0.2} { for i, ed := range Ed { P[i], Q[i] = m.Calc_pq(ev, ed) X[i] = math.Log(1.0 + (P[i]+pt)/pr) } slope := (Ed[0] - Ed[np-1]) / (Q[np-1] - Q[0]) xm := (Q[0] + Q[np-1]) / 2.0 ym := (Ed[0]+Ed[np-1])/2.0 - float64(j)*0.01 plt.Subplot(3, 2, 2) plt.Plot(P, Ed, io.Sf("label='$\\\\varepsilon_v=%g$'", ev)) plt.PlotOne(P[0], Ed[0], "'ro', clip_on=0") plt.Gll("$p$", "$\\varepsilon_d$", "") plt.Subplot(3, 2, 4) plt.Plot(X, Ed, "") plt.PlotOne(X[0], Ed[0], "'ro', clip_on=0") plt.Gll("$x=\\log{[1+(p+p_t)/p_r]}$", "$\\varepsilon_d$", "") plt.Subplot(3, 2, 6) plt.Plot(Q, Ed, "") plt.PlotOne(Q[0], Ed[0], "'ro', clip_on=0") plt.Text(xm, ym, io.Sf("slope=%g", slope), "") plt.Gll("$q$", "$\\varepsilon_d$", "") } //plt.Show() }
// Draw2d draws bins' grid func (o *Bins) Draw2d(withtxt, withgrid, withentries, setup bool, selBins map[int]bool) { if withgrid { // horizontal lines x := []float64{o.Xi[0], o.Xi[0] + o.L[0] + o.S[0]} y := make([]float64, 2) for j := 0; j < o.N[1]+1; j++ { y[0] = o.Xi[1] + float64(j)*o.S[1] y[1] = y[0] plt.Plot(x, y, "'-', color='#4f3677', clip_on=0") } // vertical lines y[0] = o.Xi[1] y[1] = o.Xi[1] + o.L[1] + o.S[1] for i := 0; i < o.N[0]+1; i++ { x[0] = o.Xi[0] + float64(i)*o.S[0] x[1] = x[0] plt.Plot(x, y, "'k-', color='#4f3677', clip_on=0") } } // selected bins nxy := o.N[0] * o.N[1] for idx, _ := range selBins { i := idx % o.N[0] // indices representing bin j := (idx % nxy) / o.N[0] x := o.Xi[0] + float64(i)*o.S[0] // coordinates of bin corner y := o.Xi[1] + float64(j)*o.S[1] plt.DrawPolyline([][]float64{ {x, y}, {x + o.S[0], y}, {x + o.S[0], y + o.S[1]}, {x, y + o.S[1]}, }, &plt.Sty{Fc: "#fbefdc", Ec: "#8e8371", Lw: 0.5, Closed: true}, "clip_on=0") } // plot items if withentries { for _, bin := range o.All { if bin == nil { continue } for _, entry := range bin.Entries { plt.PlotOne(entry.X[0], entry.X[1], "'r.', clip_on=0") } } } // labels if withtxt { for j := 0; j < o.N[1]; j++ { for i := 0; i < o.N[0]; i++ { idx := i + j*o.N[0] x := o.Xi[0] + float64(i)*o.S[0] + 0.02*o.S[0] y := o.Xi[1] + float64(j)*o.S[1] + 0.02*o.S[1] plt.Text(x, y, io.Sf("%d", idx), "size=7") } } } // setup if setup { plt.Equal() plt.AxisRange(o.Xi[0]-0.1, o.Xf[0]+o.S[0]+0.1, o.Xi[1]-0.1, o.Xf[1]+o.S[1]+0.1) } }
func Test_int02(tst *testing.T) { //verbose() chk.PrintTitle("int02. TSP") // location / coordinates of stations locations := [][]float64{ {60, 200}, {180, 200}, {80, 180}, {140, 180}, {20, 160}, {100, 160}, {200, 160}, {140, 140}, {40, 120}, {100, 120}, {180, 100}, {60, 80}, {120, 80}, {180, 60}, {20, 40}, {100, 40}, {200, 40}, {20, 20}, {60, 20}, {160, 20}, } nstations := len(locations) // parameters C := NewConfParams() C.Nova = 1 C.Noor = 0 C.Nisl = 4 C.Ninds = 24 C.RegTol = 0.3 C.RegPct = 0.2 //C.Dtmig = 30 C.GAtype = "crowd" C.ParetoPhi = 0.1 C.Elite = false C.DoPlot = false //chk.Verbose //C.Rws = true C.SetIntOrd(nstations) C.CalcDerived() // initialise random numbers generator rnd.Init(0) // objective value function C.OvaOor = func(ind *Individual, idIsland, t int, report *bytes.Buffer) { L := locations ids := ind.Ints //io.Pforan("ids = %v\n", ids) dist := 0.0 for i := 1; i < nstations; i++ { a, b := ids[i-1], ids[i] dist += math.Sqrt(math.Pow(L[b][0]-L[a][0], 2.0) + math.Pow(L[b][1]-L[a][1], 2.0)) } a, b := ids[nstations-1], ids[0] dist += math.Sqrt(math.Pow(L[b][0]-L[a][0], 2.0) + math.Pow(L[b][1]-L[a][1], 2.0)) ind.Ovas[0] = dist return } // evolver evo := NewEvolver(C) // print initial population pop := evo.Islands[0].Pop //io.Pf("\n%v\n", pop.Output(nil, false)) // 0,4,8,11,14,17,18,15,12,19,13,16,10,6,1,3,7,9,5,2 894.363 if false { for i, x := range []int{0, 4, 8, 11, 14, 17, 18, 15, 12, 19, 13, 16, 10, 6, 1, 3, 7, 9, 5, 2} { pop[0].Ints[i] = x } evo.Islands[0].CalcOvs(pop, 0) evo.Islands[0].CalcDemeritsAndSort(pop) } // check initial population ints := make([]int, nstations) if false { for i := 0; i < C.Ninds; i++ { for j := 0; j < nstations; j++ { ints[j] = pop[i].Ints[j] } sort.Ints(ints) chk.Ints(tst, "ints", ints, utl.IntRange(nstations)) } } // run evo.Run() //io.Pf("%v\n", pop.Output(nil, false)) io.Pfgreen("best = %v\n", evo.Best.Ints) io.Pfgreen("best OVA = %v (871.117353844847)\n\n", evo.Best.Ovas[0]) // best = [18 17 14 11 8 4 0 2 5 9 12 7 6 1 3 10 16 13 19 15] // best OVA = 953.4643474956656 // best = [8 11 14 17 18 15 12 19 16 13 10 6 1 3 7 9 5 2 0 4] // best OVA = 871.117353844847 // best = [5 2 0 4 8 11 14 17 18 15 12 19 16 13 10 6 1 3 7 9] // best OVA = 871.1173538448469 // best = [6 10 13 16 19 15 18 17 14 11 8 4 0 2 5 9 12 7 3 1] // best OVA = 880.7760751923065 // check final population if false { for i := 0; i < C.Ninds; i++ { for j := 0; j < nstations; j++ { ints[j] = pop[i].Ints[j] } sort.Ints(ints) chk.Ints(tst, "ints", ints, utl.IntRange(nstations)) } } // plot travelling salesman path if C.DoPlot { plt.SetForEps(1, 300) X, Y := make([]float64, nstations), make([]float64, nstations) for k, id := range evo.Best.Ints { X[k], Y[k] = locations[id][0], locations[id][1] plt.PlotOne(X[k], Y[k], "'r.', ms=5, clip_on=0, zorder=20") plt.Text(X[k], Y[k], io.Sf("%d", id), "fontsize=7, clip_on=0, zorder=30") } plt.Plot(X, Y, "'b-', clip_on=0, zorder=10") plt.Plot([]float64{X[0], X[nstations-1]}, []float64{Y[0], Y[nstations-1]}, "'b-', clip_on=0, zorder=10") plt.Equal() plt.AxisRange(10, 210, 10, 210) plt.Gll("$x$", "$y$", "") plt.SaveD("/tmp/goga", "test_evo04.eps") } }
func solve_problem(problem int) (opt *goga.Optimiser) { io.Pf("\n\n------------------------------------- problem = %d ---------------------------------------\n", problem) // parameters opt = new(goga.Optimiser) opt.Default() opt.Ncpu = 3 opt.Tf = 500 opt.Verbose = false opt.Nsamples = 1000 opt.GenType = "latin" opt.DEC = 0.1 // options for report opt.HistNsta = 6 opt.HistLen = 13 opt.RptFmtE = "%.4e" opt.RptFmtL = "%.4e" opt.RptFmtEdev = "%.3e" opt.RptFmtLdev = "%.3e" // problem variables nx := 10 opt.RptName = io.Sf("CTP%d", problem) opt.Nsol = 120 opt.FltMin = make([]float64, nx) opt.FltMax = make([]float64, nx) for i := 0; i < nx; i++ { opt.FltMin[i] = 0 opt.FltMax[i] = 1 } nf, ng, nh := 2, 1, 0 // extra problem variables var f1max float64 var fcn goga.MinProb_t var extraplot func() // problems switch problem { // problem # 0 -- TNK case 0: ng = 2 f1max = 1.21 opt.RptName = "TNK" opt.FltMin = []float64{0, 0} opt.FltMax = []float64{PI, PI} fcn = func(f, g, h, x []float64, ξ []int, cpu int) { f[0] = x[0] f[1] = x[1] g[0] = x[0]*x[0] + x[1]*x[1] - 1.0 - 0.1*math.Cos(16.0*math.Atan2(x[0], x[1])) g[1] = 0.5 - math.Pow(x[0]-0.5, 2.0) - math.Pow(x[1]-0.5, 2.0) } extraplot = func() { np := 301 X, Y := utl.MeshGrid2D(0, 1.3, 0, 1.3, np, np) Z1, Z2, Z3 := utl.DblsAlloc(np, np), utl.DblsAlloc(np, np), utl.DblsAlloc(np, np) for j := 0; j < np; j++ { for i := 0; i < np; i++ { g1 := 0.5 - math.Pow(X[i][j]-0.5, 2.0) - math.Pow(Y[i][j]-0.5, 2.0) if g1 >= 0 { Z1[i][j] = X[i][j]*X[i][j] + Y[i][j]*Y[i][j] - 1.0 - 0.1*math.Cos(16.0*math.Atan2(Y[i][j], X[i][j])) } else { Z1[i][j] = -1 } Z2[i][j] = X[i][j]*X[i][j] + Y[i][j]*Y[i][j] - 1.0 - 0.1*math.Cos(16.0*math.Atan2(Y[i][j], X[i][j])) Z3[i][j] = g1 } } plt.Contour(X, Y, Z1, "levels=[0,2],cbar=0,lwd=0.5,fsz=5,cmapidx=6") plt.Text(0.3, 0.95, "0.000", "size=5,rotation=10") plt.ContourSimple(X, Y, Z2, false, 7, "linestyles=['-'], linewidths=[0.7], colors=['k'], levels=[0]") plt.ContourSimple(X, Y, Z3, false, 7, "linestyles=['-'], linewidths=[1.0], colors=['k'], levels=[0]") } opt.Multi_fcnErr = func(f []float64) float64 { return f[0]*f[0] + f[1]*f[1] - 1.0 - 0.1*math.Cos(16.0*math.Atan2(f[0], f[1])) } // problem # 1 -- CTP1, Deb 2001, p367, fig 225 case 1: ng = 2 f1max = 1.0 a0, b0 := 0.858, 0.541 a1, b1 := 0.728, 0.295 fcn = func(f, g, h, x []float64, ξ []int, cpu int) { c0 := 1.0 for i := 1; i < len(x); i++ { c0 += x[i] } f[0] = x[0] f[1] = c0 * math.Exp(-x[0]/c0) if true { g[0] = f[1] - a0*math.Exp(-b0*f[0]) g[1] = f[1] - a1*math.Exp(-b1*f[0]) } } f0a := math.Log(a0) / (b0 - 1.0) f1a := math.Exp(-f0a) f0b := math.Log(a0/a1) / (b0 - b1) f1b := a0 * math.Exp(-b0*f0b) opt.Multi_fcnErr = func(f []float64) float64 { if f[0] < f0a { return f[1] - math.Exp(-f[0]) } if f[0] < f0b { return f[1] - a0*math.Exp(-b0*f[0]) } return f[1] - a1*math.Exp(-b1*f[0]) } extraplot = func() { np := 201 X, Y := utl.MeshGrid2D(0, 1, 0, 1, np, np) Z := utl.DblsAlloc(np, np) for j := 0; j < np; j++ { for i := 0; i < np; i++ { Z[i][j] = opt.Multi_fcnErr([]float64{X[i][j], Y[i][j]}) } } plt.Contour(X, Y, Z, "levels=[0,0.6],cbar=0,lwd=0.5,fsz=5,cmapidx=6") F0 := utl.LinSpace(0, 1, 21) F1r := make([]float64, len(F0)) F1s := make([]float64, len(F0)) F1t := make([]float64, len(F0)) for i, f0 := range F0 { F1r[i] = math.Exp(-f0) F1s[i] = a0 * math.Exp(-b0*f0) F1t[i] = a1 * math.Exp(-b1*f0) } plt.Plot(F0, F1r, "'k--',color='blue'") plt.Plot(F0, F1s, "'k--',color='green'") plt.Plot(F0, F1t, "'k--',color='gray'") plt.PlotOne(f0a, f1a, "'k|', ms=20") plt.PlotOne(f0b, f1b, "'k|', ms=20") } // problem # 2 -- CTP2, Deb 2001, p368/369, fig 226 case 2: f1max = 1.2 θ, a, b := -0.2*PI, 0.2, 10.0 c, d, e := 1.0, 6.0, 1.0 fcn = CTPgenerator(θ, a, b, c, d, e) extraplot = CTPplotter(θ, a, b, c, d, e, f1max) opt.Multi_fcnErr = CTPerror1(θ, a, b, c, d, e) // problem # 3 -- CTP3, Deb 2001, p368/370, fig 227 case 3: f1max = 1.2 θ, a, b := -0.2*PI, 0.1, 10.0 c, d, e := 1.0, 0.5, 1.0 fcn = CTPgenerator(θ, a, b, c, d, e) extraplot = CTPplotter(θ, a, b, c, d, e, f1max) opt.Multi_fcnErr = CTPerror1(θ, a, b, c, d, e) // problem # 4 -- CTP4, Deb 2001, p368/370, fig 228 case 4: f1max = 2.0 θ, a, b := -0.2*PI, 0.75, 10.0 c, d, e := 1.0, 0.5, 1.0 fcn = CTPgenerator(θ, a, b, c, d, e) extraplot = CTPplotter(θ, a, b, c, d, e, f1max) opt.Multi_fcnErr = CTPerror1(θ, a, b, c, d, e) // problem # 5 -- CTP5, Deb 2001, p368/371, fig 229 case 5: f1max = 1.2 θ, a, b := -0.2*PI, 0.1, 10.0 c, d, e := 2.0, 0.5, 1.0 fcn = CTPgenerator(θ, a, b, c, d, e) extraplot = CTPplotter(θ, a, b, c, d, e, f1max) opt.Multi_fcnErr = CTPerror1(θ, a, b, c, d, e) // problem # 6 -- CTP6, Deb 2001, p368/372, fig 230 case 6: f1max = 5.0 θ, a, b := 0.1*PI, 40.0, 0.5 c, d, e := 1.0, 2.0, -2.0 fcn = CTPgenerator(θ, a, b, c, d, e) extraplot = func() { np := 201 X, Y := utl.MeshGrid2D(0, 1, 0, 20, np, np) Z := utl.DblsAlloc(np, np) for j := 0; j < np; j++ { for i := 0; i < np; i++ { Z[i][j] = CTPconstraint(θ, a, b, c, d, e, X[i][j], Y[i][j]) } } plt.Contour(X, Y, Z, "levels=[-30,-15,0,15,30],cbar=0,lwd=0.5,fsz=5,cmapidx=6") } opt.Multi_fcnErr = CTPerror1(θ, a, b, c, d, e) // problem # 7 -- CTP7, Deb 2001, p368/373, fig 231 case 7: f1max = 1.2 θ, a, b := -0.05*PI, 40.0, 5.0 c, d, e := 1.0, 6.0, 0.0 fcn = CTPgenerator(θ, a, b, c, d, e) opt.Multi_fcnErr = func(f []float64) float64 { return f[1] - (1.0 - f[0]) } extraplot = func() { np := 201 X, Y := utl.MeshGrid2D(0, 1, 0, f1max, np, np) Z1 := utl.DblsAlloc(np, np) Z2 := utl.DblsAlloc(np, np) for j := 0; j < np; j++ { for i := 0; i < np; i++ { Z1[i][j] = opt.Multi_fcnErr([]float64{X[i][j], Y[i][j]}) Z2[i][j] = CTPconstraint(θ, a, b, c, d, e, X[i][j], Y[i][j]) } } plt.Contour(X, Y, Z2, "levels=[0,3],cbar=0,lwd=0.5,fsz=5,cmapidx=6") plt.ContourSimple(X, Y, Z1, false, 7, "linestyles=['--'], linewidths=[0.7], colors=['b'], levels=[0]") } // problem # 8 -- CTP8, Deb 2001, p368/373, fig 232 case 8: ng = 2 f1max = 5.0 θ1, a, b := 0.1*PI, 40.0, 0.5 c, d, e := 1.0, 2.0, -2.0 θ2, A, B := -0.05*PI, 40.0, 2.0 C, D, E := 1.0, 6.0, 0.0 sin1, cos1 := math.Sin(θ1), math.Cos(θ1) sin2, cos2 := math.Sin(θ2), math.Cos(θ2) fcn = func(f, g, h, x []float64, ξ []int, cpu int) { c0 := 1.0 for i := 1; i < len(x); i++ { c0 += x[i] } f[0] = x[0] f[1] = c0 * (1.0 - f[0]/c0) if true { c1 := cos1*(f[1]-e) - sin1*f[0] c2 := sin1*(f[1]-e) + cos1*f[0] c3 := math.Sin(b * PI * math.Pow(c2, c)) g[0] = c1 - a*math.Pow(math.Abs(c3), d) d1 := cos2*(f[1]-E) - sin2*f[0] d2 := sin2*(f[1]-E) + cos2*f[0] d3 := math.Sin(B * PI * math.Pow(d2, C)) g[1] = d1 - A*math.Pow(math.Abs(d3), D) } } extraplot = func() { np := 401 X, Y := utl.MeshGrid2D(0, 1, 0, 20, np, np) Z1 := utl.DblsAlloc(np, np) Z2 := utl.DblsAlloc(np, np) Z3 := utl.DblsAlloc(np, np) for j := 0; j < np; j++ { for i := 0; i < np; i++ { c1 := cos1*(Y[i][j]-e) - sin1*X[i][j] c2 := sin1*(Y[i][j]-e) + cos1*X[i][j] c3 := math.Sin(b * PI * math.Pow(c2, c)) d1 := cos2*(Y[i][j]-E) - sin2*X[i][j] d2 := sin2*(Y[i][j]-E) + cos2*X[i][j] d3 := math.Sin(B * PI * math.Pow(d2, C)) Z1[i][j] = c1 - a*math.Pow(math.Abs(c3), d) Z2[i][j] = d1 - A*math.Pow(math.Abs(d3), D) if Z1[i][j] >= 0 && Z2[i][j] >= 0 { Z3[i][j] = 1 } else { Z3[i][j] = -1 } } } plt.Contour(X, Y, Z3, "colors=['white','gray'],clabels=0,cbar=0,lwd=0.5,fsz=5") plt.ContourSimple(X, Y, Z1, false, 7, "linestyles=['--'], linewidths=[0.7], colors=['gray'], levels=[0]") plt.ContourSimple(X, Y, Z2, false, 7, "linestyles=['--'], linewidths=[0.7], colors=['gray'], levels=[0]") } opt.Multi_fcnErr = CTPerror1(θ1, a, b, c, d, e) default: chk.Panic("problem %d is not available", problem) } // initialise optimiser opt.Init(goga.GenTrialSolutions, nil, fcn, nf, ng, nh) // initial solutions var sols0 []*goga.Solution if false { sols0 = opt.GetSolutionsCopy() } // solve opt.RunMany("", "") goga.StatMulti(opt, true) io.PfYel("Tsys = %v\n", opt.SysTime) // check goga.CheckFront0(opt, true) // plot if true { feasibleOnly := false plt.SetForEps(0.8, 300) fmtAll := &plt.Fmt{L: "final solutions", M: ".", C: "orange", Ls: "none", Ms: 3} fmtFront := &plt.Fmt{L: "final Pareto front", C: "r", M: "o", Ms: 3, Ls: "none"} goga.PlotOvaOvaPareto(opt, sols0, 0, 1, feasibleOnly, fmtAll, fmtFront) extraplot() //plt.AxisYrange(0, f1max) if problem > 0 && problem < 6 { plt.Text(0.05, 0.05, "unfeasible", "color='gray', ha='left',va='bottom'") plt.Text(0.95, f1max-0.05, "feasible", "color='white', ha='right',va='top'") } if opt.RptName == "CTP6" { plt.Text(0.02, 0.15, "unfeasible", "rotation=-7,color='gray', ha='left',va='bottom'") plt.Text(0.02, 6.50, "unfeasible", "rotation=-7,color='gray', ha='left',va='bottom'") plt.Text(0.02, 13.0, "unfeasible", "rotation=-7,color='gray', ha='left',va='bottom'") plt.Text(0.50, 2.40, "feasible", "rotation=-7,color='white', ha='center',va='bottom'") plt.Text(0.50, 8.80, "feasible", "rotation=-7,color='white', ha='center',va='bottom'") plt.Text(0.50, 15.30, "feasible", "rotation=-7,color='white', ha='center',va='bottom'") } if opt.RptName == "TNK" { plt.Text(0.05, 0.05, "unfeasible", "color='gray', ha='left',va='bottom'") plt.Text(0.80, 0.85, "feasible", "color='white', ha='left',va='top'") plt.Equal() plt.AxisRange(0, 1.22, 0, 1.22) } plt.SaveD("/tmp/goga", io.Sf("%s.eps", opt.RptName)) } return }
func solve_problem(problem int) (opt *goga.Optimiser) { io.Pf("\n\n------------------------------------- problem = %d ---------------------------------------\n", problem) // GA parameters opt = new(goga.Optimiser) opt.Default() opt.Nsol = 20 opt.Ncpu = 1 opt.Tf = 40 opt.Verbose = false opt.EpsH = 1e-3 // problem variables var ng, nh int var fcn goga.MinProb_t var cprms goga.ContourParams cprms.Npts = 201 eps_prop := 0.8 eps_size := 300.0 // problems switch problem { // problem # 1: quadratic function with inequalities case 1: opt.FltMin = []float64{-2, -2} opt.FltMax = []float64{2, 2} ng, nh = 5, 0 fcn = func(f, g, h, x []float64, ξ []int, cpu int) { f[0] = x[0]*x[0]/2.0 + x[1]*x[1] - x[0]*x[1] - 2.0*x[0] - 6.0*x[1] g[0] = 2.0 - x[0] - x[1] // ≥ 0 g[1] = 2.0 + x[0] - 2.0*x[1] // ≥ 0 g[2] = 3.0 - 2.0*x[0] - x[1] // ≥ 0 g[3] = x[0] // ≥ 0 g[4] = x[1] // ≥ 0 } // problem # 2: circle with equality constraint case 2: xe := 1.0 // centre of circle le := -0.4 // selected level of f(x) ys := xe - (1.0+le)/math.Sqrt2 // coordinates of minimum point with level=le y0 := 2.0*ys + xe // vertical axis intersect of straight line defined by c(x) xc := []float64{xe, xe} // centre opt.FltMin = []float64{-1, -1} opt.FltMax = []float64{3, 3} ng, nh = 0, 1 fcn = func(f, g, h, x []float64, ξ []int, cpu int) { res := 0.0 for i := 0; i < len(x); i++ { res += (x[i] - xc[i]) * (x[i] - xc[i]) } f[0] = math.Sqrt(res) - 1.0 h[0] = x[0] + x[1] + xe - y0 } // problem # 3: Deb (2000) narrow crescent-shaped region case 3: opt.FltMin = []float64{0, 0} opt.FltMax = []float64{6, 6} ng, nh = 2, 0 fcn = func(f, g, h, x []float64, ξ []int, cpu int) { f[0] = math.Pow(x[0]*x[0]+x[1]-11.0, 2.0) + math.Pow(x[0]+x[1]*x[1]-7.0, 2.0) g[0] = 4.84 - math.Pow(x[0]-0.05, 2.0) - math.Pow(x[1]-2.5, 2.0) // ≥ 0 g[1] = x[0]*x[0] + math.Pow(x[1]-2.5, 2.0) - 4.84 // ≥ 0 } cprms.Args = "levels=[1, 10, 25, 50, 100, 200, 400, 600, 1000, 1500]" cprms.Csimple = true cprms.Lwg = 0.6 eps_prop = 1 } // initialise optimiser nf := 1 opt.Init(goga.GenTrialSolutions, nil, fcn, nf, ng, nh) // initial solutions sols0 := opt.GetSolutionsCopy() // solve opt.Solve() // results goga.SortByOva(opt.Solutions, 0) best := opt.Solutions[0] io.Pforan("X_best = %v\n", best.Flt) io.Pforan("F_best = %v\n", best.Ova[0]) io.Pforan("Oor = %v\n", best.Oor) // text box extra := func() { str := io.Sf("$f(%.5f,%.5f)=%.5f$", best.Flt[0], best.Flt[1], best.Ova[0]) plt.Text(0.98, 0.03, str, "size=12, transform=gca().transAxes, ha='right', zorder=2000, bbox=dict(boxstyle='round', facecolor='lightgray')") } // plot plt.SetForEps(eps_prop, eps_size) goga.PlotFltFltContour(io.Sf("simpleoptm%d", problem), opt, sols0, 0, 1, 0, cprms, extra, true) return opt }
// Draw draws grid // r -- radius of circles // W -- width of paths // dwt -- δwt for positioning text (w = W/2) // arrow_scale -- scale for arrows. use 0 for default value func (o *Graph) Draw(dirout, fname string, r, W, dwt, arrow_scale float64, verts_lbls map[int]string, verts_fsz float64, verts_clr string, edges_lbls map[int]string, edges_fsz float64, edges_clr string) { if len(o.Verts) < 1 { return } xmin, ymin := o.Verts[0][0], o.Verts[0][1] xmax, ymax := xmin, ymin var lbl string for i, v := range o.Verts { if verts_lbls == nil { lbl = io.Sf("%d", i) } else { lbl = verts_lbls[i] } plt.Text(v[0], v[1], lbl, io.Sf("clip_on=0, color='%s', fontsize=%g, ha='center', va='center'", verts_clr, verts_fsz)) plt.Circle(v[0], v[1], r, "clip_on=0, ec='k', lw=0.8") xmin, ymin = utl.Min(xmin, v[0]), utl.Min(ymin, v[1]) xmax, ymax = utl.Max(xmax, v[0]), utl.Max(ymax, v[1]) } if W > 2*r { W = 1.8 * r } w := W / 2.0 xa, xb := make([]float64, 2), make([]float64, 2) xc, dx := make([]float64, 2), make([]float64, 2) mu, nu := make([]float64, 2), make([]float64, 2) xi, xj := make([]float64, 2), make([]float64, 2) l := math.Sqrt(r*r - w*w) var L float64 if arrow_scale <= 0 { arrow_scale = 20 } for k, e := range o.Edges { L = 0.0 for i := 0; i < 2; i++ { xa[i] = o.Verts[e[0]][i] xb[i] = o.Verts[e[1]][i] xc[i] = (xa[i] + xb[i]) / 2.0 dx[i] = xb[i] - xa[i] L += dx[i] * dx[i] } L = math.Sqrt(L) mu[0], mu[1] = dx[0]/L, dx[1]/L nu[0], nu[1] = -dx[1]/L, dx[0]/L for i := 0; i < 2; i++ { xi[i] = xa[i] + l*mu[i] - w*nu[i] xj[i] = xb[i] - l*mu[i] - w*nu[i] xc[i] = (xi[i]+xj[i])/2.0 - dwt*nu[i] } plt.Arrow(xi[0], xi[1], xj[0], xj[1], io.Sf("st='->', sc=%g", arrow_scale)) if edges_lbls == nil { lbl = io.Sf("%d", k) } else { lbl = edges_lbls[k] } plt.Text(xc[0], xc[1], lbl, io.Sf("clip_on=0, color='%s', fontsize=%g, ha='center', va='center'", edges_clr, edges_fsz)) } xmin -= r xmax += r ymin -= r ymax += r plt.AxisOff() plt.Equal() plt.AxisRange(xmin, xmax, ymin, ymax) plt.SaveD(dirout, fname) }
// PlotDiagMoment plots bending moment diagram // Input: // M -- moment along stations // withtext -- show bending moment values // numfmt -- number format for values. use "" to chose default one // tolM -- tolerance to clip absolute values of M // sf -- scaling factor func (o *Beam) PlotDiagMoment(M []float64, withtext bool, numfmt string, tolM, sf float64) { // number of stations nstations := len(M) ds := 1.0 / float64(nstations-1) // nodes var xa, xb []float64 var u []float64 // out-of-pane vector if o.Ndim == 2 { xa = []float64{o.X[0][0], o.X[1][0], 0} xb = []float64{o.X[0][1], o.X[1][1], 0} u = []float64{0, 0, 1} } else { chk.Panic("TODO: 3D beam diagram") } // unit vector along beam v := make([]float64, 3) sum := 0.0 for j := 0; j < o.Ndim; j++ { v[j] = xb[j] - xa[j] sum += v[j] * v[j] } sum = math.Sqrt(sum) for j := 0; j < o.Ndim; j++ { v[j] /= sum } // unit normal n := make([]float64, 3) // normal utl.CrossProduct3d(n, u, v) // n := u cross v // auxiliary vectors x := make([]float64, o.Ndim) // station m := make([]float64, o.Ndim) // vector pointing to other side c := make([]float64, o.Ndim) // centre imin, imax := utl.DblArgMinMax(M) // draw text function draw_text := func(mom float64) { if math.Abs(mom) > tolM { α := math.Atan2(-n[1], -n[0]) * 180.0 / math.Pi str := io.Sf("%g", mom) if numfmt != "" { str = io.Sf(numfmt, mom) } else { if len(str) > 10 { str = io.Sf("%.10f", mom) // truncate number str = io.Sf("%g", io.Atof(str)) } } plt.Text(c[0], c[1], str, io.Sf("ha='center', size=7, rotation=%g, clip_on=0", α)) } } // draw pts := utl.DblsAlloc(nstations, 2) xx, yy := make([]float64, 2), make([]float64, 2) for i := 0; i < nstations; i++ { // station s := float64(i) * ds for j := 0; j < o.Ndim; j++ { x[j] = (1.0-s)*o.X[j][0] + s*o.X[j][1] } // auxiliary vectors for j := 0; j < o.Ndim; j++ { m[j] = x[j] - sf*M[i]*n[j] c[j] = (x[j] + m[j]) / 2.0 } // points on diagram pts[i][0], pts[i][1] = m[0], m[1] xx[0], xx[1] = x[0], m[0] yy[0], yy[1] = x[1], m[1] // draw clr, lw := "#919191", 1.0 if i == imin || i == imax { lw = 2 if M[i] < 0 { clr = "#9f0000" } else { clr = "#109f24" } } plt.Plot(xx, yy, io.Sf("'-', color='%s', lw=%g, clip_on=0", clr, lw)) if withtext { if i == imin || i == imax { // draw text @ min/max draw_text(M[i]) } else { if i == 0 || i == nstations-1 { // draw text @ extremities draw_text(M[i]) } } } } // draw polyline plt.DrawPolyline(pts, &plt.Sty{Ec: "k", Fc: "none", Lw: 1}, "") }