Key goals:
- support one model per sheet
- provide a Google Apps Script library to allow automation by users
Problems with the current architecture:
- Addons cannot expose functions as a library, so we can't allow people to do automation. The solution to this is to provide a library to handle the most of the work, and use our addon as a GUI for the library. Note that we need to copy and paste the library code into the addon rather than referencing a library: reference
- This causes another problem: the way properties are handled. Currently, we run as an addon, which gives us access to storing document-specific properties, which means we can save details per-spreadsheet. Running as a library means we can only save properties per-library (only one set of properties for all users 👎) or per-user (meaning only the user that made the model can see it 👎). Thus we need to move away from properties.
- Another issue with properties is that the property store is not robust to changes in the spreadsheet. If a sheet is renamed, the corresponding property values will not be updated.
- We currently are only able to support one model
Architecture requirements
This means we need to solve the following problems:
- Store the model in a way that exposes the model identically to both addon and library users
- Store the model in a way that is robust to sheet name changes
- Store the model in a way that allows one model per sheet
- Come up with a way of switching the model in the sidebar based on the current sheet
Model Storage
A possibility is to use a storage system similar to Frontline's Addon. They create a hidden sheet __Solver__
that contains all model details for the whole document:
![image](https://cloud.githubusercontent.com/assets/4717044/8237141/3669a670-15bb-11e5-9af6-6d5798180040.png)
The models are stored one per column. All model details are saved with the full sheet prefix and as references. This means they are updated on sheet rename.
- Row 2 contains the objective is stored. One of
=Max(<obj>)
, =Min(<obj>)
or =<obj>=<target>
.
- Row 3 contains the decision vars
=<range>
- Row 4 seems to contain a hash corresponding to the selected solver?
- Row 5 seems to contain a hash of the model options?
- Row 6 seems to contain information about the constraints in the model (not sure what)
- Rows 7+ contain the constraints in the form
=<lhs> <rel> <rhs>
We could store in a similar format on an __OpenSolver__
sheet:
- Row 1: objective
- Row 2: variables
- Row 3: num constraints
- Rows 4 to (num constraints + 4): constraints
- rows (num constraints + 5) onwards: options (solver, linearity check, show progress)
We can use the variables to determine the sheet name (with the implicit constraint that each model is contained on a single sheet).
Changing sheets in the UI
The way that solver does this is from what I can understand, any time there is a click in the UI, they check whether the current sheet matches the sheet of the model that is showing, and if not, they reload the model.
We can do something similar, and to load a model we search through the columns of the hidden model sheet to find the one that references the current sheet.
Where to go from here
Adopting this approach similar to solver seems to resolve most of the problems. I'd like to discuss any thoughts on the best way to store the models, load them, and switch contexts in the GUI.