functioneer 0.2.1__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: functioneer
3
- Version: 0.2.1
4
- Summary: A library providing easy automated analysis for your functions.
3
+ Version: 0.3.0
4
+ Summary: Effortlessly explore function behavior with automated batch analysis.
5
5
  Author-email: Quinn Marsh <quinnmarsh@hotmail.com>
6
6
  Maintainer-email: Quinn Marsh <quinnmarsh@hotmail.com>
7
7
  License: MIT
@@ -9,8 +9,8 @@ Project-URL: Homepage, https://github.com/qthedoc/functioneer
9
9
  Project-URL: Issues, https://github.com/qthedoc/functioneer/issues
10
10
  Project-URL: Funding, https://donate.pypi.org
11
11
  Project-URL: Say Thanks!, http://quinnmarsh.com
12
- Keywords: functioneer,analysis,automation,autorun,trade space,digital twin
13
- Classifier: Development Status :: 3 - Alpha
12
+ Keywords: functioneer,analysis,batch run,automation,autorun,trade space,digital twin
13
+ Classifier: Development Status :: 4 - Beta
14
14
  Classifier: Intended Audience :: Science/Research
15
15
  Classifier: Topic :: Scientific/Engineering
16
16
  Classifier: License :: OSI Approved :: MIT License
@@ -27,13 +27,15 @@ License-File: LICENSE
27
27
  Requires-Dist: numpy>=1.18.5
28
28
  Requires-Dist: scipy>=1.5.2
29
29
  Requires-Dist: pandas>=1.0.5
30
+ Dynamic: license-file
30
31
 
31
32
  # Functioneer
32
33
 
33
34
  **Author**: Quinn Marsh
34
- **Date**: February 02, 2025
35
+ **Date**: February 02, 2025\
36
+ **PyPI**: https://pypi.org/project/functioneer/
35
37
 
36
- Functioneer is a Python package that automates the analysis of ANY function, enabling you to test and optimize with unlimited combinations of parameters. Whether you're performing parameter sweeps, sensitivity testing, or optimizing digital twins, Functioneer lets you queue up thousands or even millions of tests in seconds. Easily retrieve and analyze results in formats like pandas for seamless integration into your analysis workflows.
38
+ Functioneer lets you effortlessly explore function behavior with automated batch analysis. With just a few lines of code, you can queue up thousands or even millions of function evaluations, with various parameter combinations and/or optimizations. Retrieve structured results in formats like pandas for seamless integration into your workflows. Perfect for parameter sweeps, engineering simulations, and digital twin optimization.
37
39
 
38
40
  ## Use cases
39
41
 
@@ -43,9 +45,19 @@ Functioneer is a Python package that automates the analysis of ANY function, ena
43
45
 
44
46
  ## How Functioneer Works
45
47
 
46
- Functioneer is a powerful system for defining and executing complex analysis pipelines. At its core, the toolkit organizes analyses as pipelines, where a set of *parameters* flows sequentially through a series of *analysis steps*. These steps modify the parameters in various ways, such as defining new parameters, updating existing parameter values, or performing operations like function evaluation and optimization. One of the key features of functioneer is the ability to introduce *forks*, which split the analysis into multiple *branches*, each exploring different values for a specific parameter. This structured approach enables highly flexible and dynamic analyses, suitable for a wide range of applications.
48
+ At its core, functioneer organizes analyses as tree where a *set of parameters* starts at the trunk and moves out towards the leaves. Along the way, the *set of parameters* 'flows' through a series of *analysis steps* (each of which can be defined in a single line of code). Each *analysis step* can modify or use the parameters in various ways, such as defining new parameters, modifying parameters, or using the parameters to evaluate or even optimize any function of your choice. One key feature of functioneer is the ability to introduce *forks*: a type of analysis step that splits the analysis into multiple parallel *branches*, each exploring different values for a specific parameter. Using many *Forks* in series allows you to queue up thousands or even millions of parameter combinations with only a few lines of code. This structured approach enables highly flexible and dynamic analyses, suitable for a wide range of applications.
49
+
50
+ Summary of most useful types of *analysis steps*:
51
+ - Define: Adds a new parameter to the analysis
52
+ - Fork: Splits the analysis into multiple parallel *branches*, each exploring different values for a specific parameter
53
+ - Execute: Calls a provided function using the parameters
54
+ - Optimize: Quickly set up an optimization by providing a function and defining which parameters are going to be optimized
55
+
56
+ <details>
57
+ <summary>
58
+ <span style="font-size:1.5em;">Important Terms</span>
59
+ </summary>
47
60
 
48
- ### Terms
49
61
  * AnalysisModule
50
62
  * Definition: The central container for an analysis pipeline.
51
63
  * Function: Holds a sequence of analysis steps and manages a set of parameters that flow through the pipeline.
@@ -69,6 +81,7 @@ Functioneer is a powerful system for defining and executing complex analysis pip
69
81
  * Leaf
70
82
  * Definition: The endpoint of a branch after all analysis steps have been executed.
71
83
  * Function: Represents the final state of parameters for that branch. Each leaf corresponds to a specific combination of parameter values and results. When results are tabulated, each row corresponds to a leaf.
84
+ </details>
72
85
 
73
86
  ## Installation
74
87
 
@@ -81,17 +94,19 @@ pip install functioneer
81
94
  ## Getting Started
82
95
  Below are a few quick examples of how to use Functioneer. Each example will build on the last, introducing one piece of functionality. By the end you will have witnessed the computational power of this fully armed and fully operational library.
83
96
 
84
- ### Choosing a Function to Analyze
85
- Functioneer is designed to analyze ANY function(s) with ANY number of inputs and outputs. For the following examples, the [Rosenbrock Function](https://en.wikipedia.org/wiki/Rosenbrock_function) is used for its relative simplicity, 4 inputs (plenty to play with) and its historical significance as an optimization benchmark.
97
+ ### Choose a Function to Analyze
98
+ Functioneer is designed to analyze ANY function(s) with ANY number of inputs and outputs. For the following examples, we use the [Rosenbrock Function](https://en.wikipedia.org/wiki/Rosenbrock_function) for (1) its relative simplicity, (2) 4 inputs (plenty to play with) and (3) its historical significance as an optimization benchmark.
86
99
 
87
100
  ```
101
+ # Example Function
88
102
  # Rosenbrock function (known minimum of 0 at: x=1, y=1, a=1, b=100)
89
103
  def rosenbrock(x, y, a, b):
90
104
  return (a-x)**2 + b*(y-x**2)**2
91
105
  ```
92
106
 
93
107
  ### Example 1: The Basics (Defining Parameters and Executing a Function)
94
- Set up an *analysis sequence* by defining four parameters (the inputs needed for the Rosenbrock function), then executing the function (with parameter ids matched to kwargs)
108
+ Set up an *analysis sequence* by defining four parameters to match our function, then executing the function
109
+ Note: Parameter IDs MUST match your function's args, function executions inside functioneer are fully keyword arg based.
95
110
 
96
111
  ```
97
112
  import functioneer as fn
@@ -105,7 +120,7 @@ anal.add.define('b', 100) # Define parameter 'b'
105
120
  anal.add.define('x', 1) # Define parameter 'x'
106
121
  anal.add.define('y', 1) # Define parameter 'y'
107
122
 
108
- anal.add.execute(func=rosenbrock, output_param_ids='rosen') # Execute function with parameter ids matched to kwargs
123
+ anal.add.execute(func=rosenbrock) # Execute function with parameter ids matched to kwargs
109
124
 
110
125
  # Run the analysis sequence
111
126
  results = anal.run()
@@ -115,32 +130,33 @@ print(results['df'])
115
130
 
116
131
  ```
117
132
  Output:
118
- runtime a b x y rosen datetime
119
- 0 0.0 1 100 1 1 0 2025-01-03 17:06:21.252981
133
+ runtime a b x y rosenbrock datetime
134
+ 0 0.0 1 100 1 1 0 2025-06-24 03:26:48.842824
120
135
  ```
121
136
 
122
- As predicted, the `rosen` parameter evaluates to 0 when a=1, b=100, x=1, y=1
123
-
124
- Note: the `results['df']` is a pandas DataFrame containing all parameters in addition to *runtime* and *datetime* fields
137
+ As we expect, the `rosenbrock` parameter evaluates to 0 when a=1, b=100, x=1, y=1
125
138
 
126
- But let's say you want to test a range of values for some parameters...
139
+ Note: the `results['df']` is a pandas DataFrame containing all parameters in addition to *runtime* and *datetime* for the given branch
127
140
 
128
141
  ### Example 2: Single Parameter Forks (Testing Variations of a Parameter)
142
+ Let's say you want to test a range of values for some parameters...
129
143
  If you want to test a set of values for a parameter you can create a *fork* in the *analysis sequence*. This splits the analysis into multiple *branches*, each exploring different values for a the given parameter.
130
144
 
131
- Say we want to evaluate and plot the Rosenbrock surface over the x-y domain. Let's evaluate Rosenbrock a grid where x=(0, 1, 2) and y=(1, 10) which should result in 6 final *branches* / *leaves*...
145
+ Say we want to evaluate and plot the Rosenbrock surface over the x-y domain. Let's evaluate Rosenbrock on a grid where x=(0, 1, 2) and y=(1, 10) which should result in 6 final *branches* / *leaves*...
132
146
 
147
+ Note: the parameter's name is by default set from the function name, but can be overridden using the 'assign_to' arg.
133
148
  Note: some boiler plate can be removed by defining initial parameters in the AnalysisModule() declaration
149
+ Note: initial parameter values will be overwritten as needed by parameter steps
134
150
  ```
135
151
  # Create new analysis
136
- init_params = dict(a=1, b=100, x=1, y=1) # initial parameters will be overwritten by forks, optimizations, etc
152
+ init_params = dict(a=1, b=100, x=1, y=1) # define initial parameters
137
153
  anal = fn.AnalysisModule(init_params)
138
154
 
139
155
  # Define analysis sequence
140
- anal.add.fork('x', value_sets=(0, 1, 2)) # Fork analysis, create a branch for each value of 'x': 0, 1, 2
141
- anal.add.fork('y', value_sets=(1, 10)) # Fork analysis, create a branch for each value of 'y': 1, 10
156
+ anal.add.fork('x', value_set=(0, 1, 2)) # Fork analysis, create a branch for each value of 'x': 0, 1, 2
157
+ anal.add.fork('y', value_set=(1, 10)) # Fork analysis, create a branch for each value of 'y': 1, 10
142
158
 
143
- anal.add.execute(func=rosenbrock, output_param_ids='rosen') # Execute function (for each branch) with parameters matched to kwargs
159
+ anal.add.execute(func=rosenbrock, assign_to='brock_purdy') # Execute function (for each branch) with parameters matched to kwargs
144
160
 
145
161
  # Run the analysis sequence
146
162
  results = anal.run()
@@ -148,13 +164,13 @@ print(results['df'].drop(columns='datetime'))
148
164
  ```
149
165
  ```
150
166
  Output:
151
- runtime a b x y rosen
152
- 0 0.000994 1 100 0 1 101
153
- 1 0.000994 1 100 0 10 10001
154
- 2 0.000994 1 100 1 1 0
155
- 3 0.000994 1 100 1 10 8100
156
- 4 0.000994 1 100 2 1 901
157
- 5 0.000994 1 100 2 10 3601
167
+ runtime a b x y brock_purdy
168
+ 0 0.001294 1 100 0 1 101
169
+ 1 0.000000 1 100 0 10 10001
170
+ 2 0.000000 1 100 1 1 0
171
+ 3 0.000000 1 100 1 10 8100
172
+ 4 0.000000 1 100 2 1 901
173
+ 5 0.000000 1 100 2 10 3601
158
174
  ```
159
175
  The parameters `x` and `y` were given 3 and 2 fork values respectively, this created 6 total *leaves* (end of each branch) in the analysis. `rosen` has been evaluated for each *leaf*. Essentially you have begun to map the Rosenbrock function over the x-y domain.
160
176
 
@@ -168,7 +184,7 @@ anal = fn.AnalysisModule(dict(x=0, y=0))
168
184
  anal.add.fork('a', value_set=(1, 2)) # Fork analysis, create a branch for each value of 'a': 0, 1, 2
169
185
  anal.add.fork('b', value_set=(0, 100, 200)) # Fork analysis, create a branch for each value of 'b': 0, 100, 200
170
186
 
171
- anal.add.optimize(func=rosenbrock, obj_param_id='rosen', opt_param_ids=('x', 'y'))
187
+ anal.add.optimize(func=rosenbrock, opt_param_ids=('x', 'y'))
172
188
 
173
189
  # Run the analysis sequence
174
190
  results = anal.run()
@@ -186,8 +202,7 @@ Output:
186
202
  ```
187
203
  For each branch, the Rosenbrock Function has been minimized and the solution values for `x`, `y` and `rosen` are shown.
188
204
 
189
- Note: the initial values used in the optimization are just the existing parameter values (in this case x and y are 0).
190
-
205
+ Note: the initial values (`x0`) used in the optimization are simply the existing parameter values (in this case x and y are 0) going into the optimization step.
191
206
  Note: due to optimization the runtimes for some of the analyses have gone up.
192
207
 
193
208
  ### Example 4: Multi-parameter Forks
@@ -198,8 +213,7 @@ anal = fn.AnalysisModule(dict(a=1, b=100))
198
213
 
199
214
  # Define analysis sequence
200
215
  anal.add.fork.multi(('x', 'y'), value_sets=((0, 1, 2), (0, 10, 20))) # Fork analysis, create a branch for each value of 'y': 1, 10
201
-
202
- anal.add.execute(func=rosenbrock, output_param_ids='rosen') # Execute function (for each branch) with parameters matched to kwargs
216
+ anal.add.execute(func=rosenbrock) # Execute function (for each branch) with parameters matched to kwargs
203
217
 
204
218
  # Run the analysis sequence
205
219
  results = anal.run()
@@ -225,7 +239,7 @@ anal = fn.AnalysisModule(dict(x=0, y=0))
225
239
  # Define analysis sequence
226
240
  anal.add.fork('a', value_set=(1, 2))
227
241
  anal.add.fork('b', value_set=(0, 100, 200))
228
- anal.add.optimize(func=rosenbrock, obj_param_id='rosen', opt_param_ids=('x', 'y'))
242
+ anal.add.optimize(func=rosenbrock, opt_param_ids=('x', 'y'))
229
243
 
230
244
  # Only evaluate 'expensive_func' if the optimized 'y' is above 0.5
231
245
  expensive_func = lambda x, y: x+y
@@ -236,15 +250,15 @@ print(results['df'].drop(columns='datetime'))
236
250
  ```
237
251
  ```
238
252
  Output:
239
- runtime a b x y rosen expensive_param
240
- 0 0.004001 1 0 1.000000 0.000000 4.930381e-32 NaN
241
- 1 0.009702 1 100 0.999763 0.999523 5.772481e-08 1.999286
242
- 2 0.017009 1 200 0.999939 0.999873 8.146869e-09 1.999811
243
- 3 0.000995 2 0 2.000000 0.000000 0.000000e+00 NaN
244
- 4 0.016001 2 100 1.999731 3.998866 4.067518e-07 5.998596
245
- 5 0.020995 2 200 1.999554 3.998225 2.136755e-07 5.997779
246
- ```
247
- Notice how the evaluation of `expensive_param` has been skipped where the optimized `y` did not meet the criteria `y>0.5`
253
+ runtime x y a b rosenbrock expensive_param
254
+ 0 0.001997 1.000000 0.000000 1 0 4.930381e-32 NaN
255
+ 1 0.004206 0.999763 0.999523 1 100 5.772481e-08 1.999286
256
+ 2 0.012199 0.999939 0.999873 1 200 8.146869e-09 1.999811
257
+ 3 0.000965 2.000000 0.000000 2 0 0.000000e+00 NaN
258
+ 4 0.010121 1.999731 3.998866 2 100 4.067518e-07 5.998596
259
+ 5 0.012308 1.999554 3.998225 2 200 2.136755e-07 5.997779
260
+ ```
261
+ Notice how the evaluation of `expensive_param` has been skipped where the optimized `y` did not meet our criteria `y>0.5`
248
262
 
249
263
  ## License
250
264
 
@@ -1,9 +1,10 @@
1
1
  # Functioneer
2
2
 
3
3
  **Author**: Quinn Marsh
4
- **Date**: February 02, 2025
4
+ **Date**: February 02, 2025\
5
+ **PyPI**: https://pypi.org/project/functioneer/
5
6
 
6
- Functioneer is a Python package that automates the analysis of ANY function, enabling you to test and optimize with unlimited combinations of parameters. Whether you're performing parameter sweeps, sensitivity testing, or optimizing digital twins, Functioneer lets you queue up thousands or even millions of tests in seconds. Easily retrieve and analyze results in formats like pandas for seamless integration into your analysis workflows.
7
+ Functioneer lets you effortlessly explore function behavior with automated batch analysis. With just a few lines of code, you can queue up thousands or even millions of function evaluations, with various parameter combinations and/or optimizations. Retrieve structured results in formats like pandas for seamless integration into your workflows. Perfect for parameter sweeps, engineering simulations, and digital twin optimization.
7
8
 
8
9
  ## Use cases
9
10
 
@@ -13,9 +14,19 @@ Functioneer is a Python package that automates the analysis of ANY function, ena
13
14
 
14
15
  ## How Functioneer Works
15
16
 
16
- Functioneer is a powerful system for defining and executing complex analysis pipelines. At its core, the toolkit organizes analyses as pipelines, where a set of *parameters* flows sequentially through a series of *analysis steps*. These steps modify the parameters in various ways, such as defining new parameters, updating existing parameter values, or performing operations like function evaluation and optimization. One of the key features of functioneer is the ability to introduce *forks*, which split the analysis into multiple *branches*, each exploring different values for a specific parameter. This structured approach enables highly flexible and dynamic analyses, suitable for a wide range of applications.
17
+ At its core, functioneer organizes analyses as tree where a *set of parameters* starts at the trunk and moves out towards the leaves. Along the way, the *set of parameters* 'flows' through a series of *analysis steps* (each of which can be defined in a single line of code). Each *analysis step* can modify or use the parameters in various ways, such as defining new parameters, modifying parameters, or using the parameters to evaluate or even optimize any function of your choice. One key feature of functioneer is the ability to introduce *forks*: a type of analysis step that splits the analysis into multiple parallel *branches*, each exploring different values for a specific parameter. Using many *Forks* in series allows you to queue up thousands or even millions of parameter combinations with only a few lines of code. This structured approach enables highly flexible and dynamic analyses, suitable for a wide range of applications.
18
+
19
+ Summary of most useful types of *analysis steps*:
20
+ - Define: Adds a new parameter to the analysis
21
+ - Fork: Splits the analysis into multiple parallel *branches*, each exploring different values for a specific parameter
22
+ - Execute: Calls a provided function using the parameters
23
+ - Optimize: Quickly set up an optimization by providing a function and defining which parameters are going to be optimized
24
+
25
+ <details>
26
+ <summary>
27
+ <span style="font-size:1.5em;">Important Terms</span>
28
+ </summary>
17
29
 
18
- ### Terms
19
30
  * AnalysisModule
20
31
  * Definition: The central container for an analysis pipeline.
21
32
  * Function: Holds a sequence of analysis steps and manages a set of parameters that flow through the pipeline.
@@ -39,6 +50,7 @@ Functioneer is a powerful system for defining and executing complex analysis pip
39
50
  * Leaf
40
51
  * Definition: The endpoint of a branch after all analysis steps have been executed.
41
52
  * Function: Represents the final state of parameters for that branch. Each leaf corresponds to a specific combination of parameter values and results. When results are tabulated, each row corresponds to a leaf.
53
+ </details>
42
54
 
43
55
  ## Installation
44
56
 
@@ -51,17 +63,19 @@ pip install functioneer
51
63
  ## Getting Started
52
64
  Below are a few quick examples of how to use Functioneer. Each example will build on the last, introducing one piece of functionality. By the end you will have witnessed the computational power of this fully armed and fully operational library.
53
65
 
54
- ### Choosing a Function to Analyze
55
- Functioneer is designed to analyze ANY function(s) with ANY number of inputs and outputs. For the following examples, the [Rosenbrock Function](https://en.wikipedia.org/wiki/Rosenbrock_function) is used for its relative simplicity, 4 inputs (plenty to play with) and its historical significance as an optimization benchmark.
66
+ ### Choose a Function to Analyze
67
+ Functioneer is designed to analyze ANY function(s) with ANY number of inputs and outputs. For the following examples, we use the [Rosenbrock Function](https://en.wikipedia.org/wiki/Rosenbrock_function) for (1) its relative simplicity, (2) 4 inputs (plenty to play with) and (3) its historical significance as an optimization benchmark.
56
68
 
57
69
  ```
70
+ # Example Function
58
71
  # Rosenbrock function (known minimum of 0 at: x=1, y=1, a=1, b=100)
59
72
  def rosenbrock(x, y, a, b):
60
73
  return (a-x)**2 + b*(y-x**2)**2
61
74
  ```
62
75
 
63
76
  ### Example 1: The Basics (Defining Parameters and Executing a Function)
64
- Set up an *analysis sequence* by defining four parameters (the inputs needed for the Rosenbrock function), then executing the function (with parameter ids matched to kwargs)
77
+ Set up an *analysis sequence* by defining four parameters to match our function, then executing the function
78
+ Note: Parameter IDs MUST match your function's args, function executions inside functioneer are fully keyword arg based.
65
79
 
66
80
  ```
67
81
  import functioneer as fn
@@ -75,7 +89,7 @@ anal.add.define('b', 100) # Define parameter 'b'
75
89
  anal.add.define('x', 1) # Define parameter 'x'
76
90
  anal.add.define('y', 1) # Define parameter 'y'
77
91
 
78
- anal.add.execute(func=rosenbrock, output_param_ids='rosen') # Execute function with parameter ids matched to kwargs
92
+ anal.add.execute(func=rosenbrock) # Execute function with parameter ids matched to kwargs
79
93
 
80
94
  # Run the analysis sequence
81
95
  results = anal.run()
@@ -85,32 +99,33 @@ print(results['df'])
85
99
 
86
100
  ```
87
101
  Output:
88
- runtime a b x y rosen datetime
89
- 0 0.0 1 100 1 1 0 2025-01-03 17:06:21.252981
102
+ runtime a b x y rosenbrock datetime
103
+ 0 0.0 1 100 1 1 0 2025-06-24 03:26:48.842824
90
104
  ```
91
105
 
92
- As predicted, the `rosen` parameter evaluates to 0 when a=1, b=100, x=1, y=1
93
-
94
- Note: the `results['df']` is a pandas DataFrame containing all parameters in addition to *runtime* and *datetime* fields
106
+ As we expect, the `rosenbrock` parameter evaluates to 0 when a=1, b=100, x=1, y=1
95
107
 
96
- But let's say you want to test a range of values for some parameters...
108
+ Note: the `results['df']` is a pandas DataFrame containing all parameters in addition to *runtime* and *datetime* for the given branch
97
109
 
98
110
  ### Example 2: Single Parameter Forks (Testing Variations of a Parameter)
111
+ Let's say you want to test a range of values for some parameters...
99
112
  If you want to test a set of values for a parameter you can create a *fork* in the *analysis sequence*. This splits the analysis into multiple *branches*, each exploring different values for a the given parameter.
100
113
 
101
- Say we want to evaluate and plot the Rosenbrock surface over the x-y domain. Let's evaluate Rosenbrock a grid where x=(0, 1, 2) and y=(1, 10) which should result in 6 final *branches* / *leaves*...
114
+ Say we want to evaluate and plot the Rosenbrock surface over the x-y domain. Let's evaluate Rosenbrock on a grid where x=(0, 1, 2) and y=(1, 10) which should result in 6 final *branches* / *leaves*...
102
115
 
116
+ Note: the parameter's name is by default set from the function name, but can be overridden using the 'assign_to' arg.
103
117
  Note: some boiler plate can be removed by defining initial parameters in the AnalysisModule() declaration
118
+ Note: initial parameter values will be overwritten as needed by parameter steps
104
119
  ```
105
120
  # Create new analysis
106
- init_params = dict(a=1, b=100, x=1, y=1) # initial parameters will be overwritten by forks, optimizations, etc
121
+ init_params = dict(a=1, b=100, x=1, y=1) # define initial parameters
107
122
  anal = fn.AnalysisModule(init_params)
108
123
 
109
124
  # Define analysis sequence
110
- anal.add.fork('x', value_sets=(0, 1, 2)) # Fork analysis, create a branch for each value of 'x': 0, 1, 2
111
- anal.add.fork('y', value_sets=(1, 10)) # Fork analysis, create a branch for each value of 'y': 1, 10
125
+ anal.add.fork('x', value_set=(0, 1, 2)) # Fork analysis, create a branch for each value of 'x': 0, 1, 2
126
+ anal.add.fork('y', value_set=(1, 10)) # Fork analysis, create a branch for each value of 'y': 1, 10
112
127
 
113
- anal.add.execute(func=rosenbrock, output_param_ids='rosen') # Execute function (for each branch) with parameters matched to kwargs
128
+ anal.add.execute(func=rosenbrock, assign_to='brock_purdy') # Execute function (for each branch) with parameters matched to kwargs
114
129
 
115
130
  # Run the analysis sequence
116
131
  results = anal.run()
@@ -118,13 +133,13 @@ print(results['df'].drop(columns='datetime'))
118
133
  ```
119
134
  ```
120
135
  Output:
121
- runtime a b x y rosen
122
- 0 0.000994 1 100 0 1 101
123
- 1 0.000994 1 100 0 10 10001
124
- 2 0.000994 1 100 1 1 0
125
- 3 0.000994 1 100 1 10 8100
126
- 4 0.000994 1 100 2 1 901
127
- 5 0.000994 1 100 2 10 3601
136
+ runtime a b x y brock_purdy
137
+ 0 0.001294 1 100 0 1 101
138
+ 1 0.000000 1 100 0 10 10001
139
+ 2 0.000000 1 100 1 1 0
140
+ 3 0.000000 1 100 1 10 8100
141
+ 4 0.000000 1 100 2 1 901
142
+ 5 0.000000 1 100 2 10 3601
128
143
  ```
129
144
  The parameters `x` and `y` were given 3 and 2 fork values respectively, this created 6 total *leaves* (end of each branch) in the analysis. `rosen` has been evaluated for each *leaf*. Essentially you have begun to map the Rosenbrock function over the x-y domain.
130
145
 
@@ -138,7 +153,7 @@ anal = fn.AnalysisModule(dict(x=0, y=0))
138
153
  anal.add.fork('a', value_set=(1, 2)) # Fork analysis, create a branch for each value of 'a': 0, 1, 2
139
154
  anal.add.fork('b', value_set=(0, 100, 200)) # Fork analysis, create a branch for each value of 'b': 0, 100, 200
140
155
 
141
- anal.add.optimize(func=rosenbrock, obj_param_id='rosen', opt_param_ids=('x', 'y'))
156
+ anal.add.optimize(func=rosenbrock, opt_param_ids=('x', 'y'))
142
157
 
143
158
  # Run the analysis sequence
144
159
  results = anal.run()
@@ -156,8 +171,7 @@ Output:
156
171
  ```
157
172
  For each branch, the Rosenbrock Function has been minimized and the solution values for `x`, `y` and `rosen` are shown.
158
173
 
159
- Note: the initial values used in the optimization are just the existing parameter values (in this case x and y are 0).
160
-
174
+ Note: the initial values (`x0`) used in the optimization are simply the existing parameter values (in this case x and y are 0) going into the optimization step.
161
175
  Note: due to optimization the runtimes for some of the analyses have gone up.
162
176
 
163
177
  ### Example 4: Multi-parameter Forks
@@ -168,8 +182,7 @@ anal = fn.AnalysisModule(dict(a=1, b=100))
168
182
 
169
183
  # Define analysis sequence
170
184
  anal.add.fork.multi(('x', 'y'), value_sets=((0, 1, 2), (0, 10, 20))) # Fork analysis, create a branch for each value of 'y': 1, 10
171
-
172
- anal.add.execute(func=rosenbrock, output_param_ids='rosen') # Execute function (for each branch) with parameters matched to kwargs
185
+ anal.add.execute(func=rosenbrock) # Execute function (for each branch) with parameters matched to kwargs
173
186
 
174
187
  # Run the analysis sequence
175
188
  results = anal.run()
@@ -195,7 +208,7 @@ anal = fn.AnalysisModule(dict(x=0, y=0))
195
208
  # Define analysis sequence
196
209
  anal.add.fork('a', value_set=(1, 2))
197
210
  anal.add.fork('b', value_set=(0, 100, 200))
198
- anal.add.optimize(func=rosenbrock, obj_param_id='rosen', opt_param_ids=('x', 'y'))
211
+ anal.add.optimize(func=rosenbrock, opt_param_ids=('x', 'y'))
199
212
 
200
213
  # Only evaluate 'expensive_func' if the optimized 'y' is above 0.5
201
214
  expensive_func = lambda x, y: x+y
@@ -206,15 +219,15 @@ print(results['df'].drop(columns='datetime'))
206
219
  ```
207
220
  ```
208
221
  Output:
209
- runtime a b x y rosen expensive_param
210
- 0 0.004001 1 0 1.000000 0.000000 4.930381e-32 NaN
211
- 1 0.009702 1 100 0.999763 0.999523 5.772481e-08 1.999286
212
- 2 0.017009 1 200 0.999939 0.999873 8.146869e-09 1.999811
213
- 3 0.000995 2 0 2.000000 0.000000 0.000000e+00 NaN
214
- 4 0.016001 2 100 1.999731 3.998866 4.067518e-07 5.998596
215
- 5 0.020995 2 200 1.999554 3.998225 2.136755e-07 5.997779
216
- ```
217
- Notice how the evaluation of `expensive_param` has been skipped where the optimized `y` did not meet the criteria `y>0.5`
222
+ runtime x y a b rosenbrock expensive_param
223
+ 0 0.001997 1.000000 0.000000 1 0 4.930381e-32 NaN
224
+ 1 0.004206 0.999763 0.999523 1 100 5.772481e-08 1.999286
225
+ 2 0.012199 0.999939 0.999873 1 200 8.146869e-09 1.999811
226
+ 3 0.000965 2.000000 0.000000 2 0 0.000000e+00 NaN
227
+ 4 0.010121 1.999731 3.998866 2 100 4.067518e-07 5.998596
228
+ 5 0.012308 1.999554 3.998225 2 200 2.136755e-07 5.997779
229
+ ```
230
+ Notice how the evaluation of `expensive_param` has been skipped where the optimized `y` did not meet our criteria `y>0.5`
218
231
 
219
232
  ## License
220
233
 
@@ -4,13 +4,13 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "functioneer"
7
- version = "0.2.1"
7
+ version = "0.3.0"
8
8
  authors = [{ name = "Quinn Marsh", email = "quinnmarsh@hotmail.com" }]
9
9
  maintainers = [{ name = "Quinn Marsh", email = "quinnmarsh@hotmail.com" }]
10
- description = "A library providing easy automated analysis for your functions."
10
+ description = "Effortlessly explore function behavior with automated batch analysis."
11
11
  readme = "README.md"
12
12
  license = { text = "MIT" }
13
- keywords = ["functioneer", "analysis", "automation", "autorun", "trade space", "digital twin"]
13
+ keywords = ["functioneer", "analysis", "batch run", "automation", "autorun", "trade space", "digital twin"]
14
14
  requires-python = ">=3.7"
15
15
  dependencies = [
16
16
  "numpy>=1.18.5",
@@ -19,7 +19,7 @@ dependencies = [
19
19
  ]
20
20
 
21
21
  classifiers = [
22
- "Development Status :: 3 - Alpha",
22
+ "Development Status :: 4 - Beta",
23
23
  "Intended Audience :: Science/Research",
24
24
  "Topic :: Scientific/Engineering",
25
25
  "License :: OSI Approved :: MIT License",
@@ -1,6 +1,4 @@
1
1
  # functioneer/__init__.py
2
-
3
- # Import specific functions and classes from your modules
4
-
2
+ __version__ = "0.3.0"
5
3
  from functioneer.analysis import AnalysisModule, AnalysisStep, Define, Fork, Execute, Optimize
6
4
  from functioneer.parameter import Parameter