diff --git a/mc_work/ToDo b/mc_work/ToDo
index bec88f24733d30cbe508f511fc9dd65f8fc004c9..9ab631ab0053b5c9548a21f091e3488421ae7dfa 100644
--- a/mc_work/ToDo
+++ b/mc_work/ToDo
@@ -3,11 +3,4 @@ dlv test --build-flags "-tags=no_gfx"
In dorun.go
-* do we have the random number seed as a settable parameter ?
-
-* make the csv files optional
-
Note.. Benchmarking suggests that most of the time is spent in Ackley function, and, to be exact, in the cosine and exp() function.
-
-In the plottin functions,
-Put a secondary axis on the X trajectory or check out multiplots so that the two plots line up with each other.
diff --git a/mc_work/dorun.go b/mc_work/dorun.go
index 0597b26a50632167bb8e78d75120f9cbe5de05dc..042d9826c3f802f1104401ce98897e7d66f6be30 100644
--- a/mc_work/dorun.go
+++ b/mc_work/dorun.go
@@ -135,16 +135,6 @@ func setupRun(mcPrm *McPrm, cprm *cprm) error {
return nil
}
-// altnewx is not used at the moment, but I will build a switch for it.
-// It is like newx, but moves all n dimensions a bit.
-func alt_newx(xold []float32, xT []float32, rand *rand.Rand, xDlta float32) {
- for i, x := range xold {
- t := 2.*rand.Float32() - 1
- t *= xDlta
- xT[i] = x + t
- }
-}
-
// newx will move just one coordinate at a time
func newx(xold []float32, xT []float32, rand *rand.Rand, xDlta float64) {
var iDim int
@@ -203,10 +193,11 @@ func nRunAdj(mcPrm *McPrm, nstep int, runAcc float64, xDlta float64) float64 {
// 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) ([]byte, []byte, error) {
+func DoRun(mcPrm *McPrm) (MCresult, error) {
var cprm cprm
+ broken := MCresult{}
if err := setupRun(mcPrm, &cprm); err != nil {
- return nil, nil, err
+ return broken, err
}
if cprm.doTxtFval { // The text file documenting the run
defer cprm.fOutRaw.Close()
@@ -271,13 +262,13 @@ func DoRun(mcPrm *McPrm) ([]byte, []byte, error) {
if fTrial != fOld { // last move was not accepted, so we have to add last step
saveStep(&cprm, mcPrm.NStep, tmprtr, x, fOld)
}
- defer fmt.Println("n accepted:", nAcc, "of", mcPrm.NStep+1)
+ defer fmt.Println("n accepted:", nAcc, "of", mcPrm.NStep)
if err := plotfWrt(&cprm); err != nil {
- return nil, nil, err
+ return broken, err
}
if err := plotxWrt(&cprm, len(mcPrm.XIni)); err != nil {
- return nil, nil, err
+ return broken, err
}
var fdata, xdata []byte
@@ -287,7 +278,6 @@ func DoRun(mcPrm *McPrm) ([]byte, []byte, error) {
if xBuf, ok := cprm.xplotWrt.(withBytes); ok {
xdata = xBuf.Bytes()
}
- nothing(fdata, xdata)
- return fdata, xdata, nil
+ return MCresult{ Fdata: fdata, Xdata: xdata, NStep: mcPrm.NStep, NAcc: nAcc}, nil
}
diff --git a/mc_work/mc_work.go b/mc_work/mc_work.go
index f1c6c43af8c37e6f7311df760dd03449c86b520d..c3dada8c3e9459aba26a421207ff7f611cdfd020 100644
--- a/mc_work/mc_work.go
+++ b/mc_work/mc_work.go
@@ -2,14 +2,10 @@
package mcwork
-import (
- "flag"
- "fmt"
- "os"
-)
-
-// Have to export everything, including the seed,
-// so the graphical interface can get to them
+// This is the structure which holds everything we read in to control
+// a Monte Carlo run.
+// Most things have to be exported so the graphical interface can get
+// to them.
type McPrm struct {
IniTmp, FnlTmp float64 // Initial and final temperatures
XIni []float32 // initial x slice
@@ -23,10 +19,12 @@ type McPrm struct {
dummy bool // for testing. If set, do not do a run
}
-var Seed int // for random numbers, but each thread gets its own value
+// For random numbers. It is not in the main structure, since, if one ever writes
+// a threaded version, each thread can have its own value.
+var Seed int
-// usage
-func usage() {
- u := `[options] [input_parameter_file]`
- fmt.Fprintf(flag.CommandLine.Output(), "usage of %s: %s\n", os.Args[0], u)
+// For returning results
+type MCresult struct {
+ Fdata, Xdata []byte // png images of function and X data
+ NStep, NAcc int // number of steps and accepted steps
}
diff --git a/mc_work/plotres.r b/mc_work/plotres.r
index bada2a0c0c1472000c4e8d17e695bca2e79b160b..412c230309df0384c0d295230c6cd1d3ab994db9 100644
--- a/mc_work/plotres.r
+++ b/mc_work/plotres.r
@@ -1,4 +1,4 @@
-# Obviously this only makes sense for local testing of some of the results
+# This only makes sense for local testing of some of the results
# We can plot out the column f_val as a function of temperature, x-coordinates, ...
names <- c("step", "temperature", "f_val", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10")
diff --git a/mc_work/realmain_nogfx.go b/mc_work/realmain_nogfx.go
index 81e7f1018a6074687e33be10b27614b3d2d162ca..351d63ac2054f095b34ad5992c4f2f7044c301e7 100644
--- a/mc_work/realmain_nogfx.go
+++ b/mc_work/realmain_nogfx.go
@@ -7,26 +7,32 @@
package mcwork
import (
+ "flag"
"fmt"
"io"
"os"
)
// realmain is the real main function. The program wants to read from a file,
-// but we can have it read from an io.Reader and then use the test functions
-// for playing with it.
+// but we can have it read from an io.Reader. This makes testing practical.
func realmain(fp io.Reader) error {
var mcPrm McPrm
if err := RdPrm(fp, &mcPrm); err != nil {
return err
}
- if _, _, err := DoRun(&mcPrm); err != nil {
+ if _, err := DoRun(&mcPrm); err != nil {
return err
}
return nil
}
+// usage
+func usage() {
+ u := `[input_parameter_file]`
+ fmt.Fprintf(flag.CommandLine.Output(), "usage of %s: %s\n", os.Args[0], u)
+}
+
// MyMain is called from the real main. It opens the input file, but passes a
// reader to the function that does the work. This lets us call it from a test
// function.
diff --git a/mc_work/set_suffix.go b/mc_work/set_suffix.go
index 154dd25a17e35cbbc9660ebf025ebcaf0de24a3c..17f95adfb53d613d0895661b9f0495e70c62c578 100644
--- a/mc_work/set_suffix.go
+++ b/mc_work/set_suffix.go
@@ -48,5 +48,3 @@ func removeQuotes(s string) string {
}
return s
}
-
-func nothing(...interface{}) {}
diff --git a/ui/input_tab.go b/ui/input_tab.go
index fda90ffffda0fd8ebcc9e3ae7a5d3ddc48cdc6d4..bd934cea3d696c38186f0df537d13c432fd26223 100644
--- a/ui/input_tab.go
+++ b/ui/input_tab.go
@@ -69,31 +69,34 @@ func validateXini(s string) error {
// This gets put on the list of things to do from the reload function.
func floatItem(xAddr *float64, label string) (*widget.FormItem, func()) {
bind := binding.BindFloat(xAddr)
- entry := widget.NewEntryWithData(binding.FloatToStringWithFormat(bind, "%.2f"))
+ entry := widget.NewEntryWithData(binding.FloatToStringWithFormat(bind, "%.3f"))
fitem := widget.NewFormItem(label, entry)
reloadfunc := func() { _ = bind.Reload() }
return fitem, reloadfunc
}
// intItem does the same wrapping as floatItem, but for ints
-func intItem(xAddr *int, label string) (*widget.FormItem, func()) {
+func intItem(xAddr *int, label string, htext string) (*widget.FormItem, func()) {
bind := binding.BindInt(xAddr)
entry := widget.NewEntryWithData(binding.IntToString(bind))
iItem := widget.NewFormItem(label, entry)
+ iItem.HintText = htext
reloadfunc := func() { _ = bind.Reload() }
return iItem, reloadfunc
}
+var xCoordHint = "The starting point. A comma-separated list of floats. It is used to set the dimensionality"
// paramBox sets up a screen full of parameters we can adjust.
// It returns the screen and a function to be called to refresh it.
// This is necessary, since there is a button to read parameters from
// a file, which means all the values should be updated.
-func paramBox(genParams genParams) *widget.Form {
+func paramForm(genParams genParams) *widget.Form {
mcPrm := genParams.mcPrm
+
iniTmpItem, iniTmpReload := floatItem(&mcPrm.IniTmp, "initial temperature")
fnlTmpItem, fnlTmpReload := floatItem(&mcPrm.FnlTmp, "final temperature")
xDltaItem, xDltaReload := floatItem(&mcPrm.XDlta, "X delta")
-
+ xDltaItem.HintText = "Maximum step size in one dimension"
xIniStr := binding.NewString()
_ = xIniStr.Set(fslicestrng(mcPrm.XIni))
xIniEntry := widget.NewEntryWithData(xIniStr)
@@ -107,10 +110,11 @@ func paramBox(genParams genParams) *widget.Form {
}
xIniEntry.Validator = validateXini
xIniItem := widget.NewFormItem("initial X", xIniEntry)
+ xIniItem.HintText = xCoordHint
- nStepItem, nStepReload := intItem(&mcPrm.NStep, "N steps")
- seedItem, seedReload := intItem(&mcwork.Seed, "seed random numbers")
-
+ nStepItem, nStepReload := intItem(&mcPrm.NStep, "N steps", "number of steps in calculation")
+ seedItem, seedReload := intItem(&mcwork.Seed, "seed random numbers", "seed for random number generator")
+
reloadPTab := func() {
iniTmpReload()
fnlTmpReload()
@@ -129,6 +133,7 @@ func paramBox(genParams genParams) *widget.Form {
nStepItem, seedItem, rdFileItem)
r.SubmitText = "start calculation"
r.OnSubmit = func() { startrun(genParams, r, mcPrm) }
+ reloadPTab() // does this help ? sometimes the form pops up with entries not ready
return r
}
@@ -177,15 +182,15 @@ func rdwork(genParams genParams, reload func()) {
func mcWrap(genParams genParams) {
chn := genParams.chn
chn <- workstatus{status: calculating}
- if fdata, xdata, err := mcwork.DoRun(genParams.mcPrm); err != nil {
+ if result, err := mcwork.DoRun(genParams.mcPrm); err != nil {
dialog.NewError(err, genParams.win).Show()
chn <- workstatus{status: errorCalc, err: err}
} else {
- chn <- workstatus{fdata: fdata, xdata: xdata, status: resultsReady}
+ chn <- workstatus{ MCresult: result, status: resultsReady}
}
}
// inputTab sets up the input page.
func inputTab(genParams genParams) *widget.Form {
- return paramBox(genParams)
+ return paramForm(genParams)
}
diff --git a/ui/mymain.go b/ui/mymain.go
index e17ff98e1aa0a77ceb5662407f249938be7ef8e0..54493ea0068ffa7f4bc4dc2b2e54bfd375ba0f4a 100644
--- a/ui/mymain.go
+++ b/ui/mymain.go
@@ -6,7 +6,6 @@
package ui
import (
- "fmt"
"io"
"os"
@@ -33,7 +32,6 @@ func realmain(fp io.Reader) error {
func MyMain() error {
if len(os.Args) < 2 {
- fmt.Println("MyMain did not get a file to work with ")
return realmain(nil)
}
fname := os.Args[1]
diff --git a/ui/output_tab.go b/ui/output_tab.go
index 1ab771845b2e8ded1201406a66a2fb6a5c35724f..b0349eb0d68adf54a8376ffef7fec8c593a24393 100644
--- a/ui/output_tab.go
+++ b/ui/output_tab.go
@@ -24,21 +24,6 @@ import (
"fyne.io/fyne/v2/widget"
)
-// We have a channel that sends the status to the output tab.
-type status uint8
-
-const (
- calculating status = iota // currently running a simulation
- resultsReady // You should collect the results
- errorCalc // You should display an error message
-)
-
-type workstatus struct {
- fdata, xdata []byte // the data in a function or X value plot
- err error
- status status // Tells us what we should do now
-}
-
// If we get a message with an error, display it
func showErrTab(cntr *fyne.Container, err error) {
cntr.Objects = nil
@@ -84,9 +69,13 @@ func innerWrite(d []byte, parent fyne.Window) {
var leftText = `Stretch window and play with the divider to make plots bigger.
Clicking on a button below will let one save the plot of the cost function or the
actual X values given to the function`
-type spacer struct { widget.Separator }
-func (spacer) Hide () {}
-func (spacer) MinSize () fyne.Size{ return fyne.Size{Width:1, Height:2}}
+
+// This spacer is the simplest way to stick a bit of room in the stucture
+// below. We cheat a bit in that the Hide() is just a noop.
+type spacer struct{widget.Separator }
+
+func (spacer) Hide() {}
+func (spacer) MinSize() fyne.Size { return fyne.Size{Width: 1, Height: 2} }
// leftbar sets up the buttons on the left
func leftbar(win fyne.Window, fdata, xdata []byte) *fyne.Container {
@@ -98,8 +87,8 @@ func leftbar(win fyne.Window, fdata, xdata []byte) *fyne.Container {
infobox := widget.NewLabel(leftText)
infobox.Alignment = fyne.TextAlignLeading
infobox.Wrapping = fyne.TextWrapWord
- s:= &spacer{}
- return container.NewVBox(infobox, s, fdataBtn, s,xdataBtn)
+ s := &spacer{}
+ return container.NewVBox(infobox, s, fdataBtn, s, xdataBtn)
}
// png2image takes the file data we have and puts it in a fyne image with
@@ -115,24 +104,25 @@ func png2image(d []byte, fname string) *canvas.Image {
// This allows us to make a layout for putting two plots on top of each other.
// The object resize()'s so that it fills the width and each object (plot)
// gets half of the vertical space. An rbox satisfies fyne's Layout interface.
-type rbox struct {}
+type rbox struct{}
// MinSize for an rbox... The width of the two plots, and height for two of them.
func (*rbox) MinSize(objects []fyne.CanvasObject) fyne.Size {
- w:= objects[0].MinSize().Width
- h:= objects[0].MinSize().Height
- return (fyne.NewSize(w, 2.0 *h))
+ w := objects[0].MinSize().Width
+ h := objects[0].MinSize().Height
+ return (fyne.NewSize(w, 2.0*h))
}
+
// Layout for an rbox. Put two objects on top of each other in a box that resizes.
func (*rbox) Layout(objects []fyne.CanvasObject, cntrSize fyne.Size) {
top := objects[0]
bottom := objects[1]
half := cntrSize.Height / 2.
sWant := fyne.Size{Width: cntrSize.Width, Height: half}
- top.Resize (sWant)
- bottom.Resize (sWant)
- top.Move (fyne.Position{0,0})
- bottom.Move (fyne.Position{0, half})
+ top.Resize(sWant)
+ bottom.Resize(sWant)
+ top.Move(fyne.Position{X: 0, Y: 0})
+ bottom.Move(fyne.Position{X: 0, Y: half})
}
// showResultsTab shows buttons on the left and two plots on the right
@@ -144,8 +134,8 @@ func showResultsTab(cntr *fyne.Container, win fyne.Window, fdata, xdata []byte)
left := leftbar(win, fdata, xdata)
split := container.NewHSplit(left, right)
- split.SetOffset (0.01)
- cntr.Add (split)
+ split.SetOffset(0.01)
+ cntr.Add(split)
}
// outputTab is run as a background process. After showing the initial
@@ -158,7 +148,7 @@ func outputTab(genParams genParams, cntr *fyne.Container, form *widget.Form) {
case calculating:
showCalcTab(cntr)
case resultsReady:
- showResultsTab(cntr, genParams.win, s.fdata, s.xdata)
+ showResultsTab(cntr, genParams.win, s.Fdata, s.Xdata)
form.Enable()
form.Refresh()
case errorCalc:
diff --git a/ui/ui_run.go b/ui/ui_run.go
index b1ea8a89d8a77bad5c4435d36cad9dd9709c1f15..dfa4be54f1931d7993d1969cf757ef1bdaf8b9b4 100644
--- a/ui/ui_run.go
+++ b/ui/ui_run.go
@@ -22,6 +22,22 @@ type genParams struct{
chn chan workstatus // To tell the output tab current status
}
+// We have a channel that sends the status to the output tab.
+type status uint8
+
+const (
+ calculating status = iota // currently running a simulation
+ resultsReady // You should collect the results
+ errorCalc // You should display an error message
+)
+
+type workstatus struct {
+ mcwork.MCresult
+// fdata, xdata []byte // the data in a function or X value plot
+ err error
+ status status // Tells us what we should do now
+}
+
// UiDoRun sets up the screen to do a run. It is effectively a big
// wrapper around the DoRun() function.
func UiDoRun(mcPrm *mcwork.McPrm) error {