diff --git a/ackwork/ToDo b/ackwork/ToDo new file mode 100644 index 0000000000000000000000000000000000000000..66a6c3aec13703b2f43eae169d5b8c1bc729b50e --- /dev/null +++ b/ackwork/ToDo @@ -0,0 +1,9 @@ +In dorun.go + +* remove the writeclosers from the cprm structure. Just open and close the file when we have to plot or write. + +* make the csv files optional + +* If the last step was not accepted, we do not write a value out. + +* is there some way to clean up, using the go build tools ? diff --git a/ackwork/ackwork_test.go b/ackwork/ackwork_test.go index 9d4c3aa70b0bbef9972d2cd2bcf7ce8aa07d6904..43ef64162f90c0c1656e8ae90b00ddee161b84ad 100644 --- a/ackwork/ackwork_test.go +++ b/ackwork/ackwork_test.go @@ -18,6 +18,7 @@ var sTypo = ` ini_temp = 1 final_temp 0 x_ini 0.8,0.8,0.8 +x_delta, "0.4" n_step = 100000 n_output = 5000 fOutNamen testReal` @@ -118,8 +119,8 @@ func TestCsv(t *testing.T) { } var s1dplot = ` -ini_temp 0.095 -final_temp 0.06 +ini_temp 0.0925 +final_temp 0.09 x_ini 15,10,11,12,14,18,-12,-8,-9 n_step 100000 n_output 5000 diff --git a/ackwork/dorun.go b/ackwork/dorun.go index af7290da85875de7773d989a3962c3b4c42cb0ff..3713acbdd49d5d6548fed16bf9a729d8ab56281d 100644 --- a/ackwork/dorun.go +++ b/ackwork/dorun.go @@ -31,19 +31,18 @@ func getSeed() int64 { } type cprm struct { // parameters calculated from input - rand *rand.Rand - coolMult float64 // multiplier for temperature - coolme bool // Are we cooling or just doing constant temperature ? - fplotme bool // Are we making output for plotting func values - xplotme bool // Are we plotting X trajectories - nEvery uint32 // Output every nEvery steps - fOut io.WriteCloser // csv file for plotting - fPlt io.WriteCloser // for function values - xPlt io.WriteCloser // for x trajectories - plotx []float64 // Why float 64 ? Because the plotting libraries - plotf []float64 // Function values for plotting - plotTmprtr []float64 // Temperature values for plotting - plotXtrj []float32 // for plotting trajectories + rand *rand.Rand + coolMult float64 // multiplier for temperature + coolme bool // Are we cooling or just doing constant temperature ? + fplotme bool // Are we making output for plotting func values + xplotme bool // Are we plotting X trajectories + fOut io.WriteCloser // csv file for plotting + fPlt io.WriteCloser // for function values + xPlt io.WriteCloser // for x trajectories + plotnstp []float64 // Why float 64 ? Because the plotting libraries + plotf []float64 // Function values for plotting + plotTmprtr []float64 // Temperature values for plotting + plotXtrj []float32 // for plotting trajectories } // setupRun does things like get the cooling rate, seed the random numbers. @@ -71,8 +70,6 @@ func setupRun(mcPrm *mcPrm, cprm *cprm) error { cprm.coolMult = math.Exp(-coolrate) } - cprm.nEvery = uint32(math.Ceil(float64(mcPrm.nStep) / float64(mcPrm.nOutput))) - if mcPrm.fOutName, err = setSuffix(mcPrm.fOutName, ".csv"); err != nil { return err } @@ -89,7 +86,7 @@ func setupRun(mcPrm *mcPrm, cprm *cprm) error { } cprm.fplotme = true n_alloc := mcPrm.nStep / 5 // About a fifth of the number of steps - cprm.plotx = make([]float64, 0, n_alloc) + cprm.plotnstp = make([]float64, 0, n_alloc) cprm.plotf = make([]float64, 0, n_alloc) if cprm.coolme { cprm.plotTmprtr = make([]float64, 0, n_alloc) @@ -106,8 +103,8 @@ func setupRun(mcPrm *mcPrm, cprm *cprm) error { cprm.xplotme = true n_alloc := mcPrm.nStep / 5 n_dim := len(mcPrm.xIni) - cprm.plotXtrj = make([]float32, 0, int(n_alloc) * n_dim) - // Should check that cprm.plotx is allocated for the step number + cprm.plotXtrj = make([]float32, 0, int(n_alloc)*n_dim) + // Should check that cprm.plotx is allocated for the step number } return nil } @@ -122,17 +119,30 @@ func newx(xold []float32, xT []float32, rand *rand.Rand, xDlta float32) { } } -// plotFval adds a point to the data to be plotted. At the start, we check -// if we have to plot at all. This is done here, to make the main loop -// below a bit shorter. -func plotFval(n uint32, fTrial, tmprtr float64, - plotx, plotf, plotTmprtr *[]float64, plotme bool) { - if !plotme { - return - } - *plotx = append(*plotx, float64(n)) - *plotf = append(*plotf, float64(fTrial)) - *plotTmprtr = append (*plotTmprtr, tmprtr) +// printfVal is just the loop to print out the function value and coordinates +// probably for later plotting. +func printfVal(fOut io.Writer, x []float32, n uint32, tmprtr float64, fOld float64) { + fmt.Fprintf(fOut, "%d,%.4g,%.5g", n, tmprtr, fOld) + for _, xx := range x { + fmt.Fprintf(fOut, ",%.2g", xx) + } + fmt.Fprintln(fOut) +} + +// saveStep is called when we accept a change. It then writes or saves for +// later plotting. +func saveStep(cprm *cprm, n uint32, tmprtr float64, x []float32, fTrial float64) { + if cprm.fplotme || cprm.xplotme { + cprm.plotnstp = append(cprm.plotnstp, float64(n)) + } + if cprm.fplotme { // Function values + cprm.plotf = append(cprm.plotf, fTrial) + cprm.plotTmprtr = append(cprm.plotTmprtr, tmprtr) + } + if cprm.xplotme { // The trajectory + cprm.plotXtrj = append(cprm.plotXtrj, x...) + } + printfVal(cprm.fOut, x, n, tmprtr, fTrial) } // nRunAdj will try to adjust the step size, given our history of accept/reject. @@ -153,25 +163,10 @@ func nRunAdj(mcPrm *mcPrm, runAcc float64, xDlta float32) float32 { return xDlta } -// printfVal is just the loop to print out the function value and coordinates -// probably for later plotting. -func printfVal (fOut io.Writer, x []float32, n uint32, tmprtr float64, fOld float64) { - fmt.Fprintf(fOut, "%d,%.4g,%.5g", n, tmprtr, fOld) - for _, xx := range x { - fmt.Fprintf(fOut, ",%.2g", xx) - } - fmt.Fprintln(fOut) -} - -// plotXtrj adds the next x coordinates to the pltXtrj for plotting at -// the end -func plotXtrj(n uint32, x []float32, pltXtrj *[]float32, xplotme bool) { - if ! xplotme { return } - *pltXtrj = append(*pltXtrj, x...) -} - // doRun does a Monte Carlo run. Although single precision is fine for the // coordinates and function, we use double precision for the temperature. +// Unfortunately, the plotting functions want double precision, so we store +// an awful lot of stuff as float64. func doRun(mcPrm *mcPrm) error { var cprm cprm if err := setupRun(mcPrm, &cprm); err != nil { @@ -189,7 +184,7 @@ func doRun(mcPrm *mcPrm) error { var nAcc int // Counter of number of accepted moves x := make([]float32, len(mcPrm.xIni)) // current position xT := make([]float32, len(mcPrm.xIni)) // trial position - nout := uint32(1) // counter for printing output +// nout := uint32(1) // counter for printing output runAcc := accRateIdeal // Running acceptance rate, exponentially weighted copy(x, mcPrm.xIni) fOld := ackley.Ackley(x) // Initial function value @@ -197,16 +192,15 @@ func doRun(mcPrm *mcPrm) error { nRunAcc := nRunAccAdj // Every nRunAccAdj, try adjusting the step size. const runMult = 0.99 xDlta := mcPrm.xDlta // Adaptable step size - // if either plot is running, save the step. - plotFval(0, fOld, tmprtr, &cprm.plotx, &cprm.plotf, &cprm.plotTmprtr, cprm.fplotme) - plotXtrj(0, x, &cprm.plotXtrj, cprm.xplotme) + saveStep(&cprm, 0, tmprtr, x, fOld) + for n := uint32(0); n < mcPrm.nStep; n++ { var acc bool - nout-- - if nout == 0 { // Do we want to print out results on this step ? - printfVal (cprm.fOut, x, n, tmprtr, fOld) - nout = cprm.nEvery - } + // nout-- + // if nout == 0 { // Do we want to print out results on this step ? + // printfVal(cprm.fOut, x, n, tmprtr, fOld) + // nout = cprm.nEvery + // } nRunAcc-- if nRunAcc == 0 { // Do we want to try adjusting the step size ? xDlta = nRunAdj(mcPrm, runAcc, xDlta) @@ -230,8 +224,7 @@ func doRun(mcPrm *mcPrm) error { runAcc = runMult*runAcc + (1.0 - runMult) copy(x, xT) fOld = fTrial - plotFval(n+1, fTrial, tmprtr, &cprm.plotx, &cprm.plotf, &cprm.plotTmprtr, cprm.fplotme) - plotXtrj(n+1, x, &cprm.plotXtrj, cprm.xplotme) + saveStep(&cprm, n+1, tmprtr, x, fTrial) } else { // update the running estimate of acceptance runAcc = runMult * runAcc } @@ -239,11 +232,13 @@ func doRun(mcPrm *mcPrm) error { tmprtr *= cprm.coolMult } } - err := plotfWrt(cprm.plotx, cprm.plotf, cprm.plotTmprtr, cprm.fPlt, cprm.fplotme) + // On plots, we want the last step, even if nothing changed. Print me. Fix. + err := plotfWrt(cprm.plotnstp, cprm.plotf, cprm.plotTmprtr, cprm.fPlt, cprm.fplotme) if err != nil { - return err } - err = plotxWrt (&cprm, len(mcPrm.xIni)) - + return err + } + err = plotxWrt(&cprm, len(mcPrm.xIni)) + fmt.Println("n accepted:", nAcc, "of", mcPrm.nStep+1) return err } diff --git a/ackwork/plot.go b/ackwork/plot.go index 3d1478cab8eb5ee7fcfecebcf591b513806a0ffc..ac90d193253bb1cc519f22326065e69ccba077ee 100644 --- a/ackwork/plot.go +++ b/ackwork/plot.go @@ -135,7 +135,7 @@ func plotxWrt(cprm *cprm, ndim int) error { } type f64 []float64 - len_used := len(cprm.plotx) + len_used := len(cprm.plotnstp) xdata := make([]f64, ndim) fmt.Println("plotxWrt has", ndim, "dimensions and len_used is", len_used) for i := 0; i < ndim; i++ { @@ -153,7 +153,7 @@ func plotxWrt(cprm *cprm, ndim int) error { for i := 0; i < ndim; i++ { series[i] = chart.ContinuousSeries{ Name: fmt.Sprintf("dimension %d", i), - XValues: cprm.plotx, + XValues: cprm.plotnstp, YValues: xdata[i], } }