I am writing a package featuring several functions which depend on a large number of parameters. I'm trying to use Options
so that I can define default values for these parameters and only specify parameters in function calls when the parameters differ from the default values. However, there is some interdependence among the parameters (the value of some parameters depends on the values of other parameters). I'm currently doing something like this:
BeginPackage["MyModel`"];
Unprotect["MyModel`*"];
Begin["`Private`"];
Options[MyModel]=
{
param1->someDefaultValue,
param2->someOtherDefaultValue,
param3:>OptionValue[MyModel,param1]*OptionValue[MyModel,param2];
};
(* define my functions for the model *)
End[];
Protect["MyModel`*"];
EndPackage[];
When I load the package into a notebook and examine the value of param3, it evaluates and gives the correct answer in numerical form.
<< MyModel`
result1 = OptionValue[MyModel,param3];
If I change the value of one of the options that param3 depends upon and reevaluate param3, the result changes as expected (result1 != result2).
SetOptions[MyModel,param1->aNewValue];
result2 = OptionValue[MyModel,param3];
What I want to do is allow a set of fundamental parameters to be changed (param1, param2), but write protect derived parameters (param3) so that the user cannot inadvertently change them (violating the relationships between the parameters).
With the code as is, if I run
SetOptions[MyModel,param3->1234];
Mathematica will allow me to clobber the original value of param3. I would like to let the user get the value of param3, but I want to prohibit them from setting it. How can this be done?
Update:
Perhaps some additional background would help explain what I'm trying to accomplish. All of the options for MyModel were originally defined as variables:
param1 = 2.034;
param2 = 5.258;
param3 = param1*param2;
These variables were treated as constants and used in several other functions:
f[x_,v_,q_]:=param1*x^2+(param3-param2*q)/v;
g[l_,m_,z_,y_,r_]:=param3*Sin[l*m]+param2*(z-y+r);
etc., etc.
Initially, I was only varying a limited number of parameters, which were passed in as arguments to the functions (such as x
, v
, q
, l
, m
, z
, y
, and r
in the example above). Now, I want to do Monte Carlo simulations, sensitivity analysis, etc. on the system defined by those functions. Because of this, I will be varying more parameters, including many of the ones that I'd originally defined as simple variables like param1
, param2
, and param3
.
Faced with the prospect of greatly expanding the number of input arguments for my functions, I went looking for another way of doing it and thought Mathematica's Options
would be a good solution.
Instead of having a bunch of functions with complicated call signatures featuring more than 50 input parameters in many cases, I'd instead have a default set of Options
for the model and pass in only those options that differ from the default values.
So, the function definitions become something like:
f[x_,v_,q_,OptionsPattern[MyModel]]:=OptionValue[param1]*x^2+(OptionValue[param3]-OptionValue[param2]*q)/v;
g[l_,m_,z_,y_,r_,OptionsPattern[MyModel]]:=OptionValue[param3]*Sin[l*m]+OptionValue[param2]*(z-y+r);
Instead of:
f[x_,v_,q_,param1_,param2_,param3_]:=param1*x^2+(param3-param2*q)/v;
g[l_,m_,z_,y_,r_,param2_,param3_]:=param3*Sin[l*m]+param2*(z-y+r);
Likewise, function invocation becomes something like:
f[2.0, 1.1, 9.2] (* gives the same result as the expression below because default values are defined for the other parameters in Options[MyModel] *)
instead of:
f[2.0, 1.1, 9.2, 2.034, 5.258, 2.034*5.258]
It doesn't make a lot of difference in this explanatory example, but in the actual model this simplifies the signature for a typical function call from:
someFunction[param1, param2, param3, param4, param5, param6, ..., param52]
to:
someFunction[param6->someNonDefaultValue, param32->anotherNonDefaultValue]
param3
should be a variable, not an option. You can useProtect[]
to keep the user from inadvertently changing its value. You could also write a function to return its value. $\endgroup$