// HashPoint returns a unique id of a point func HashPoint(x, xmin, xdel []float64, tol float64) int { if tol < 1e-15 { chk.Panic("HashPoint: minimum tolerance must be 1e-15. %v is invalid", tol) } coefs := []float64{11, 101, 1001} n := utl.Imin(len(x), 3) var hash, xbar float64 for i := 0; i < n; i++ { if x[i] < xmin[i] { chk.Panic("HashPoint: coordinate is outside range: %v < %v", x[i], xmin[i]) } if x[i] > xmin[i]+xdel[i] { chk.Panic("HashPoint: coordinate is outside range: %v > %v", x[i], xmin[i]+xdel[i]) } if xdel[i] > 0 { xbar = (x[i] - xmin[i]) / xdel[i] if xbar < 0 { xbar = 0 } if xbar > 1 { xbar = 1 } hash += (xbar / tol) * coefs[i] } } return int(hash) }
// Solve solves optimisation problem func (o *Optimiser) Solve() { // benchmark if o.Verbose { t0 := gotime.Now() defer func() { io.Pf("\nnfeval = %d\n", o.Nfeval) io.Pfblue2("cpu time = %v\n", gotime.Now().Sub(t0)) }() } // output if o.Output != nil { o.Output(0, o.Solutions) } // perform evolution done := make(chan int, o.Ncpu) time := 0 texc := time + o.DtExc for time < o.Tf { // run groups in parallel. up to exchange time for icpu := 0; icpu < o.Ncpu; icpu++ { go func(cpu int) { nfeval := 0 for t := time; t < texc; t++ { if cpu == 0 && o.Verbose { io.Pf("time = %10d\r", t+1) } nfeval += o.EvolveOneGroup(cpu) } done <- nfeval }(icpu) } for cpu := 0; cpu < o.Ncpu; cpu++ { o.Nfeval += <-done } // compute metrics with all solutions included o.Metrics.Compute(o.Solutions) // exchange via tournament if o.Ncpu > 1 { if o.ExcTour { for i := 0; i < o.Ncpu; i++ { j := (i + 1) % o.Ncpu I := rnd.IntGetUnique(o.Groups[i].Indices, 2) J := rnd.IntGetUnique(o.Groups[j].Indices, 2) A, B := o.Groups[i].All[I[0]], o.Groups[i].All[I[1]] a, b := o.Groups[j].All[J[0]], o.Groups[j].All[J[1]] o.Tournament(A, B, a, b, o.Metrics) } } // exchange one randomly if o.ExcOne { rnd.IntGetGroups(o.cpupairs, utl.IntRange(o.Ncpu)) for _, pair := range o.cpupairs { i, j := pair[0], pair[1] n := utl.Imin(o.Groups[i].Ncur, o.Groups[j].Ncur) k := rnd.Int(0, n) A := o.Groups[i].All[k] B := o.Groups[j].All[k] B.CopyInto(o.tmp) A.CopyInto(B) o.tmp.CopyInto(A) } } } // update time variables time += o.DtExc texc += o.DtExc time = utl.Imin(time, o.Tf) texc = utl.Imin(texc, o.Tf) // output if o.Output != nil { o.Output(time, o.Solutions) } } }
// Compute computes limits, find non-dominated Pareto fronts, and compute crowd distances func (o *Metrics) Compute(sols []*Solution) (nfronts int) { // reset variables and find limits z := o.Fsizes nsol := len(sols) for i, sol := range sols { // reset values sol.Nwins = 0 sol.Nlosses = 0 sol.FrontId = 0 sol.DistCrowd = 0 sol.DistNeigh = INF z[i] = 0 // check oors for j := 0; j < o.prms.Noor; j++ { if math.IsNaN(sol.Oor[j]) { chk.Panic("NaN found in out-of-range value array\n\txFlt = %v\n\txInt = %v\n\tova = %v\n\toor = %v", sol.Flt, sol.Int, sol.Ova, sol.Oor) } } // ovas range for j := 0; j < o.prms.Nova; j++ { x := sol.Ova[j] if math.IsNaN(x) { chk.Panic("NaN found in objective value array\n\txFlt = %v\n\txInt = %v\n\tova = %v\n\toor = %v", sol.Flt, sol.Int, sol.Ova, sol.Oor) } if i == 0 { o.Omin[j] = x o.Omax[j] = x } else { o.Omin[j] = utl.Min(o.Omin[j], x) o.Omax[j] = utl.Max(o.Omax[j], x) } } // floats range for j := 0; j < o.prms.Nflt; j++ { x := sol.Flt[j] if i == 0 { o.Fmin[j] = x o.Fmax[j] = x } else { o.Fmin[j] = utl.Min(o.Fmin[j], x) o.Fmax[j] = utl.Max(o.Fmax[j], x) } } // ints range for j := 0; j < o.prms.Nint; j++ { x := sol.Int[j] if i == 0 { o.Imin[j] = x o.Imax[j] = x } else { o.Imin[j] = utl.Imin(o.Imin[j], x) o.Imax[j] = utl.Imax(o.Imax[j], x) } } } // compute neighbour distance for i := 0; i < nsol; i++ { A := sols[i] for j := i + 1; j < nsol; j++ { B := sols[j] o.closest(A, B) } } // skip if single-objective problem if o.prms.Nova < 2 { return } // compute wins/losses data for i := 0; i < nsol; i++ { A := sols[i] for j := i + 1; j < nsol; j++ { B := sols[j] A_win, B_win := A.Compare(B) if A_win { A.WinOver[A.Nwins] = B A.Nwins++ B.Nlosses++ } if B_win { B.WinOver[B.Nwins] = A B.Nwins++ A.Nlosses++ } } } // first front for _, sol := range sols { if sol.Nlosses == 0 { o.Fronts[0][z[0]] = sol z[0]++ } } // next fronts for r, front := range o.Fronts { if z[r] == 0 { break } s := r + 1 nfronts++ for i := 0; i < z[r]; i++ { A := front[i] for j := 0; j < A.Nwins; j++ { B := A.WinOver[j] B.Nlosses-- if B.Nlosses == 0 { // B belongs to next front B.FrontId = s o.Fronts[s][z[s]] = B z[s]++ } } } } // crowd distances for r := 0; r < nfronts; r++ { l, m := z[r], z[r]-1 if l == 1 { o.Fronts[r][0].DistCrowd = -1 continue } F := o.Fronts[r][:l] for j := 0; j < o.prms.Nova; j++ { SortByOva(F, j) δ := o.Omax[j] - o.Omin[j] + 1e-15 F[0].DistCrowd = INF F[m].DistCrowd = INF for i := 1; i < m; i++ { F[i].DistCrowd += ((F[i].Ova[j] - F[i-1].Ova[j]) / δ) * ((F[i+1].Ova[j] - F[i].Ova[j]) / δ) } } } return }