llm4ad 1.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.
- llm4ad-1.0/LICENSE +21 -0
- llm4ad-1.0/PKG-INFO +18 -0
- llm4ad-1.0/README.md +306 -0
- llm4ad-1.0/llm4ad/__init__.py +6 -0
- llm4ad-1.0/llm4ad/base/__init__.py +9 -0
- llm4ad-1.0/llm4ad/base/code.py +270 -0
- llm4ad-1.0/llm4ad/base/evaluate.py +285 -0
- llm4ad-1.0/llm4ad/base/modify_code.py +402 -0
- llm4ad-1.0/llm4ad/base/sample.py +234 -0
- llm4ad-1.0/llm4ad/gui.py +141 -0
- llm4ad-1.0/llm4ad/method/__init__.py +57 -0
- llm4ad-1.0/llm4ad/method/eoh/__init__.py +2 -0
- llm4ad-1.0/llm4ad/method/eoh/eoh.py +305 -0
- llm4ad-1.0/llm4ad/method/eoh/population.py +83 -0
- llm4ad-1.0/llm4ad/method/eoh/profiler.py +161 -0
- llm4ad-1.0/llm4ad/method/eoh/prompt.py +120 -0
- llm4ad-1.0/llm4ad/method/eoh/resume.py +104 -0
- llm4ad-1.0/llm4ad/method/eoh/sampler.py +29 -0
- llm4ad-1.0/llm4ad/method/funsearch/__init__.py +3 -0
- llm4ad-1.0/llm4ad/method/funsearch/config.py +23 -0
- llm4ad-1.0/llm4ad/method/funsearch/funsearch.py +195 -0
- llm4ad-1.0/llm4ad/method/funsearch/profiler.py +135 -0
- llm4ad-1.0/llm4ad/method/funsearch/programs_database.py +305 -0
- llm4ad-1.0/llm4ad/method/funsearch/resume.py +111 -0
- llm4ad-1.0/llm4ad/method/hillclimb/__init__.py +2 -0
- llm4ad-1.0/llm4ad/method/hillclimb/hillclimb.py +189 -0
- llm4ad-1.0/llm4ad/method/hillclimb/profiler.py +8 -0
- llm4ad-1.0/llm4ad/method/hillclimb/resume.py +83 -0
- llm4ad-1.0/llm4ad/method/randsample/__init__.py +2 -0
- llm4ad-1.0/llm4ad/method/randsample/profiler.py +8 -0
- llm4ad-1.0/llm4ad/method/randsample/randsample.py +181 -0
- llm4ad-1.0/llm4ad/method/randsample/resume.py +73 -0
- llm4ad-1.0/llm4ad/task/__init__.py +29 -0
- llm4ad-1.0/llm4ad/task/machine_learning/__init__.py +0 -0
- llm4ad-1.0/llm4ad/task/machine_learning/acrobot/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/machine_learning/acrobot/evaluation.py +65 -0
- llm4ad-1.0/llm4ad/task/machine_learning/acrobot/template.py +35 -0
- llm4ad-1.0/llm4ad/task/machine_learning/acrobot/test.py +46 -0
- llm4ad-1.0/llm4ad/task/machine_learning/car_mountain/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/machine_learning/car_mountain/evaluation.py +57 -0
- llm4ad-1.0/llm4ad/task/machine_learning/car_mountain/q-learning.py +123 -0
- llm4ad-1.0/llm4ad/task/machine_learning/car_mountain/template.py +22 -0
- llm4ad-1.0/llm4ad/task/machine_learning/car_mountain/test.py +163 -0
- llm4ad-1.0/llm4ad/task/machine_learning/moon_lander/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/machine_learning/moon_lander/evaluation.py +84 -0
- llm4ad-1.0/llm4ad/task/machine_learning/moon_lander/template.py +32 -0
- llm4ad-1.0/llm4ad/task/machine_learning/moon_lander/test.py +51 -0
- llm4ad-1.0/llm4ad/task/optimization/__init__.py +30 -0
- llm4ad-1.0/llm4ad/task/optimization/admissible_set/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/optimization/admissible_set/evaluation.py +155 -0
- llm4ad-1.0/llm4ad/task/optimization/admissible_set/template.py +22 -0
- llm4ad-1.0/llm4ad/task/optimization/cvrp_construct/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/optimization/cvrp_construct/evaluation.py +152 -0
- llm4ad-1.0/llm4ad/task/optimization/cvrp_construct/get_instance.py +50 -0
- llm4ad-1.0/llm4ad/task/optimization/cvrp_construct/template.py +22 -0
- llm4ad-1.0/llm4ad/task/optimization/online_bin_packing/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/optimization/online_bin_packing/evaluation.py +91 -0
- llm4ad-1.0/llm4ad/task/optimization/online_bin_packing/generate_weibull_instances.py +36 -0
- llm4ad-1.0/llm4ad/task/optimization/online_bin_packing/template.py +15 -0
- llm4ad-1.0/llm4ad/task/optimization/ovrp_construct/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/optimization/ovrp_construct/evaluation.py +124 -0
- llm4ad-1.0/llm4ad/task/optimization/ovrp_construct/get_instance.py +50 -0
- llm4ad-1.0/llm4ad/task/optimization/ovrp_construct/template.py +22 -0
- llm4ad-1.0/llm4ad/task/optimization/tsp_construct/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/optimization/tsp_construct/evaluation.py +148 -0
- llm4ad-1.0/llm4ad/task/optimization/tsp_construct/get_instance.py +15 -0
- llm4ad-1.0/llm4ad/task/optimization/tsp_construct/template.py +24 -0
- llm4ad-1.0/llm4ad/task/optimization/vrptw_construct/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/optimization/vrptw_construct/evaluation.py +174 -0
- llm4ad-1.0/llm4ad/task/optimization/vrptw_construct/get_instance.py +65 -0
- llm4ad-1.0/llm4ad/task/optimization/vrptw_construct/template.py +23 -0
- llm4ad-1.0/llm4ad/task/science_discovery/__init__.py +0 -0
- llm4ad-1.0/llm4ad/task/science_discovery/bactgrow/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/science_discovery/bactgrow/evaluation.py +87 -0
- llm4ad-1.0/llm4ad/task/science_discovery/bactgrow/template.py +20 -0
- llm4ad-1.0/llm4ad/task/science_discovery/bactgrow/test_id.py +17502 -0
- llm4ad-1.0/llm4ad/task/science_discovery/bactgrow/test_odd.py +105002 -0
- llm4ad-1.0/llm4ad/task/science_discovery/bactgrow/train.py +52502 -0
- llm4ad-1.0/llm4ad/task/science_discovery/ode_1d/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/science_discovery/ode_1d/evaluation.py +152 -0
- llm4ad-1.0/llm4ad/task/science_discovery/ode_1d/strogatz_equations.py +224 -0
- llm4ad-1.0/llm4ad/task/science_discovery/ode_1d/strogatz_extended.py +34001 -0
- llm4ad-1.0/llm4ad/task/science_discovery/ode_1d/template.py +22 -0
- llm4ad-1.0/llm4ad/task/science_discovery/oscillator1/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/science_discovery/oscillator1/evaluation.py +85 -0
- llm4ad-1.0/llm4ad/task/science_discovery/oscillator1/template.py +19 -0
- llm4ad-1.0/llm4ad/task/science_discovery/oscillator1/test_id.py +50002 -0
- llm4ad-1.0/llm4ad/task/science_discovery/oscillator1/test_odd.py +50002 -0
- llm4ad-1.0/llm4ad/task/science_discovery/oscillator1/train.py +50002 -0
- llm4ad-1.0/llm4ad/task/science_discovery/oscillator2/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/science_discovery/oscillator2/evaluation.py +87 -0
- llm4ad-1.0/llm4ad/task/science_discovery/oscillator2/template.py +20 -0
- llm4ad-1.0/llm4ad/task/science_discovery/oscillator2/test_id.py +60002 -0
- llm4ad-1.0/llm4ad/task/science_discovery/oscillator2/test_odd.py +60002 -0
- llm4ad-1.0/llm4ad/task/science_discovery/oscillator2/train.py +60002 -0
- llm4ad-1.0/llm4ad/task/science_discovery/stresstrain/__init__.py +2 -0
- llm4ad-1.0/llm4ad/task/science_discovery/stresstrain/evaluation.py +85 -0
- llm4ad-1.0/llm4ad/task/science_discovery/stresstrain/template.py +19 -0
- llm4ad-1.0/llm4ad/task/science_discovery/stresstrain/test_id.py +7212 -0
- llm4ad-1.0/llm4ad/task/science_discovery/stresstrain/test_odd.py +3692 -0
- llm4ad-1.0/llm4ad/task/science_discovery/stresstrain/train.py +10807 -0
- llm4ad-1.0/llm4ad/tools/__init__.py +3 -0
- llm4ad-1.0/llm4ad/tools/llm/__init__.py +32 -0
- llm4ad-1.0/llm4ad/tools/llm/llm_api_https.py +73 -0
- llm4ad-1.0/llm4ad/tools/llm/llm_api_openai.py +21 -0
- llm4ad-1.0/llm4ad/tools/log_utils.py +730 -0
- llm4ad-1.0/llm4ad/tools/profiler/__init__.py +40 -0
- llm4ad-1.0/llm4ad/tools/profiler/profile.py +208 -0
- llm4ad-1.0/llm4ad/tools/profiler/tensorboard_profiler.py +85 -0
- llm4ad-1.0/llm4ad/tools/profiler/wandb_profiler.py +100 -0
- llm4ad-1.0/llm4ad.egg-info/PKG-INFO +18 -0
- llm4ad-1.0/llm4ad.egg-info/SOURCES.txt +115 -0
- llm4ad-1.0/llm4ad.egg-info/dependency_links.txt +1 -0
- llm4ad-1.0/llm4ad.egg-info/requires.txt +11 -0
- llm4ad-1.0/llm4ad.egg-info/top_level.txt +1 -0
- llm4ad-1.0/setup.cfg +4 -0
- llm4ad-1.0/setup.py +24 -0
llm4ad-1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
llm4ad-1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: llm4ad
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: Large Language Model for Algorithm Design Platform
|
|
5
|
+
Author: Optima
|
|
6
|
+
Requires-Python: >=3.9,<=3.11
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: numpy<2
|
|
9
|
+
Requires-Dist: tensorboard
|
|
10
|
+
Requires-Dist: scipy
|
|
11
|
+
Requires-Dist: tqdm
|
|
12
|
+
Requires-Dist: requests
|
|
13
|
+
Requires-Dist: openai
|
|
14
|
+
Requires-Dist: pytz
|
|
15
|
+
Requires-Dist: matplotlib
|
|
16
|
+
Requires-Dist: python-docx
|
|
17
|
+
Requires-Dist: gym
|
|
18
|
+
Requires-Dist: ttkbootstrap
|
llm4ad-1.0/README.md
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
<h1 align="center">
|
|
5
|
+
<img src="./assets/figs/logo.png" alt="LLM4AD Logo" style="width: 90%; height: auto;">
|
|
6
|
+
</h1>
|
|
7
|
+
<h1 align="center">
|
|
8
|
+
LLM4AD: Large Language Model for Algorithm Design
|
|
9
|
+
</h1>
|
|
10
|
+
|
|
11
|
+
[](https://github.com/Optima-CityU/LLM4AD/releases)
|
|
12
|
+

|
|
13
|
+
[](https://github.com/Optima-CityU/LLM4AD/pulls)
|
|
14
|
+

|
|
15
|
+
[](https://github.com/Optima-CityU/LLM4AD/blob/main/LICENSE)
|
|
16
|
+
[](https://llm4ad-doc.readthedocs.io/en/latest/?badge=latest)
|
|
17
|
+
[](https://colab.research.google.com/github/Optima-CityU/llm4ad/blob/main/example/online_bin_packing/online_bin_packing_tutorial.ipynb)
|
|
18
|
+
|
|
19
|
+
[Website](http://www.llm4ad.com/)
|
|
20
|
+
| [Documentation](https://llm4ad-doc.readthedocs.io/en/latest/)
|
|
21
|
+
| [Examples](https://github.com/Optima-CityU/LLM4AD/tree/main/example)
|
|
22
|
+
| [GUI](https://github.com/Optima-CityU/LLM4AD/tree/main/GUI)
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
<br>
|
|
26
|
+
|
|
27
|
+
## Introduction 📖
|
|
28
|
+
|
|
29
|
+
LLM4AD is an open-source Python-based Platform leveraging **Large Language Models (LLMs)** for **Automatic Algorithm Design (AD)**. Please refer to the [paper](https://arxiv.org/pdf/2412.17287) [LLM4AD] for detailed information, including the overview, methodology, and benchmark results.
|
|
30
|
+
|
|
31
|
+
LLM4AD is accomplished with [Documents](https://llm4ad-doc.readthedocs.io/en/latest/) and [Examples](https://github.com/Optima-CityU/LLM4AD/tree/main/example) materials to support users and developers to easily test, build and deploy their own LLM4AD applications and conduct research.
|
|
32
|
+
|
|
33
|
+
LLM4AD was originally developed for [optimisation tasks](https://llm4ad-doc.readthedocs.io/en/latest/task/optimization/index.html). The framework is versatile enough to be used in other areas, including [machine learning](https://llm4ad-doc.readthedocs.io/en/latest/task/machine_learning/index.html), [science discovery](https://llm4ad-doc.readthedocs.io/en/latest/task/science_discovery/index.html), game theory and engineering design.
|
|
34
|
+
|
|
35
|
+
For more information, see the [contact list](https://github.com/Optima-CityU/LLM4AD#Contact)
|
|
36
|
+
|
|
37
|
+
<img src="./assets/figs/overview.png" alt="llm4ad" style="zoom:50%;" />
|
|
38
|
+
|
|
39
|
+
## 🔥 News
|
|
40
|
+
|
|
41
|
+
+ 2024.12 🎉🎉 **LLM4AD paper Released** [“LLM4AD: A Platform for Algorithm Design with Large Language Model"](https://arxiv.org/pdf/2412.17287) !
|
|
42
|
+
|
|
43
|
+
+ 2024.11 🎉🎉 **LLM4AD v1.0 Released** !
|
|
44
|
+
|
|
45
|
+
+ 2024.10 🎉🎉 **Survey Paper** [“A Systematic Survey on Large Language Models for Algorithm Design”](https://arxiv.org/pdf/2410.14716) is online !
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
## 💡 Features of our package
|
|
50
|
+
|
|
51
|
+
| Feature | Support / To be supported |
|
|
52
|
+
| ------------------------------------------------------------ | ------------------------- |
|
|
53
|
+
| **Unified Interfaces** for methods | 🔥Support |
|
|
54
|
+
| **Unified Interfaces** for tasks | 🔥Support |
|
|
55
|
+
| **Unified Interfaces** for LLMs | 🔥Support |
|
|
56
|
+
| **Evaluation acceleration:** multiprocessing evaluation, add Numba wrapper for heuristic | 🔥Support |
|
|
57
|
+
| **Secure Evaluation:** main process protection, timeout interruption | 🔥Support |
|
|
58
|
+
| **Logs:** local logs, Wandb and Tensorboard support | 🔥Support |
|
|
59
|
+
| **GUI:** methods selection, tasks selection, convergence, best algorithm, ... | 🔥Support |
|
|
60
|
+
| **Resume run** | 🚀Will be updated soon |
|
|
61
|
+
| Support other languages | 🚀Will be updated soon |
|
|
62
|
+
| More search methods | 🚀Will be updated soon |
|
|
63
|
+
| More task examples | 🚀Will be updated soon |
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
## 🎁 Requirements & Installation
|
|
68
|
+
|
|
69
|
+
> [!Important]
|
|
70
|
+
> The Python version **must** be larger or equal to Python 3.9.
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
- refer to [requirements.txt](./requirements.txt)
|
|
74
|
+
|
|
75
|
+
- Numba (if you want to use Numba accelerate)
|
|
76
|
+
|
|
77
|
+
- Tensorboard (if you want to use a Tensorboard logger)
|
|
78
|
+
|
|
79
|
+
- wandb (if you want to use wandb logger)
|
|
80
|
+
|
|
81
|
+
- gym (if you want to try **Machine Learning** tasks)
|
|
82
|
+
|
|
83
|
+
- pandas (if you want to try **Science Discovery** tasks)
|
|
84
|
+
|
|
85
|
+
- all required packages in [requirements.txt](./requirements.txt) (if you want to use GUI)
|
|
86
|
+
|
|
87
|
+
#### Install LLM4AD locally
|
|
88
|
+
|
|
89
|
+
We suggest to install and run LLM4AD in [conda](https://conda.io/projects/conda/en/latest/index.html) env with python>=3.9, <=3.11
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
cd LLM4AD
|
|
93
|
+
|
|
94
|
+
pip install .
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
#### Install LLM4AD using PiPy
|
|
98
|
+
|
|
99
|
+
We suggest to install and run LLM4AD in [conda](https://conda.io/projects/conda/en/latest/index.html) env with python>=3.9, <=3.11
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
pip install llm4ad
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
## 💻 Example Usage
|
|
108
|
+
|
|
109
|
+
### Quick Start:
|
|
110
|
+
|
|
111
|
+
> [!Note]
|
|
112
|
+
> Configure your LLM api before running the script. For example:
|
|
113
|
+
>
|
|
114
|
+
> 1) Set `host`: 'api.deepseek.com'
|
|
115
|
+
> 2) Set `key`: 'your api key'
|
|
116
|
+
> 3) Set `model` `deepseek-chat'
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from llm4ad.task.optimization.online_bin_packing import OBPEvaluation
|
|
120
|
+
from llm4ad.tools.llm.llm_api_https import HttpsApi
|
|
121
|
+
from llm4ad.method.eoh import EoH, EoHProfiler
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def main():
|
|
125
|
+
|
|
126
|
+
llm = HttpsApi(host="xxx", # your host endpoint, e.g., api.openai.com, api.deepseek.com
|
|
127
|
+
key="sk-xxx", # your key, e.g., sk-xxxxxxxxxx
|
|
128
|
+
model="xxx", # your llm, e.g., gpt-3.5-turbo, deepseek-chat
|
|
129
|
+
timeout=20)
|
|
130
|
+
|
|
131
|
+
task = OBPEvaluation()
|
|
132
|
+
|
|
133
|
+
method = EoH(llm=llm,
|
|
134
|
+
profiler=EoHProfiler(log_dir='logs/eoh', log_style='simple'),
|
|
135
|
+
evaluation=task,
|
|
136
|
+
max_sample_nums=20,
|
|
137
|
+
max_generations=10,
|
|
138
|
+
pop_size=4,
|
|
139
|
+
num_samplers=1,
|
|
140
|
+
num_evaluators=1,
|
|
141
|
+
debug_mode=False)
|
|
142
|
+
|
|
143
|
+
method.run()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
if __name__ == '__main__':
|
|
147
|
+
main()
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
### More Examples:
|
|
153
|
+
+ [Constructive Heuristics for TSP](https://github.com/Optima-CityU/LLM4AD/blob/main/example/tsp_construct/run_eoh.py)
|
|
154
|
+
+ [Constructive Heuristics for VRPTW](https://github.com/Optima-CityU/LLM4AD/blob/main/example/vrptw_construct/run_eoh.py)
|
|
155
|
+
+ ...
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
Check [Documents](https://llm4ad-doc.readthedocs.io/en/latest/index.html) for more tasks and examples
|
|
159
|
+
|
|
160
|
+
### GUI usage:
|
|
161
|
+
|
|
162
|
+
> [!Important]
|
|
163
|
+
> Install all required packages in [requirements.txt](./requirements.txt) for GUI usage
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
$ cd GUI
|
|
167
|
+
$ python run_gui.py
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Check [GUI Introduction](https://llm4ad-doc.readthedocs.io/en/latest/getting_started/gui.html) for more information
|
|
171
|
+
|
|
172
|
+
<img src="./assets/figs/gui.gif" alt="llm4ad" style="zoom:80%;" />
|
|
173
|
+
|
|
174
|
+
## 📦 LLM4AD Search Methods
|
|
175
|
+
|
|
176
|
+
| Methods | Paper title |
|
|
177
|
+
| ----------------------------------------------------- | ------------------------------------------------------------ |
|
|
178
|
+
| **AEL** (Preliminary Version of **EoH**) | [Algorithm Evolution using Large Language Model](https://arxiv.org/abs/2311.15249) (Arxiv 2023) |
|
|
179
|
+
| **EoH** | [Evolution of Heuristics: Towards Efficient Automatic Algorithm Design Using Large Language Model](https://openreview.net/pdf?id=BwAkaxqiLB) (ICML 2024) |
|
|
180
|
+
| **FunSearch** | [Mathematical Discoveries from Program Search with Large Language Models](https://www.nature.com/articles/s41586-023-06924-6) (Nature 2024) |
|
|
181
|
+
| **RandomSampling** | [Understanding the Importance of Evolutionary Search in Automated Heuristic Design with Large Language Models](https://arxiv.org/abs/2407.10873) (PPSN 2024) |
|
|
182
|
+
| **(1+1)-EPS** <br/>(HillClimbing) | [Understanding the Importance of Evolutionary Search in Automated Heuristic Design with Large Language Models](https://arxiv.org/abs/2407.10873) (PPSN 2024) |
|
|
183
|
+
| RegEvo | coming soon |
|
|
184
|
+
| Neighborhood search methods | coming soon |
|
|
185
|
+
| Multi-objective search methods | coming soon |
|
|
186
|
+
| Others | coming soon |
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
## 📦LLM4AD Algorithm Design Tasks
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
| Area | Algorithm Task | Paper |
|
|
193
|
+
| ----------------- | ------------------------------------------------------------ | ------------------------------------------------- |
|
|
194
|
+
| Optimization | [Online Bin Packing, Constructive heuristic] | [paper](https://openreview.net/pdf?id=BwAkaxqiLB) |
|
|
195
|
+
| | [Traveling Salesman Problem (TSP), Construct heuristic](https://llm4ad-doc.readthedocs.io/en/latest/task/optimization/tsp_construct.html) | [paper](https://arxiv.org/pdf/2311.15249) |
|
|
196
|
+
| | Traveling Salesman Problem (TSP), Guided local search | [paper](https://openreview.net/pdf?id=BwAkaxqiLB) |
|
|
197
|
+
| | Flow Shop Scheduling Problem (FSSP), Guided local search | [paper](https://openreview.net/pdf?id=BwAkaxqiLB) |
|
|
198
|
+
| | Bayesian Optimization, Cost-aware Acquisition Function Design | [paper](https://arxiv.org/abs/2404.16906) |
|
|
199
|
+
| Machine Learning | Adversarial Attack, Attack strategy | [paper](https://arxiv.org/abs/2401.15335) |
|
|
200
|
+
| | [Acrobot, Heuristic (Agent)](https://llm4ad-doc.readthedocs.io/en/latest/task/machine_learning/acrobot.html) | |
|
|
201
|
+
| | [Cart Pole, Heuristic (Agent)](https://llm4ad-doc.readthedocs.io/en/latest/task/machine_learning/car_pole.html) | |
|
|
202
|
+
| | [Mountain Car, Heuristic (Agent)](https://llm4ad-doc.readthedocs.io/en/latest/task/machine_learning/mountain_car.html) | |
|
|
203
|
+
| Science Discovery | Computational fluid dynamics, Turbulence model design | [paper](https://arxiv.org/pdf/2410.10657) |
|
|
204
|
+
| | [Bacteria Growth, Function](https://llm4ad-doc.readthedocs.io/en/latest/task/science_discovery/bacteria_grow.html) | |
|
|
205
|
+
| | [Oscillator, Equation](https://llm4ad-doc.readthedocs.io/en/latest/task/science_discovery/oscillator1.html) | |
|
|
206
|
+
| | [Stress & Strain, Equation](https://llm4ad-doc.readthedocs.io/en/latest/task/science_discovery/stress_strain.html) | |
|
|
207
|
+
| Math | Admissible Sets | [paper](https://www.nature.com/articles/s41586-023-06924-6) |
|
|
208
|
+
| coming soon ... | | |
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
## 🤖 LLM Interfaces
|
|
213
|
+
There are three approaches on LLM interface implementation, check [Tutorial on LLM interface implementation](https://llm4ad-doc.readthedocs.io/en/latest/dev/llm.html) for more information.
|
|
214
|
+
+ **Remote LLM API** (e.g., GPT4o, GPT3.5, Gemini Pro, Deepseek ...) (**<Recommended !!!>**)
|
|
215
|
+
+ **Local HuggingFace LLM Deployment** (e.g., Llamacode, Llama, Gemma, Deepseek, ...)
|
|
216
|
+
+ **Your Implementation** If you want to use your own GPT API or local LLMs deployment, please create and add your interface in [LLM](https://github.com/Optima-CityU/LLM4AD/tree/main/llm4ad/tools/llm)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
## 🗎 Tutorial: How to Use LLM4AD to Solve Your Algorithm Design Task
|
|
221
|
+
|
|
222
|
+
A Step-by-step Tutorial on using LLM4AD to solve your algorithm design task is provided [here](https://llm4ad-doc.readthedocs.io/en/latest/dev/run_new_task.html#)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
## 🪪 Licence
|
|
228
|
+
|
|
229
|
+
This project is licensed under the **MIT License** - see the [LICENSE](./LICENSE) file for details. Parts of this project use code licensed under the Apache License 2.0.
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
## ✨Reference
|
|
234
|
+
|
|
235
|
+
If you find LLM4AD helpful please cite:
|
|
236
|
+
|
|
237
|
+
```bibtex
|
|
238
|
+
@article{liu2024llm4ad,
|
|
239
|
+
title={LLM4AD: A Platform for Algorithm Design with Large Language Model},
|
|
240
|
+
author={Fei Liu and Rui Zhang and Zhuoliang Xie and Rui Sun and Kai Li and Xi Lin and Zhenkun Wang and Zhichao Lu and Qingfu Zhang},
|
|
241
|
+
year={2024},
|
|
242
|
+
eprint={2412.17287},
|
|
243
|
+
archivePrefix={arXiv},
|
|
244
|
+
primaryClass={cs.AI},
|
|
245
|
+
url={https://arxiv.org/abs/2412.17287},
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
## About LLM4AD
|
|
252
|
+
|
|
253
|
+
This platform is developed and maintained by LLM4AD developer group from the City University of Hong Kong (CityUHK) and the Southern University of Science and Technology (SUSTech). We develop LLM4AD platform for research purposes and hope to contribute to the research area by delivering tools for LLM-based algorithm design methods.
|
|
254
|
+
|
|
255
|
+
+ **Contribution:** We are more than welcome to contribute (see our 📖 [contribution guide](https://github.com/Optima-CityU/llm4ad/tree/main/assets/contribution.md)) including developing code and ideas to improve our platform.
|
|
256
|
+
+ **Collaborations:** If you like our platform, and you would like to use it for profit-making purposes? We are always searching for industrial collaborations because they help direct research to meet the industry’s needs.
|
|
257
|
+
+ **Issue:** If you find a bug or you have any kind of concern regarding the correctness, please report us an [issue](https://github.com/Optima-CityU/llm4ad/issues).
|
|
258
|
+
+ **Profit Purpose:** If you intend to use LLM4AD for any profit-making purposes, please contact [us](http://www.llm4ad.com/contact.html).
|
|
259
|
+
|
|
260
|
+
## :star: Star Trends
|
|
261
|
+
[](https://star-history.com/#Optima-CityU/llm4ad&Date)
|
|
262
|
+
|
|
263
|
+
## Contact
|
|
264
|
+
|
|
265
|
+
If you are interested in LLM4AD or if you encounter any difficulty using the platform, you can:
|
|
266
|
+
|
|
267
|
+
1. Visit our website [LLM4AD Web](http://www.llm4ad.com)
|
|
268
|
+
|
|
269
|
+
2. Visit our collection [a collection of resources and research papers on LLM4AD](https://github.com/FeiLiu36/LLM4Opt)
|
|
270
|
+
|
|
271
|
+
3. Visit [Discussions](https://github.com/Optima-CityU/llm4ad/discussions) to connect with other members of our community
|
|
272
|
+
|
|
273
|
+
4. Join our QQ Group
|
|
274
|
+
|
|
275
|
+
<img src="./assets/figs/qq.png" alt="LLM4AD Logo" style="width: 30%; height: auto;">
|
|
276
|
+
|
|
277
|
+
5. Contact us through email fliu36-c@my.cityu.edu.hk
|
|
278
|
+
|
|
279
|
+
6. Submit an [issue](https://github.com/Optima-CityU/LLM4AD)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
## Contributors
|
|
284
|
+
|
|
285
|
+
Any new ideas, features, and improvements are welcomed!
|
|
286
|
+
|
|
287
|
+
You can contribute to LLM4AD follow our 📖 [Contribution Guide](https://github.com/Optima-CityU/llm4ad/tree/main/assets/contribution.md).
|
|
288
|
+
|
|
289
|
+
Thank you for contributing to LLM4AD and welcome to being part of the LLM4AD community! :sparkles:
|
|
290
|
+
|
|
291
|
+
<table>
|
|
292
|
+
<tbody>
|
|
293
|
+
<tr>
|
|
294
|
+
<td align="center" valign="top" width="12.5%"><a href="https://github.com/FeiLiu36"><img src="https://avatars.githubusercontent.com/FeiLiu36" width="50px;" alt="Fei Liu"/><br /><sub><b>Fei Liu</b></sub></td>
|
|
295
|
+
<td align="center" valign="top" width="12.5%"><a href="https://ahalikai.github.io/"><img src="https://github.com/Ahalikai/Ahalikai.github.io/blob/main/Aha.jpg?raw=true" width="50px;" alt="Kai Li"/><br /><sub><b>Kai Li</b></sub>
|
|
296
|
+
</td>
|
|
297
|
+
<td align="center" valign="top" width="12.5%"><a href="https://github.com/SunnyR7"><img src="https://avatars.githubusercontent.com/SunnyR7" width="50px;" alt="Rui Sun"/><br /><sub><b>Rui Sun</b></sub></td>
|
|
298
|
+
<td align="center" valign="top" width="12.5%"><a href="https://github.com/Acquent0"><img src="https://avatars.githubusercontent.com/Acquent0" width="50px;" alt="Julian XIE"/><br /><sub><b>Julian XIE</b></sub>
|
|
299
|
+
</td>
|
|
300
|
+
<td align="center" valign="top" width="12.5%"><a href="https://github.com/ShunyuYao6"><img src="https://avatars.githubusercontent.com/ShunyuYao6" width="50px;" alt="Shunyu Yao"/><br /><sub><b>Shunyu Yao</b></sub>
|
|
301
|
+
</td>
|
|
302
|
+
<td align="center" valign="top" width="12.5%"><a href="https://github.com/RayZhhh"><img src="https://avatars.githubusercontent.com/RayZhhh" width="50px;" alt="Rui Zhang"/><br /><sub><b>Rui Zhang</b></sub>
|
|
303
|
+
</td>
|
|
304
|
+
</tr>
|
|
305
|
+
|
|
306
|
+
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This file implements 2 classes representing unities of code:
|
|
3
|
+
|
|
4
|
+
- Function, containing all the information we need about functions: name, args,
|
|
5
|
+
body and optionally a return type and a docstring.
|
|
6
|
+
|
|
7
|
+
- Program, which contains a code preface (which could be imports, global
|
|
8
|
+
variables and classes, ...) and a list of Functions.
|
|
9
|
+
|
|
10
|
+
- For example, a function is shown below,
|
|
11
|
+
which is an un-executable program because 'np' is not defined, and 'WEIGHT' is not defined.
|
|
12
|
+
--------------------------------------------------------------------------------------------
|
|
13
|
+
def func(a: np.ndarray, b: np.ndarray) -> np.ndarray:
|
|
14
|
+
b = b + WEIGHT
|
|
15
|
+
return a + b
|
|
16
|
+
--------------------------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
- A program is an executable object as shown below.
|
|
19
|
+
--------------------------------------------------------------------------------------------
|
|
20
|
+
import numpy as np
|
|
21
|
+
WEIGHT = 10
|
|
22
|
+
|
|
23
|
+
def func(a: np.ndarray, b: np.ndarray) -> np.ndarray:
|
|
24
|
+
b = b + WEIGHT
|
|
25
|
+
return a + b
|
|
26
|
+
--------------------------------------------------------------------------------------------
|
|
27
|
+
"""
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import ast
|
|
31
|
+
import copy
|
|
32
|
+
import dataclasses
|
|
33
|
+
from typing import Any
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclasses.dataclass
|
|
37
|
+
class Function:
|
|
38
|
+
"""A parsed Python function."""
|
|
39
|
+
|
|
40
|
+
name: str
|
|
41
|
+
args: str
|
|
42
|
+
body: str
|
|
43
|
+
return_type: str | None = None
|
|
44
|
+
docstring: str | None = None
|
|
45
|
+
score: Any | None = None
|
|
46
|
+
evaluate_time: float | None = None
|
|
47
|
+
sample_time: float | None = None
|
|
48
|
+
|
|
49
|
+
def __str__(self) -> str:
|
|
50
|
+
return_type = f' -> {self.return_type}' if self.return_type else ''
|
|
51
|
+
|
|
52
|
+
function = f'def {self.name}({self.args}){return_type}:\n'
|
|
53
|
+
if self.docstring:
|
|
54
|
+
# self.docstring is already indented on every line except the first one.
|
|
55
|
+
# Here, we assume the indentation is always four spaces.
|
|
56
|
+
new_line = '\n' if self.body else ''
|
|
57
|
+
function += f' """{self.docstring}"""{new_line}'
|
|
58
|
+
# self.body is already indented.
|
|
59
|
+
function += self.body + '\n\n'
|
|
60
|
+
return function
|
|
61
|
+
|
|
62
|
+
def __setattr__(self, name: str, value: str) -> None:
|
|
63
|
+
# Ensure there aren't leading & trailing new lines in `body`.
|
|
64
|
+
if name == 'body':
|
|
65
|
+
value = value.strip('\n')
|
|
66
|
+
# Ensure there aren't leading & trailing quotes in `docstring``.
|
|
67
|
+
if name == 'docstring' and value is not None:
|
|
68
|
+
if '"""' in value:
|
|
69
|
+
value = value.strip()
|
|
70
|
+
value = value.replace('"""', '')
|
|
71
|
+
super().__setattr__(name, value)
|
|
72
|
+
|
|
73
|
+
def __eq__(self, other: Function):
|
|
74
|
+
assert isinstance(other, Function)
|
|
75
|
+
return (self.name == other.name and
|
|
76
|
+
self.args == other.args and
|
|
77
|
+
self.return_type == other.return_type and
|
|
78
|
+
self.body == other.body)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclasses.dataclass(frozen=True)
|
|
82
|
+
class Program:
|
|
83
|
+
"""A parsed Python program."""
|
|
84
|
+
|
|
85
|
+
# `preface` is everything from the beginning of the code till the first
|
|
86
|
+
# function is found.
|
|
87
|
+
preface: str
|
|
88
|
+
functions: list[Function]
|
|
89
|
+
|
|
90
|
+
def __str__(self) -> str:
|
|
91
|
+
program = f'{self.preface}\n' if self.preface else ''
|
|
92
|
+
program += '\n'.join([str(f) for f in self.functions])
|
|
93
|
+
return program
|
|
94
|
+
|
|
95
|
+
def find_function_index(self, function_name: str) -> int:
|
|
96
|
+
"""Returns the index of input function name."""
|
|
97
|
+
function_names = [f.name for f in self.functions]
|
|
98
|
+
count = function_names.count(function_name)
|
|
99
|
+
if count == 0:
|
|
100
|
+
raise ValueError(
|
|
101
|
+
f'function {function_name} does not exist in program:\n{str(self)}'
|
|
102
|
+
)
|
|
103
|
+
if count > 1:
|
|
104
|
+
raise ValueError(
|
|
105
|
+
f'function {function_name} exists more than once in program:\n'
|
|
106
|
+
f'{str(self)}'
|
|
107
|
+
)
|
|
108
|
+
index = function_names.index(function_name)
|
|
109
|
+
return index
|
|
110
|
+
|
|
111
|
+
def get_function(self, function_name: str) -> Function:
|
|
112
|
+
index = self.find_function_index(function_name)
|
|
113
|
+
return self.functions[index]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class _ProgramVisitor(ast.NodeVisitor):
|
|
117
|
+
"""Parses code to collect all required information to produce a `Program`.
|
|
118
|
+
Note that we do not store function decorators.
|
|
119
|
+
"""
|
|
120
|
+
|
|
121
|
+
def __init__(self, sourcecode: str):
|
|
122
|
+
self._codelines: list[str] = sourcecode.splitlines()
|
|
123
|
+
self._preface: str = ''
|
|
124
|
+
self._functions: list[Function] = []
|
|
125
|
+
self._current_function: str | None = None
|
|
126
|
+
|
|
127
|
+
def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
|
|
128
|
+
"""Collects all information about the function being parsed.
|
|
129
|
+
"""
|
|
130
|
+
# We only care about first level functions.
|
|
131
|
+
if node.col_offset == 0:
|
|
132
|
+
self._current_function = node.name
|
|
133
|
+
# --------------------------------------------------------------------------------------------
|
|
134
|
+
# RZ: Here is an issue: some cases were not taken into consideration.
|
|
135
|
+
# For instance, if the first parsed function has decorators,
|
|
136
|
+
# these decorators will also be retained in the preceding code snippet.
|
|
137
|
+
# However, in the algorithm's flow, these decorators are invalid,
|
|
138
|
+
# leading to subsequent evaluations reporting errors.
|
|
139
|
+
# --------------------------------------------------------------------------------------------
|
|
140
|
+
# if not self._functions:
|
|
141
|
+
# self._preface = '\n'.join(self._codelines[:node.lineno - 1])
|
|
142
|
+
# --------------------------------------------------------------------------------------------
|
|
143
|
+
# Fix bugs: if the first function is decorated, find the smallest line_no of the decorator,
|
|
144
|
+
# FIX bugs: and retrain the code above it as 'preface'.
|
|
145
|
+
# --------------------------------------------------------------------------------------------
|
|
146
|
+
if not self._functions:
|
|
147
|
+
has_decorators = bool(node.decorator_list)
|
|
148
|
+
if has_decorators:
|
|
149
|
+
# find the minimum line number and retain the code above
|
|
150
|
+
decorator_start_line = min(decorator.lineno for decorator in node.decorator_list)
|
|
151
|
+
self._preface = '\n'.join(self._codelines[:decorator_start_line - 1])
|
|
152
|
+
else:
|
|
153
|
+
self._preface = '\n'.join(self._codelines[:node.lineno - 1])
|
|
154
|
+
# --------------------------------------------------------------------------------------------
|
|
155
|
+
function_end_line = node.end_lineno
|
|
156
|
+
body_start_line = node.body[0].lineno - 1
|
|
157
|
+
# Extract the docstring.
|
|
158
|
+
docstring = None
|
|
159
|
+
if isinstance(node.body[0], ast.Expr) and isinstance(node.body[0].value, ast.Str):
|
|
160
|
+
docstring = f' """{ast.literal_eval(ast.unparse(node.body[0]))}"""'
|
|
161
|
+
if len(node.body) > 1:
|
|
162
|
+
# ----------------------------------------------------------------------------
|
|
163
|
+
# RZ: If the next line of the docstring is also comment that starts with "#"
|
|
164
|
+
# We should preserve it.
|
|
165
|
+
# ----------------------------------------------------------------------------
|
|
166
|
+
# body_start_line = node.body[1].lineno - 1
|
|
167
|
+
# ----------------------------------------------------------------------------
|
|
168
|
+
# Fix bugs: If we find the docstring, the function body start with
|
|
169
|
+
# Fix bugs: body[0].end_lineno, where body[0] refers to the docstring node.
|
|
170
|
+
# ----------------------------------------------------------------------------
|
|
171
|
+
body_start_line = node.body[0].end_lineno
|
|
172
|
+
# ----------------------------------------------------------------------------
|
|
173
|
+
else:
|
|
174
|
+
body_start_line = function_end_line
|
|
175
|
+
|
|
176
|
+
self._functions.append(Function(
|
|
177
|
+
name=node.name,
|
|
178
|
+
args=ast.unparse(node.args),
|
|
179
|
+
return_type=ast.unparse(node.returns) if node.returns else None,
|
|
180
|
+
docstring=docstring,
|
|
181
|
+
body='\n'.join(self._codelines[body_start_line:function_end_line]),
|
|
182
|
+
))
|
|
183
|
+
self.generic_visit(node)
|
|
184
|
+
|
|
185
|
+
def return_program(self) -> Program:
|
|
186
|
+
return Program(preface=self._preface, functions=self._functions)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class TextFunctionProgramConverter:
|
|
190
|
+
"""Convert text to Program instance and Function instance,
|
|
191
|
+
Convert Program instance to Function instance, and Function instance to Program instance.
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
@classmethod
|
|
195
|
+
def text_to_program(cls, program_str: str) -> Program | None:
|
|
196
|
+
"""Returns Program object by parsing input text using Python AST.
|
|
197
|
+
"""
|
|
198
|
+
try:
|
|
199
|
+
# We assume that the program is composed of some preface (e.g. imports,
|
|
200
|
+
# classes, assignments, ...) followed by a sequence of functions.
|
|
201
|
+
tree = ast.parse(program_str)
|
|
202
|
+
visitor = _ProgramVisitor(program_str)
|
|
203
|
+
visitor.visit(tree)
|
|
204
|
+
return visitor.return_program()
|
|
205
|
+
except:
|
|
206
|
+
return None
|
|
207
|
+
|
|
208
|
+
@classmethod
|
|
209
|
+
def text_to_function(cls, program_str: str) -> Function | None:
|
|
210
|
+
"""Returns Function object by parsing input text using Python AST.
|
|
211
|
+
"""
|
|
212
|
+
try:
|
|
213
|
+
program = cls.text_to_program(program_str)
|
|
214
|
+
if len(program.functions) != 1:
|
|
215
|
+
raise ValueError(f'Only one function expected, got {len(program.functions)}'
|
|
216
|
+
f':\n{program.functions}')
|
|
217
|
+
return program.functions[0]
|
|
218
|
+
except ValueError as value_err:
|
|
219
|
+
raise value_err
|
|
220
|
+
except:
|
|
221
|
+
return None
|
|
222
|
+
|
|
223
|
+
@classmethod
|
|
224
|
+
def function_to_program(cls, function: str | Function, template_program: str | Program) -> Program | None:
|
|
225
|
+
try:
|
|
226
|
+
# convert function to Function instance
|
|
227
|
+
if isinstance(function, str):
|
|
228
|
+
function = cls.text_to_function(function)
|
|
229
|
+
else:
|
|
230
|
+
function = copy.deepcopy(function)
|
|
231
|
+
|
|
232
|
+
# convert template_program to Program instance
|
|
233
|
+
if isinstance(template_program, str):
|
|
234
|
+
template_program = cls.text_to_program(template_program)
|
|
235
|
+
else:
|
|
236
|
+
template_program = copy.deepcopy(template_program)
|
|
237
|
+
|
|
238
|
+
# assert that a program have one function
|
|
239
|
+
if len(template_program.functions) != 1:
|
|
240
|
+
raise ValueError(f'Only one function expected, got {len(template_program.functions)}'
|
|
241
|
+
f':\n{template_program.functions}')
|
|
242
|
+
|
|
243
|
+
# replace the function body with the new function body
|
|
244
|
+
template_program.functions[0].body = function.body
|
|
245
|
+
return template_program
|
|
246
|
+
except ValueError as value_err:
|
|
247
|
+
raise value_err
|
|
248
|
+
except:
|
|
249
|
+
return None
|
|
250
|
+
|
|
251
|
+
@classmethod
|
|
252
|
+
def program_to_function(cls, program: str | Program) -> Function | None:
|
|
253
|
+
try:
|
|
254
|
+
# convert program to Program instance
|
|
255
|
+
if isinstance(program, str):
|
|
256
|
+
program = cls.text_to_program(program)
|
|
257
|
+
else:
|
|
258
|
+
program = copy.deepcopy(program)
|
|
259
|
+
|
|
260
|
+
# assert that a program have one function
|
|
261
|
+
if len(program.functions) != 1:
|
|
262
|
+
raise ValueError(f'Only one function expected, got {len(program.functions)}'
|
|
263
|
+
f':\n{program.functions}')
|
|
264
|
+
|
|
265
|
+
# return the function
|
|
266
|
+
return program.functions[0]
|
|
267
|
+
except ValueError as value_err:
|
|
268
|
+
raise value_err
|
|
269
|
+
except:
|
|
270
|
+
return None
|