Skip to content

Commit e93b1c6

Browse files
committed
feat: Add atomic model generation using JSON and iterative code generation
1 parent fbde16d commit e93b1c6

9 files changed

Lines changed: 471 additions & 22 deletions
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
**External Transition (`extTransition`):**
2+
- Executed when the model receives a message via its input ports. Only applicable to models that handle incoming data, such as the default model.
3+
- Use `self.peek(self.IPorts[0], *args) to retrieve a message from a port. Change the index to peek at a specific port.
4+
*Example : retrieve a message for every ports :*
5+
for port in self.IPorts:
6+
msg = self.peek(port, *args)
7+
8+
- `Message` is a class with the following variables : `value` which is the content of the message, and `time` representing the simulation time it was sent.
9+
- Based on the message content, the model can take actions such as changing state, executing specific logic, or remaining in the current state.
10+
- Use `self.holdIn()` to set the new state and delay until the next transition as needed
11+
- the line **`return self.getState()`** is required
12+
13+
14+
**Handle and change state: **
15+
- Use `self.getState()` to retrieve the model’s current state at any point in the code. This can help conditionally control actions based on the model’s state.
16+
- Use `self.phaseIs()` to test if the model's current state name is equal to the provided string. Example : `if self.phaseIs("State_Name"):`.
17+
- Use `self.getStatus()` to get the model's current state name. Use this if only the current state name is needed.
18+
19+
**Example: the model has at least one input port**
20+
def extTransition(self, *args):
21+
''' DEVS external transition function (only for models that receive data) '''
22+
for port in self.IPorts:
23+
msg = self.peek(port, *args)
24+
if msg:
25+
# State change or action logic based on the message
26+
current_state = self.getState() # Example usage of getState()
27+
# Customize based on intended behavior
28+
29+
return self.getState()
30+
31+
32+
**Example: The model doesn't have any input ports**
33+
def extTransition(self, *args):
34+
''' DEVS external transition function (only for models that receive data) '''
35+
pass
36+
37+
38+
## Steps
39+
1. Use the number of input ports to identify if the function is necessary
40+
2. Use the 'parameters' field to add the eventually needed parameters.
41+
3. Use the 'description' and 'input_ports' fields to infer if you need to peek at every ports or only a specific one.
42+
4. Use the information in the 'states' array when using `self.holdIn()`. If the 'time' field is a string, assume that a class variable has been created. For example : `self.holdIn("state",self.variable_name)`.
43+
*Exception:* if the time is marked as 'infinity', use it directly, as a constant, without the quotes.
44+
Example :
45+
"states": [
46+
{ "name": "IDLE", "time": "INFINITY"},
47+
{ "name": "SEND", "time": "duration"},
48+
{ "name": "GENERATE", "time": 0}
49+
],
50+
Where :
51+
- INFINITY represents the DEVSimPy constant
52+
- period, or any other string, represents a class variable
53+
- 0, or any other number, directly represent the state duration
54+
is used :
55+
- `self.holdIn("IDLE",INFINITY)`
56+
- `self.holdIn("SEND",self.duration)`
57+
- `self.holdIn("GENERATE",0)`
58+
5. Except told otherwise, there is no need to check the state before changing it.
59+
6. Only use the json's data value, the keys and structure must not appear in the code.
60+
7. Assume that every variable in 'model_properties' has been initialized and can be used directly, with the provided type and value.
61+
8. the function self.peek() should always be present if the function is needed.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
1. **Required Imports:**
2+
3+
from DomainInterface.DomainBehavior import DomainBehavior
4+
from DomainInterface.Object import Message
5+
6+
7+
2. **Inheritance:** The class should inherit from `DomainBehavior`.
8+
9+
3. **Constructor (`__init__`):**
10+
- Accept customizable external parameters with default values to configure the model’s behavior.
11+
- Initialize any necessary attributes within the class, just like a standard Python constructor.
12+
- Important: Use `self.initPhase()` to define the initial state and corresponding duration.
13+
- The ports aren't initialized here.
14+
15+
16+
**Example:**
17+
from DomainInterface.DomainBehavior import DomainBehavior
18+
from DomainInterface.Object import Message
19+
20+
class ModelName(DomainBehavior):
21+
''' DEVS Class for a generic model '''
22+
23+
def __init__(self, param1=10, param2="default"):
24+
''' Constructor '''
25+
DomainBehavior.__init__(self)
26+
self.param1 = param1
27+
self.param2 = param2
28+
# Initialize any other required attributes
29+
self.initPhase('INITIAL_STATE', INFINITY) # Customizable initial state and duration
30+
31+
32+
## Steps
33+
1. Include the required imports
34+
2. Use the 'model_name' field to complete de class name.
35+
3. Initialize the needed variables (informations in the 'model_properties' array : a dictionary represents all the needed information for one variable). Only put the variables in the constructor parameters if they are in the 'parameters' field of the function, or if stated directly, else, only initialize them in the function's body. Some may be present in the 'model_description', you can add them too.
36+
4. Add additional imports if they seem relevant or necessary.
37+
5. Use the 'initial_state' field to get the name and time for the self.initPhase() function.
38+
6. You can write additional code to answer the 'description' request.
39+
7. Only output the imports, class declaration and __init__().
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
**Internal Transition (`intTransition`):**
2+
- Executed when the internal transition time expires, based on the model’s current state.
3+
- This transition may include changing the state, performing actions, or maintaining the current state.
4+
- To modify the model’s state during an internal transition, **use `self.holdIn("State_Name", timeUntilNextTransition)`**.
5+
- `timeUntilNextTransition` can directly be a number or a variable
6+
- the line **`return self.getState()`** is required
7+
8+
9+
**Handle and change state: **
10+
- Use `self.getState()` to retrieve the model’s current state at any point in the code. This can help conditionally control actions based on the model’s state.
11+
- Use `self.phaseIs()` to test if the model's current state name is equal to the provided string. Example : `if self.phaseIs("State_Name"):`.
12+
- Use `self.getStatus()` to get the model's current state name. Use this if only the current state name is needed.
13+
14+
15+
**Example: **
16+
17+
def intTransition(self):
18+
''' DEVS internal transition function '''
19+
current_state = self.getState() # Example usage of getState()
20+
# Use self.holdIn() to change state or set an internal delay
21+
# Customize as needed
22+
23+
return self.getState()
24+
25+
26+
## Steps
27+
1. Use the 'parameters' field to add the eventual needed parameters.
28+
2. Write code to follow the 'description' field.
29+
3. Check if you need to directly access the state or only change it. In the second case, directly use `holdIn()`
30+
4. Pay attention to how you need to access the state :
31+
- the full state object (getState())
32+
- only the name
33+
5. Use the information in the 'states' array when using `self.holdIn()`. If the 'time' is a string, assume that a class variable has been created. For example : `self.holdIn("state",self.variable_name)`.
34+
Example :
35+
JSON states array :
36+
"states": [
37+
{ "name": "IDLE", "time": "INFINITY"},
38+
{ "name": "SEND", "time": "duration"},
39+
{ "name": "GENERATE", "time": 0}
40+
],
41+
Where :
42+
- INFINITY represents the DEVSimPy constant
43+
- period, or any other string, represents a class variable
44+
- 0, or any other number, directly represent the state duration
45+
is used in code :
46+
- `self.holdIn("IDLE",INFINITY)`
47+
- `self.holdIn("SEND",self.duration)`
48+
- `self.holdIn("GENERATE",0)`
49+
*Exception:* if the time is marked as 'INFINITY', use it directly, as a constant (without the quotes).
50+
6. Only use the json's data value, the keys and structure must not appear in the code.
51+
7. Assume that every variable in 'model_properties' has been initialized and can be used directly, with the provided type and value.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
**Output Function (`outputFnc`):**
2+
- Sends messages via output ports, only required for models that transmit data, like the default model.
3+
- Structure the message using the `Message` class to transmit necessary information according to the model’s logic. This class has two attributes : `value` which is the content of the message, and `time` representing the simulation time it was sent.
4+
- Use the `self.poke(self.OPorts[0], Message("Message content", self.timeNext))` to send the message.
5+
**self.poke needs to be a return**
6+
7+
8+
**Handle state: **
9+
- Use `self.getState()` to retrieve the model’s current state at any point in the code. This can help conditionally control actions based on the model’s state.
10+
- Use `self.phaseIs()` to test if the model's current state name is equal to the provided string. Example : `if self.phaseIs("State_Name"):`.
11+
- Use `self.getStatus()` to get the model's current state name. Use this if only the current state name is needed.
12+
13+
**Example: if the model has at least one output port**
14+
def outputFnc(self):
15+
''' DEVS output function (only for models that send data) '''
16+
# Create and return a structured message for output ports
17+
return self.poke(self.OPorts[0], Message("Message content", self.timeNext))
18+
19+
**Example: if the model doesn't have an output port**
20+
def outputFnc(self):
21+
''' DEVS output function (only for models that send data) '''
22+
pass
23+
24+
25+
## Steps
26+
1. Use the number of output ports to identify if the function is necessary
27+
2. Use the 'parameters' field to add the eventual needed parameters.
28+
3. Follow the 'description' field to write the needed code.
29+
4. Use the 'description' field to understand which message needs to be sent.
30+
5. Use the 'description' and 'output_ports' fields to infer if one or multiple ports need to send the message.
31+
6. Assume that every variable in 'class_variables' has been initialized.
32+
7. Always return the self.poke result if the function is needed.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
**Time Advance (`timeAdvance`):**
2+
- Controls time advancement in the simulation by returning `self.getSigma()` for the time until the next transition.
3+
4+
**Example:**
5+
def timeAdvance(self):
6+
''' DEVS Time Advance function '''
7+
return self.getSigma()
8+
9+
## Steps
10+
1. Unless the 'description' and 'parameters' fields are specified, you can just return the provided example.

devsimpy/AI/json_gen_prompt.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
You are an expert in DEVS modeling. The user input describes different characteristics of a DEVS model, return them as a json.
2+
3+
Here is an explanation about how some fields work :
4+
- "states" : each state has a "name" and is held for a certain "time". The time can correspond to a class_variable. In this case, use the name provided.
5+
- "model_description" should be a short paragraph explaining the actions the model needs to do. It can be directly paraphrased from the user's input.
6+
- "initial_state" should correspond to one of the entry in the "states" array.
7+
- "model_properties" represent all the properties either described by the user, or judged as necessary. If the property can have multiple value (like enum, array, list) then use an array to represent all the possibilities.
8+
- "parameters" are a function parameters in a coding sense. It represents the additional parameters (like a constructor variables). If a variable is in the model_properties, it doesn't need to be put in parameters.
9+
10+
1. Identify the model's main goal.
11+
2. Identify the properties (a property can't be a possible function)
12+
3. Identify the state(s) : their name and time.
13+
4. Make sure the "initial_state" corresponds to a "states" entry
14+
5. Only put parameters in the function is they are not "model_properties"
15+
6. If a behavior isn't specified for a function, then use the default behavior.
16+

0 commit comments

Comments
 (0)