param()The
param()class, located inpizza.private.mstructis an essential low-level class for 🍕 Pizza³. It used as parent class for data containers used byscript,pipescript,dscript,scriptobject,forcefield,dforcefield. Its methods offer scripting capabilities between Pythonic and LAMMPS syntaxes.
The param class extends the struct class (located in the same module) and allows dynamic evaluation of expressions, implicit calculations, and NumPy-style operations. Instances of this class are iterable and can be managed using a Matlab-like syntax(*).
The syntax evolved between versions towards more flexibility and robustness. The capacity to perform calculations matrix/nd-operations is vital for building LAMMPS codelets/blocks with complex displacements and boundary conditions.
(*)note: Matlab inputs are also enabled as shorthands.
note: It is mandatory to import NumPy as np (internal convention) if NumPy arrays are defined in param text expressions.
The following snippet also shows how to check the current working directory (if needed)
x# assuming that cwd is Pizza3/ main folder# check it with :'''# control snippetimport oscurrent_dir = os.getcwd()print(current_dir)'''import numpy as npfrom pizza.private.mstruct import param, paramauto # paramauto is used in one example
def prettyprint(var, value): """Display the variable's name, its value, and its type after evaluation.""" print(f"{var} = {value} (type: {type(value).__name__})")note: If your notebook is showing an empty figure above, it is normal at at the initialization of Pizza. The code is testing the graphical capabilities.
paramandparamautoare sibling classes with similar features, offering MATLAB-like syntax, variable interpolation, and mathematical evaluation. Additionally,paramautoimplements an internal mechanism to reorder expressions into a feasible execution sequence. This feature allows users to define expressions before their inputs or linked expressions, regardless of their order of definition. Such functionality is handy in multiscale modeling, where physical properties, discretization, and simulation parameters are interdependent. As a result, rescaling or imposing a physical property does not require rewriting the corresponding 🍕 Pizza³ template.For conciseness, this document focuses on the
paramclass. The same syntax applies toparamauto, with the only difference being the instance initialization:p = paramauto()instead ofp = param().
✍️ The param() class stores values and expressions as fields/attributes. Variables are referenced using the syntax ${var}. For example, if an instance is created as p = param(var=value, ...), then:
p.var retrieves the value of ${var}.
p.var = value assigns or updates the value.
p("var") returns the evaluated value of ${var} in the current context.
🗑️ To delete a variable, use either:
p.var = []
del(p, "var")
param Expressions 🟰 param expressions are stored as strings. They can represent either mathematical expressions or template strings. Unlike Python’s built-in eval(), the evaluation result depends on the context—returning either a numerical value or a processed string.
📏 Matrix operations are supported using @{matrix} instead of ${matrix}.
➗ Valid expression components:
Operators: +, -, *, /, **, @, .T
Built-in functions: sum, prod, min, max
Mathematical functions: sin, cos, log, pi
NumPy functions: Prefixed with np.
Some statistical functions
🧮 Interpolation (substitution) and 🚀 evaluation occur in this order:
1️⃣ Direct interpolation/substitution
"The content of var is ${var}"
note: Only fully evaluated variable can be accessed.
2️⃣ Local evaluation with a text result
"The sum of variables ${var1 + var2}"
"The third value is ${var[2]}"
"The sum is ${sum(var)}"
3️⃣ Full evaluation with a numeric result
"${var}", "@{vector}.T", "@{matrix1} @ @{matrix2}"
4️⃣ Mixed evaluation in a list
["var=${myvar}", "sum=${mylist}", "@{matrix1} @ @{matrix2}"]
🤔 If a full evaluation is not feasible, the result is stored with 4 significant digits by default (configurable).
❌ Errors during evaluation return an error message. For example, accessing a variable that has not been evaluated will raise an error.
🚨 Enable debug messages on error evaluation with:
xxxxxxxxxxp = param(debug=True)🔄 Alternative Syntax:
For simple variable substitutions, Pythonic {variable} notation is also supported alongside ${variable} for more flexible evaluation.
🔁 Nested vs. forced Evaluation:
Nested evaluation is implemented. 🌀 The best interpolation/local/global/evaluation scenario will be followed according to the context.
🔧 Full evaluation can be forced by prefixing the param expression with a ❗ like var = "! ...".
param Text Expressions 🔢 Variables can be stored as strings ("1.0") or numbers (1.0). Scalars and complex numbers are supported.
📐 Defining matrices & arrays using different param notations:
Matlab-style: $[1 2 3; 4 5 6]
NumPy-style: $[[1,2,3],[4,5,6]]
Hybrid notation: $[[1 2 3; 4 5 6],[7 8 9; 10 11 12]]
Range expansions: "$[1:10]" or "$[1:0.5:10]"
⚠️ Evaluation Order
Variables are evaluated sequentially.
If dependency resolution is required, use paramauto() instead.
Unlike Python f-strings, modifying one variable updates all dependent expressions.
🔄 Convert a dynamic param instance to a static structure with:
xxxxxxxxxxs = p.eval() # or equivalently s = p()or equivalently
xxxxxxxxxxs = p()Variables can be specified
xxxxxxxxxxsubs = p("var1","var2",...)🤝 param instances behave like lists or collections:
p[5] → Returns the 6th element of p.
p[[5]] → Returns a substructure with the 6th element.
p[1:10:2] or p[[0,3,8]] → Returns a substructure for the specified indices.
✅ Auto-assigning Undefined Variables
If ${var} appears in an expression but isn’t defined, assign it automatically as:
xxxxxxxxxxp.var = "${var}" # Placeholder until assigned a real valueUse p.check() to validate all variable assignments.
📦 Batch updating variables within a param instance:
xxxxxxxxxxp.update(var1=value1, var2="expression2", ...)or via dictionary:
xxxxxxxxxxp.update(**d) # where d["var"] = value or "expression"🔗 Merging multiple param instances using the + operator:
xxxxxxxxxxpmerged = poriginal + pupdate➡️ Convert param instances (p) to various formats:
| Conversion | Method |
|---|---|
param ➡️ Static struct (non-evaluated) | s = p.tostatic() |
param ➡️ Evaluated struct | se = p.tostruct() or se = p() |
param ➡️ Dictionary | d = p.todict() |
param ➡️ paramauto | pa = p.paramauto() or pa = paramauto(**p) |
struct ➡️ param | p = s.struct2param() |
struct ➡️ Dictionary | d = s.struct2dict() |
dict ➡️ struct | s = struct(**d) |
dict ➡️ param | p = param(**d) |
dict ➡️ paramauto | pa = paramauto(**d) |
💾 Save and load param instances:
📥 Save to disk
xxxxxxxxxxp.write(filename)📤 Load from disk
xxxxxxxxxxp = struct.read(filename).toparam()Basic syntax: Create an instance with p = param() and then define variables as:
xxxxxxxxxxp.var = valuep.var = "value"p.var = "expression"
You can also initialize variables directly: p = param(var1=..., var2=...).
Accessing a variable: p.var or getattr(p, "var") returns the raw value of ${var}.
To obtain a static structure, use s = p() or s = p.eval().
Evaluate specific variables with p("var1", "var2", ...).
Prefix a string with $ to designate it as a literal (i.e., not an expression).
For debugging evaluation issues, use p = param(debug=True).
Avoid using a variable named ${e} to prevent confusion with exp(1).
For legacy support, literal expressions can be defined either by:
Adding the prefix $ to the expression (e.g., "$ab"), or
Placing the expression inside a list (e.g., ["ab"]).
note: The latest versions of param() can automatically detect literals that cannot be evaluated.
This example demonstrates how to use literal expressions with param():
line1: A raw string that escapes ${a} to prevent substitution.
line2: A list of strings.
line3: A string that interpolates a value from line2.
ab: A variable holding the literal "AB".
line4: A literal expression where the $ prefix preserves the literal value of ab.
line5: A plain string "ab".
line6: A string "sin(x)" that will not generate an error.
line7: An expression "${sin(x)}" which will generate an error since x is not defined.
The evaluated static structure is obtained by calling l().
xxxxxxxxxxl = param()l.line1 = r"\${a}+1" # escape `${a}` to prevent its substitutionl.line2 = ["a","b"]l.line3 = 'The first letter in ${line2} is "${line2[0]}"'l.ab = "AB"l.line4 = "$ab"l.line5 = "ab"l.line6 = "sin(x)" # it will not generate an errorl.line7 = "${sin(x)}" # it will generate an error since x is not definedprint('The values of l:')print(repr(l))print('\nthe static content of l')s = l() # equivalent to s = p.eval()sxxxxxxxxxxThe values of l:-------------:----------------------------------------line1: \${a}+1= ${a}+1line2: ['a', 'b']= ['a', 'b']line3: The first letter in [...] e2} is "${line2[0]}"= The first letter in ['a', 'b'] is "a"ab: AB= ABline4: $ab= abline5: ab= abline6: sin(x)= sin(x)line7: ${sin(x)}= <Error: Variable or function 'x' is not defined>-------------:----------------------------------------parameter list (param object) with 8 definitionsthe static content of l-------------:----------------------------------------line1: ${a}+1line2: ['a', 'b']line3: The first letter in ['a', 'b'] is "a"ab: ABline4: abline5: abline6: sin(x)line7: <Error: Variable or [...] 'x' is not defined>-------------:----------------------------------------
xxxxxxxxxxstructure (struct object) with 8 fields
paramauto altenative and variable reorderingThe missing parameter x can be supplied :
by another param instance param(x=np.pi/4) and combined with the previous instance via the operator + (solution 1);
by using a paramauto instance l_auto capable of reordering automatically fields at runtime (solution 2);
by reordering directly the variables in l (solution 3)
+xxxxxxxxxxlfixed = param(x=np.pi/4) + l # the missing parameter must precede the definition of l (prepend)lfixedxxxxxxxxxx-------------:----------------------------------------x: 0.7853981633974483line1: \${a}+1= ${a}+1line2: ['a', 'b']= ['a', 'b']line3: The first letter in [...] e2} is "${line2[0]}"= The first letter in ['a', 'b'] is "a"ab: AB= ABline4: $ab= abline5: ab= abline6: sin(x)= sin(x)line7: ${sin(x)}= 0.7071067811865475-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 9 definitions
l and l can be converted to a paramauto instance. The instance paramauto shows eventually order errors, but it tries to reorder the fields at runtime to remove errors.xxxxxxxxxxl.x = np.pi/4 # l is addedl_auto = l.toparamauto() ## note that the syntax **l is required to zip all variablesl_autoxxxxxxxxxxWARNING: unable to interpret 3/9 expressions in "definitions"-------------:----------------------------------------line1: \${a}+1= ${a}+1line2: ['a', 'b']line3: The first letter in [...] e2} is "${line2[0]}"= The first letter in ['a', 'b'] is "a"ab: AB= ABline4: $ab= abline5: ab= abline6: sin(x)= sin(x)line7: ${sin(x)}= <Error: Variable or [...] 'x' is not defined>x: 0.7853981633974483-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 9 definitions
+.xxxxxxxxxxlreordered = l[-1:] + l[:-1] # x has been appended at the previous steplreorderedxxxxxxxxxx-------------:----------------------------------------x: 0.7853981633974483line1: \${a}+1= ${a}+1line2: ['a', 'b']= ['a', 'b']line3: The first letter in [...] e2} is "${line2[0]}"= The first letter in ['a', 'b'] is "a"ab: AB= ABline4: $ab= abline5: ab= abline6: sin(x)= sin(x)line7: ${sin(x)}= 0.7071067811865475-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 9 definitions
param and struct instances can be indexed with lists [idx1,idx2,key1,key2...]:with integers (0 being the first value, -1 the last one, -2 the one before the last...)
xxxxxxxxxxl[[-1,7]]xxxxxxxxxx-------------:----------------------------------------x: 0.7853981633974483line7: ${sin(x)}= 0.7071067811865475-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 2 definitions
with a list of keys/names
xxxxxxxxxxl[["x","line7"]]xxxxxxxxxx-------------:----------------------------------------x: 0.7853981633974483line7: ${sin(x)}= 0.7071067811865475-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 2 definitions
with a hybrid list mixing integers and key names
xxxxxxxxxxl[["x",-2]]xxxxxxxxxx-------------:----------------------------------------x: 0.7853981633974483line7: ${sin(x)}= 0.7071067811865475-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 2 definitions
This example demonstrates basic numeric assignments:
p.a is assigned the float 10.0.
p.b is assigned the string "10", representing the number 10.
p.c is assigned a literal string "$10" (thus it is not interpreted as a number).
p.d is defined as a Python list of numbers.
p.f is created by converting p.d into a NumPy array (as a row vector).
xxxxxxxxxxp = param() # initialize param. Note that can use also `p = param(a=..., b=...)`p.a = 10.0 # number 10 as floatp.b = "10" # number 10 stored as a stringp.c = "$10" # characters "1" and "0" (not a number)p.d = [1.0, 0.2, 0.03, 0.004] # Python listp.f = np.array([p.d]) # Converts the list d into a row vectorpxxxxxxxxxx-------------:----------------------------------------a: 10.0b: 10= 10c: $10= 10d: [1.0, 0.2, 0.03, 0.004]= [1.0, 0.2, 0.03, 0.004]f: [1 0.2 0.03 0.004] (double)-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 5 definitions
This section demonstrates the interpolation and local evaluation capabilities:
Simple interpolation/substitution: ${var} is replaced by its content.
Mathematical expressions: Expressions within ${} are evaluated in place.
Local evaluation: Supports scalars, lists, NumPy arrays, and expressions.
Indexing: Use ${var[i]} or ${var[i,j]} to index into arrays or matrices.
Indexing: Use ${var[key]} to index dictionaries (do not quote key).
Escaping: Use \${...} to prevent execution of the interpolation.
✅ Supported Operations
Indexing of lists, dicts, and arrays.
Mathematical operations using operators like +, -, *, /.**
✅ Supported Mathematical Functions
Built-in functions: abs, round, min, max, sum, divmod.
Functions from the math module such as pi, e, nan, inf.
NumPy functions (with the np. prefix) and operators such as @ and .T.
Statistics functions: gauss, uniform, randint, choice.
The following examples show scalar evaluations:
p.g evaluates an expression that retrieves d[1] and adds b.
p.h evaluates an expression combining an element from the NumPy array f and an element from d.
p.i demonstrates that the notation ${d}[1] + ${b} is equivalent to a global evaluation.
p.j uses a similar pattern for matrix operations but mixing outer indexing is not recommended.
note: ` It is recommended not to mix global and local expressions (especially for indexing with NumPy arrays).
xxxxxxxxxxp.g = "${d[1]}+${b}" # Retrieves `a[1]` = 0.2 and add 10 `0.2 + 10`p.h = "${f[0,1]} + ${d[0]}" # Evaluates as `0.2 + 1.0`p.i = "${d}[1]+${b}" # This notation also works but via global evaluation (equivalent to c for the part `${a}[1]`) `0.2 + 10`p.j = "${f}[0,1] + ${d}[0]" # However, it should be avoided with implicit NumPy arrays (see below)# à la Matlab practice, type the variable to see its contentp # alternatively use repr(p)xxxxxxxxxx-------------:----------------------------------------a: 10.0b: 10= 10c: $10= 10d: [1.0, 0.2, 0.03, 0.004]= [1.0, 0.2, 0.03, 0.004]f: [1 0.2 0.03 0.004] (double)g: ${d[1]}+${b}= 10.2h: ${f[0,1]} + ${d[0]}= 1.2i: ${d}[1]+${b}= 10.2j: ${f}[0,1] + ${d}[0]= [[1.0,0.2,0.03,0.004 [...] 0.2, 0.03, 0.004][0]-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 9 definitions
Evaluation and Display of Scalar Evaluations
The following code evaluates all expressions (using p()) and displays:
The equivalence between inner and outer indexing for lists.
The differences for NumPy arrays, where only the first value (h) is numeric.
A warning to avoid using outer indexing outside of ${...}.
xxxxxxxxxx# evaluate all expressions and store them in ss = p() # equivalent to s = p.eval() # c and e are equivalentprint("Inner and outer indexing are similar for list")repr(p("g","i")) # show the evaluation of c and eprint('All values are numeric (float)')prettyprint("g",s.g)prettyprint("i",s.i)# d and f are not equivalentprint("\n","Inner and outer indexing are not similar for NumPy arrays")repr(p("h","j")) # show the evaluation of d and fprint("only the first value (h) is numeric")prettyprint("h",s.h)prettyprint("j",s.j)print('avoid using outer indexing and keep it within "{}"')xxxxxxxxxxInner and outer indexing are similar for list-------------:----------------------------------------g: 10.2i: 10.2-------------:----------------------------------------All values are numeric (float)g = 10.2 (type: float)i = 10.2 (type: float)Inner and outer indexing are not similar for NumPy arrays-------------:----------------------------------------h: 1.2j: [[1.0,0.2,0.03,0.004 [...] 0.2, 0.03, 0.004][0]-------------:----------------------------------------only the first value (h) is numerich = 1.2 (type: float)j = [[1.0,0.2,0.03,0.004]][0,1] + [1.0, 0.2, 0.03, 0.004][0] (type: str)avoid using outer indexing and keep it within "{}"
Nested interpolation enables the use of a variable as an index or key:
${list[${idx}]} with ${idx} a variable coding for a scalar index (for example 1 or "1") of a list.
${dict["${key}"]} with ${key} a string coding for a key value of a `dict
note: Nested interpolation is not enabled for NumPy arrays defined in param text expressions. Tuples can be indexed
The following examples show the principles:
i.a is a list (not a vector).
i.b is an index of a defined as int (integer)
i.c returns the value for the next index b+1; the shift is done before interpolation.
i.d returns the same value with the shift applied after interpolation.
note: e is not used as a key as it can be confused with exp(1)
i.f defines a dict (dictionary) container
i.g is a key of i.f
i.h operates an operation *100 on the entry of f matching g; *note that quotes (here '${g}') are mandatory.
xxxxxxxxxxi = param()i.a = [1,2,3]i.b = 1i.c = "${a[${b+1}]}"i.d = "${a[${b}+1]}" # as c with the increment performed outside the expression i.f = {"A":1, "B":2, "C":3}i.g = "C"i.h ="${f['${g}']*100}"ixxxxxxxxxx-------------:----------------------------------------a: [1, 2, 3]= [1, 2, 3]b: 1c: ${a[${b+1}]}= 3d: ${a[${b}+1]}= 3f: {'A': 1, 'B': 2, 'C': 3}g: C= Ch: ${f['${g}']*100}= 300-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 7 definitions
note: Lists and dictionaries defined in param text expressions can be also indexed.
These features are exemplified by replacing Python expressions with text ones.
xxxxxxxxxxi.a = "[10,20,30,40]" # previous values are multiplied by (without $, it is a list)i.b = "2" # index +1i.f = '{"A":100, "B":200, "C":300}' # previous values are multiplied by 100ixxxxxxxxxx-------------:----------------------------------------a: [10,20,30,40]= [10, 20, 30, 40]b: 2= 2c: ${a[${b+1}]}= 40d: ${a[${b}+1]}= 40f: {"A":100, "B":200, "C":300}= {'A': 100, 'B': 200, 'C': 300}g: C= Ch: ${f['${g}']*100}= 30000-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 7 definitions
This section demonstrates that variables can hold multiple values and that results are stored in lists:
note: The special character ! can be placed in front of expressions using lists as results (e.g., "!["${myvar}",${sum(myvar)+offset}]" to force recursive execution if it is not guessed internally.
param Text Example
In the following example, q.units is a literal string (with the $ prefix).
q.a is a list containing a literal string and another literal.
q.b uses interpolation to reference units.
q.c shows a string with interpolation and an escaped placeholder.
xxxxxxxxxxq = param()q.units = "$si" # literal string (no interpolation)q.a = ["units","$lj"] q.b = ["units","${units}"]q.c = "the ${a[0]} are ${units} as defined with \\${units}"qxxxxxxxxxx-------------:----------------------------------------units: $si= sia: ['units', '$lj']= ['units', 'lj']b: ['units', '${units}']= ['units', 'si']c: the ${a[0]} are ${un [...] fined with \${units}= the units are si as [...] efined with ${units}-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 4 definitions
Text/Numeric Evaluation Example This example mixes text and numeric evaluations:
r.a is a numeric list.
r.b is provided as a string that represents a list with param expressions.
r.c uses the ! prefix to force recursive evaluation of expressions in lists.
r.d and r.e combine expressions from other list entries.
r.f is a list containing a mixture of expressions and literal values.
xxxxxxxxxxr = param()r.a = [0,1,2] # this list is numeric and is already in Pythonr.b = '[1,2,"test","${a[1]}"]' # this list combines param expressionsr.c = '![1,2,"test","${a[1]}"]' # the `!` to force recursive evaluation of expressions in listsr.d = "${b[3]}*10" # the expressions can be combined togetherr.e = "${c[3]}*10" # the expressions can be combined togetherr.f = ["${a[1]+a[2]}*3", 1,2,"test","${a[1]}", "${a[1]+a[2]}", "${1+2}", "b"]rxxxxxxxxxx-------------:----------------------------------------a: [0, 1, 2]= [0, 1, 2]b: [1,2,"test","${a[1]}"]= [1, 2, 'test', '1']c: ![1,2,"test","${a[1]}"]= [1, 2, 'test', 1]d: ${b[3]}*10= 10e: ${c[3]}*10= 10f: ['${a[1]+a[2]}*3', 1 [...] 2]}', '${1+2}', 'b']= [9, 1, 2, 'test', 1, 3, 3, 'b']-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 6 definitions
This example defines a param instance t with parameters o and p. Then:
t.a is constructed as a list containing ${o} and ${p}.
t.b computes the sum of the elements in a.
t.c calculates the maximum surface area using pi and the maximum value in a.
xxxxxxxxxxt = param(o=10,p=100)t.a = "[${o},${p}]"t.b = "the sum of a is ${sum(a)}"t.c = "the maximum surface area is ${pi*max(a)**2}"txxxxxxxxxx-------------:----------------------------------------o: 10p: 100a: [${o},${p}]= [10, 100]b: the sum of a is ${sum(a)}= the sum of a is 110c: the maximum surface [...] a is ${pi*max(a)**2}= the maximum surface [...] s 31415.926535897932-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 5 definitions
dict (dictionnaries)By design, instances of struct (and, by extension, param()) are intended to serve as flexible containers that can
hold any type of data—including class instances. However, evaluating advanced types, such as nested lists or dictionaries,
is more challenging. At this stage, only minimal support is provided for these advanced types in param().
note: Dictionary fields can be defined either as native Python dictionaries or as strings representing dictionaries. One limitation is that nesting strings for key names (i.e., defining keys as strings within string representations) remains an open issue. This is because, according to PEP 3101 (the guidelines for Python's advanced string formatting), quoted keys are not accepted in formatted strings. Consequently, a compromise approach is currently implemented.
Local evaluation/interpolation within ${} follows PEP 3101: no quotes.
Global evaluation outside ${} uses conventional Pythonic syntax with quotes ' or "
A representation (global) of a dict d can be achieved outside local evaluation/interpolation with ${d} and {d}
param()d.a is directly assigned a dictionary.
d.b is assigned a string that represents a dictionary.
d.c is assigned an expression referencing b.
d.d is assigned an expression that uses dictionary indexing.
d.f is assigned an expression that indexes a dictionary and performs an arithmetic operation.
note: e is not used as a key as it can be confused with exp(1)
d.g sets a dict using local interpolation/evaluation (PEP 3101 syntax).
d.h same definition using a global evaluation (conventional Pythonic syntax).
d.i global representation of h using ${h}, no possibility of interpolation
d.j idem using the Pythonic shorthand {h}, no possibility of interpolation
note: The definition of a dict within a param expression `${}' imposes fields to be used without quotes (adherence to PEP 3101)
xxxxxxxxxxd = param()d.a = {'a': 'a', 'b': 2}d.b = "{'a': 'a', 'b': 2}"d.c = "${b}"d.d = "${a[a]}"d.f = "${c[b]}+1"d.g = "${{bcopy: ${c[b]}, fcopy: ${f}}}" # syntax within ${}, PEP 3101 holds (no quote) - local evaluationd.h = "{'bcopy': ${c['b']}, 'fcopy': ${f}}" # syntax outside ${} using global evaluationd.i = "the value of h is: ${h}" # ${h} is used outside any evaluation/interpolation regiond.j = "the value of h is: {h}" # dxxxxxxxxxx-------------:----------------------------------------a: {'a': 'a', 'b': 2}b: {'a': 'a', 'b': 2}= {'a': 'a', 'b': 2}c: ${b}= {'a': 'a', 'b': 2}d: ${a[a]}= af: ${c[b]}+1= 3g: ${{bcopy: ${c[b]}, fcopy: ${f}}}= {bcopy: 2, fcopy: 3}h: {'bcopy': ${c['b']}, 'fcopy': ${f}}= {'bcopy': 2, 'fcopy': 3}i: the value of h is: ${h}= the value of h is: { [...] opy': 2, 'fcopy': 3}j: the value of h is: {h}= the value of h is: { [...] opy': 2, 'fcopy': 3}-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 9 definitions
Lists cannot be directly used as vectors and must be converted into NumPy arrays before performing vectorized operations.
Note:This section separate non-mathematical syntaxes leading to list instances from mathematical ones generating NumPy instances.
Numeric lists and lists of strings are non-mathematical containers. They accept à la Matlab and Pythonic shorthands for rapid prototyping and definitions. They cannot be used directly in NumPy operations, and only their scalar values can be used.
These syntaxes are used without $[] and operates only with a minimum of interpolation. Their use is limited to simple expressions and constants (float, int, str):
start:stop and start:step:stop expands a list between start and stop values with a step step (default value = 1).
[a b; c d; e f] embeds lists row-wise [[a,b],[c,d],[e,f]], the result is not a NumPy object.
the operator * repeats a string or lists element-wise
the lists can be indexed with int, including with negative integers (e.g., -1 represents the last value, etc.)
the list content can be included in a string with {list} without using $
The following example illustrates rapid syntaxes applicable to lists
u.a defines the list [1,2,3,4,5] using a matlab shorthand 1:5
u.b expands a list similarly using variables start, step and stop
u.c defines explicitly a list combining values and a[2]
u.d generates a nested list including numbers exp(1) and pi
u.f repeats "~" f_repetitions times
u.g repeats ["p"] g_repetitions times
u.h extracts the last sublist of d
u.i embeds the value of h in a string
xxxxxxxxxxu = param()u.a = "1:5"u.start = "0"u.step = "10"u.stop = "50"u.b = "${start}:${step}:${stop}"u.c = "[1,30,500,${a[2]}]"u.d = "[1 e; 3 pi; 4 5.0]"u.f_repetitions = "20"u.f = "'~'*${f_repetitions}"u.g_repetitions = "3"u.g = "['p']*${g_repetitions}"u.h = "${d[-1]}"u.i = "the values of h are {h}"uxxxxxxxxxx-------------:----------------------------------------a: 1:5= [1, 2, 3, 4, 5]start: 0= 0step: 10= 10stop: 50= 50b: ${start}:${step}:${stop}= [0, 10, 20, 30, 40, 50]c: [1,30,500,${a[2]}]= [1, 30, 500, 3]d: [1 e; 3 pi; 4 5.0]= [[1, 2.7182818284590 [...] 53589793], [4, 5.0]]f_repetitions: 20= 20f: '~'*${f_repetitions}= ~~~~~~~~~~~~~~~~~~~~g_repetitions: 3= 3g: ['p']*${g_repetitions}= ['p', 'p', 'p']h: ${d[-1]}= [4, 5.0]i: the values of h are {h}= the values of h are [4, 5.0]-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 13 definitions
The param() class offers several shorthands to seamlessly manipulate NumPy arrays using param text expressions:
1D: $[1 2 3] → np.atleast_2d(np.array([1,2,3]))
2D: $[[1 2],[3 4]] → np.array([[1,2],[3,4]])
3D: $[[[1 2],[3 4]],[[5 6],[7 8]]] → np.array([[[1,2],[3,4]],[[5,6],[7,8]]])
4D: $[[[[1 2]]]] → np.array([[[[1,2]]]])
Variable References:
@{var} is equivalent to np.atleast_2d(np.array(${var})).
Transpose:
Use @{var}.T to transpose.
Function Application:
Apply a function to a vector with: np.foo(@var).
Slicing:
${var[:,0]} converts a slice into a list.
@{var}[:,0] preserves the slice as a NumPy array.
Matlab Notations Supported:
Automatic row vector expansion using $[start:stop] or $[start:step:stop].
Spaces can be used to separate values row-wise.
Semicolons (;) separate rows.
Examples:
$[1, 2 ${var1} ; 4, 5 ${var2}] is equivalent to $[[1,2,${var1}],[4,5,${var2}]]
$[1;2; 3] becomes $[[1],[2],[3]]
[[-0.5, 0.5;-0.5, 0.5],[ -0.5, 0.5; -0.5, 0.5]] becomes $[[[-0.5,0.5],[-0.5,0.5]],[[-0.5,0.5],[-0.5,0.5]]]
$[[1,2;3,4],[5,6; 7,8]] becomes $[[[1,2],[3,4]],[[5,6],[7,8]]]
$[1, 2, 3; 4, 5, 6] becomes $[[1,2,3],[4,5,6]]
This example demonstrates simple definitions using Matlab-style notations:
e.a uses $[1:3] to create the vector [1, 2, 3].
e.b uses $[1;2;3] to create a column vector [[1],[2],[3]].
e.c uses $[0.1:0.1:0.9] to create the vector [0.1, 0.2, ..., 0.9].
e.d defines a 2D matrix with $[1 2 3; 4 5 6].
xxxxxxxxxxe = param()e.a = "$[1:3]" # Becomes `[1, 2, 3]`e.b = "$[1;2;3]" # Becomes `[[1];[2];[3]]`e.c = "$[0.1:0.1:0.9]" # `[0.1, 0.2, 0.3, ..., 0.9]`e.d = "$[1 2 3; 4 5 6]" # `[[1,2,3], [4,5,6]]`exxxxxxxxxx-------------:----------------------------------------a: $[1:3]= [1 2 3] (int64)b: $[1;2;3]= [1 2 3]T (int64)c: $[0.1:0.1:0.9]= [0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9] (double)d: $[1 2 3; 4 5 6]= [2×3 int64]-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 4 definitions
This example illustrates simple matrix operations:
m.a is a list of numeric values.
m.b is a NumPy array created from m.a (as a row vector).
m.c computes m.a * 2 (element-wise multiplication for a list).
m.d computes m.b * 2 (element-wise multiplication for a NumPy array).
m.e is the transpose of m.b.
m.f performs matrix multiplication between the transpose of m.b and m.b.
Variables m.g through m.o demonstrate various forms of expression evaluation, indexing, and string interpolation.
note: "@{j}+1" and "${j}+1" do not have the same meaning.
m.p uses a raw string (with the r prefix) to correctly escape ${a[0]}.
xxxxxxxxxx# Example with simple matrix operationsm=param()m.a = [1.0, .2, .03, .004]m.b = np.array([m.a])m.c = m.a*2m.d = m.b*2m.e = m.b.Tm.f = m.b.T@m.b # Matrix multiplication for (3x1) @ (1x3)m.g = "${a[1]}"m.h = "${b[0,1]} + ${a[0]}"m.i = "${f[0,1]}"m.j = "${f[:,1]}"m.k = "@{j}+1" # note that "@{j}+1" and "${j}+1" do not have the same meaningm.l = "${b.T}" # note that b is already a NumPy array (no need to call @(b).T, which works also)m.m = "${b.T @ b}" # evaluate fully the matrix operationm.n = "${b.T} @ ${b}" # concatenate two string-results separated by @m.o ="the result is: ${b[0,1]} + ${a[0]}"m.p = r"the value of \${a[0]} is ${a[0]}" # literal (r" ") is used because "\$" is not a valid escape sequence, use "\\$" alternativelymxxxxxxxxxx-------------:----------------------------------------a: [1.0, 0.2, 0.03, 0.004]= [1.0, 0.2, 0.03, 0.004]b: [1 0.2 0.03 0.004] (double)c: [1.0, 0.2, 0.03, 0.0 [...] 0, 0.2, 0.03, 0.004]= [1.0, 0.2, 0.03, 0.0 [...] 0, 0.2, 0.03, 0.004]d: [2 0.4 0.06 0.008] (double)e: [1 0.2 0.03 0.004]T (double)f: [4×4 double]g: ${a[1]}= 0.2h: ${b[0,1]} + ${a[0]}= 1.2i: ${f[0,1]}= 0.2j: ${f[:,1]}= [0.2, 0.040000000000 [...] 0001, 0.006, 0.0008]k: @{j}+1= [1.2 1.04 1.006 1.001] (double)l: ${b.T}= [[1. ][0.2 ][0.03 ][0.004]]m: ${b.T @ b}= [[1.0, 0.2, 0.03, 0. [...] , 0.00012, 1.6e-05]]n: ${b.T} @ ${b}= [[1. ][0.2 ][ [...] 0.2 0.03 0.004]]o: the result is: ${b[0,1]} + ${a[0]}= the result is: 0.2 + 1.0p: the value of \${a[0]} is ${a[0]}= the value of ${a[0]} is 1.0-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 16 definitions
This example demonstrates slicing operations:
s.a and s.b are scalar values.
s.c creates a NumPy vector from an operation.
s.n defines a vector using the $ syntax.
s.o1 creates a copy of n using the @{} notation.
s.o2 creates a NumPy vector directly.
s.o3 performs multiplication between two vectors.
s.d shows another multiplication example using a transpose.
s.f uses an explicit NumPy operation.
s.nT is the transpose of vector n.
s.m attempts an illegal operation (it will be kept as a string).
s.o shows the correct syntax for the operation.
s.p defines a 2D NumPy array.
s.q indexes the 2D array to retrieve an element.
s.r slices the 2D array, returning a list.
s.s applies an operation to the slice, preserving it as a NumPy array.
xxxxxxxxxxs = param(debug=True);s.a = 1.0s.b = "10.0"s.c = "$[${a},2,3]*${b}" # Create a Numpy vector from an operations.n = "$[0,0,1]" # another ones.o1 = "@{n}" # create a copys.o2 = "$[${a},2,3]" # create a Numpy vectors.o3 = "@{o1} @ @{o2}.T" # multiplication between two vectotss.d = "@{n}.T @ $[[${a},2,3]]" # another ones.f = "($[${a},2,3]*${b}) @ ns.array([[0,0,1]]).T" # another one using explicitly NumPys.nT = "@{n}.T" # transpose of a vector/matrixs.m = "${n.T}*2" # this operation is illegal and will be kept as a strings.o = "@{n}.T*2" # this one is the correct ones.p = "$[[1,2],[3,4]]" # Create a 2D Numpy arrays.q = "${p[1,1]}" # index a 2D NumPy arrays.r = "${p[:,1]}" # this is a valid syntax to get the slice as a lists.s = "@{p}[:,1]+1" # use this syntax if you need apply an operation to the slicesxxxxxxxxxx-------------:----------------------------------------a: 1.0b: 10.0= 10.0c: $[${a},2,3]*${b}= [10 20 30] (double)n: $[0,0,1]= [0 0 1] (int64)o1: @{n}= [0 0 1] (int64)o2: $[${a},2,3]= [1 2 3] (double)o3: @{o1} @ @{o2}.T= 3.0 (double)d: @{n}.T @ $[[${a},2,3]]= [3×3 double]f: ($[${a},2,3]*${b}) @ [...] s.array([[0,0,1]]).T= (np.atleast_2d(np.ar [...] s.array([[0,0,1]]).TnT: @{n}.T= [0 0 1]T (int64)m: ${n.T}*2= [[0][0][1]]*2o: @{n}.T*2= [0 0 2]T (int64)p: $[[1,2],[3,4]]= [2×2 int64]q: ${p[1,1]}= 4r: ${p[:,1]}= [2, 4]s: @{p}[:,1]+1= [3 5] (int64)-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 16 definitions
This advanced example demonstrates operations such as:
Defining a vector V1.
Computing V2 as V1 + 1.
Performing matrix multiplication between the transpose of V1 and V2.
Creating a diagonal matrix from the resulting product.
Calculating the eigenvalues and eigenvectors of the resulting matrix.
Displaying the first eigenvalue in a formatted string.
xxxxxxxxxxa = param(debug=True)a.V1 = "$[1.0,0.2,0.03]"a.V2 = "@{V1}+1"a.V3 = "@{V1}.T @ @{V2}"a.V4 = "np.diag(@{V3})"a.V5 = "np.linalg.eig(@{V3})"a.out = "the first eigenvalue is: ${V5.eigenvalues[0]}"axxxxxxxxxx-------------:----------------------------------------V1: $[1.0,0.2,0.03]= [1 0.2 0.03] (double)V2: @{V1}+1= [2 1.2 1.03] (double)V3: @{V1}.T @ @{V2}= [3×3 double]V4: np.diag(@{V3})= [2 0.24 0.0309] (double)V5: np.linalg.eig(@{V3})= EigResult(eigenvalue [...] 332, -0.06057363]]))out: the first eigenvalue [...] ${V5.eigenvalues[0]}= the first eigenvalue [...] s: 2.270900000000001-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 6 definitions
A global evaluation is attempted for all expressions after interpolation and local evaluations have been performed.
If the global evaluation does not raise any error, the evaluated result is kept; otherwise, the original interpolated
expression is preserved. Since several expressions involving matrix operations require global evaluation (i.e., outside
of ${...} or @{...}), it is recommended to define mathematically valid expressions and, if needed, use separate
variables to store results as text.
This example demonstrates global evaluation:
u.p creates a 2D NumPy array.
u.q indexes the array to retrieve an element.
u.r adds 1 to the second column of p.
u.s reshapes a slice and performs matrix multiplication in a Matlab-like manner.
u.t computes the eigenvalues and eigenvectors of the resulting matrix.
u.w calculates the sum of the first two eigenvalues.
u.x horizontally concatenates a literal with the sum of the eigenvalues.
xxxxxxxxxxu = param(debug=True)u.p = "$[[1, 2], [3, 4]]" # Create a 2D NumPy arrayu.q = "${p[1, 1]}" # Indexing: retrieves 4u.r = "@{p}[:,1] + 1" # Add 1 to the second columnu.s = "@{p}[:, 1].reshape(-1, 1) @ @{r}" # perform p(:,1)'*s in Matlab senseu.t = "np.linalg.eig(@{s})"u.w = "${t.eigenvalues[0]} + ${t.eigenvalues[1]}" # sum of eigen valuesu.x = "$[[0,${t.eigenvalues[0]}+${t.eigenvalues[1]}]]" # horizontal concat à la Matlabuxxxxxxxxxx-------------:----------------------------------------p: $[[1, 2], [3, 4]]= [2×2 int64]q: ${p[1, 1]}= 4r: @{p}[:,1] + 1= [3 5] (int64)s: @{p}[:, 1].reshape(-1, 1) @ @{r}= [2×2 int64]t: np.linalg.eig(@{s})= EigResult(eigenvalue [...] 576, -0.89442719]]))w: ${t.eigenvalues[0]} [...] ${t.eigenvalues[1]}= 26.0x: $[[0,${t.eigenvalues [...] {t.eigenvalues[1]}]]= [0 26] (double)-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 7 definitions
This example demonstrates various matrix operations:
A list l is defined.
Vectors and matrices (a, b, c) are created using Matlab-style notations.
Element-wise and matrix operations are performed.
More complex structures (x0, y0, z0) are defined using multiple operations.
Finally, the results are flattened into vectors X0, Y0, and Z0.
xxxxxxxxxxv = param()v.l = [1e-3, 2e-3, 3e-3] # l is defined as a listv.a = "$[1 2 3]" # a is defined with Matlab notationsv.b = "$[1:3]" # b is defined with Matlab notationsv.c = "$[0.1:0.1:0.9]" # c is defined with Matlab notationsv.scale = "@{l}*2*@{a}" # l is rescaledv.x0 = "$[[[-0.5, -0.5],[-0.5, -0.5]],[[ 0.5, 0.5],[ 0.5, 0.5]]]*${scale[0,0]}*${a[0,0]}"v.y0 = "$[[[-0.5, -0.5],[0.5, 0.5]],[[ -0.5, -0.5],[ 0.5, 0.5]]]*${scale[0,1]}*${a[0,1]}"v.z0 = "$[[-0.5 0.5 ;-0.5 0.5],[ -0.5, 0.5; -0.5, 0.5]]*${l[2]}*${a[0,2]}"v.X0 = "@{x0}.flatten()"v.Y0 = "@{y0}.flatten()"v.Z0 = "@{z0}.flatten()"vxxxxxxxxxx-------------:----------------------------------------l: [0.001, 0.002, 0.003]= [0.001, 0.002, 0.003]a: $[1 2 3]= [1 2 3] (int64)b: $[1:3]= [1 2 3] (int64)c: $[0.1:0.1:0.9]= [0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9] (double)scale: @{l}*2*@{a}= [0.002 0.008 0.018] (double)x0: $[[[-0.5, -0.5],[-0. [...] cale[0,0]}*${a[0,0]}= [[2×2 matrix] [2×2 matrix]] (2×2×2 double)y0: $[[[-0.5, -0.5],[0.5 [...] cale[0,1]}*${a[0,1]}= [[2×2 matrix] [2×2 matrix]] (2×2×2 double)z0: $[[-0.5 0.5 ;-0.5 0. [...] ]]*${l[2]}*${a[0,2]}= [[2×2 matrix] [2×2 matrix]] (2×2×2 double)X0: @{x0}.flatten()= [-0.001 -0.001 -0.001 -0.001 0.001 0.001 0.001 0.001] (double)Y0: @{y0}.flatten()= [-0.008 -0.008 0.008 0.008 -0.008 -0.008 0.008 0.008] (double)Z0: @{z0}.flatten()= [-0.0045 0.0045 -0.0045 0.0045 -0.0045 0.0045 -0.0045 0.0045] (double)-------------:----------------------------------------
xxxxxxxxxxparameter list (param object) with 11 definitions