From e2d8b571ed9400fb8decfcf186ae9850e9ddc26f Mon Sep 17 00:00:00 2001
From: "Andrew E. Torda" <torda@zbh.uni-hamburg.de>
Date: Thu, 6 Jan 2022 13:07:53 +0100
Subject: [PATCH] Cleaned up writing of values for plotting and printing. It is
now all in one function which is only called after a move is accepted.
---
ackwork/ToDo | 9 ++++
ackwork/ackwork_test.go | 5 +-
ackwork/dorun.go | 117 +++++++++++++++++++---------------------
ackwork/plot.go | 4 +-
4 files changed, 70 insertions(+), 65 deletions(-)
create mode 100644 ackwork/ToDo
diff --git a/ackwork/ToDo b/ackwork/ToDo
new file mode 100644
index 0000000..66a6c3a
--- /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 9d4c3aa..43ef641 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 af7290d..3713acb 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 3d1478c..ac90d19 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],
}
}
--
GitLab