composabl-cli-dev 0.19.1.dev1__cp310-cp310-macosx_11_0_arm64.whl

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.

Potentially problematic release.


This version of composabl-cli-dev might be problematic. Click here for more details.

Files changed (71) hide show
  1. composabl_cli/__init__.py +9 -0
  2. composabl_cli/cli/__init__.cpython-310-darwin.so +0 -0
  3. composabl_cli/cli/cli.cpython-310-darwin.so +0 -0
  4. composabl_cli/cli/cli_agent.cpython-310-darwin.so +0 -0
  5. composabl_cli/cli/cli_benchmark.cpython-310-darwin.so +0 -0
  6. composabl_cli/cli/cli_debug.cpython-310-darwin.so +0 -0
  7. composabl_cli/cli/cli_historian.cpython-310-darwin.so +0 -0
  8. composabl_cli/cli/cli_job.cpython-310-darwin.so +0 -0
  9. composabl_cli/cli/cli_main.cpython-310-darwin.so +0 -0
  10. composabl_cli/cli/cli_perceptor.cpython-310-darwin.so +0 -0
  11. composabl_cli/cli/cli_selector.cpython-310-darwin.so +0 -0
  12. composabl_cli/cli/cli_sim.cpython-310-darwin.so +0 -0
  13. composabl_cli/cli/cli_skill.cpython-310-darwin.so +0 -0
  14. composabl_cli/cli/cli_version.cpython-310-darwin.so +0 -0
  15. composabl_cli/k8s/k8s_train.cpython-310-darwin.so +0 -0
  16. composabl_cli/k8s/util.cpython-310-darwin.so +0 -0
  17. composabl_cli/main/agent.cpython-310-darwin.so +0 -0
  18. composabl_cli/main/perceptor.cpython-310-darwin.so +0 -0
  19. composabl_cli/main/selector.cpython-310-darwin.so +0 -0
  20. composabl_cli/main/sim.cpython-310-darwin.so +0 -0
  21. composabl_cli/main/skill.cpython-310-darwin.so +0 -0
  22. composabl_cli/template/agent_composabl/agent.py +90 -0
  23. composabl_cli/template/agent_docker/agent.py +99 -0
  24. composabl_cli/template/agent_local/agent.py +96 -0
  25. composabl_cli/template/perceptor/README.md +67 -0
  26. composabl_cli/template/perceptor/pyproject.toml +15 -0
  27. composabl_cli/template/perceptor/{{NAME_MODULE}}/__init__.py +3 -0
  28. composabl_cli/template/perceptor/{{NAME_MODULE}}/perceptor.py +34 -0
  29. composabl_cli/template/selector_controller/README.md +67 -0
  30. composabl_cli/template/selector_controller/pyproject.toml +12 -0
  31. composabl_cli/template/selector_controller/{{NAME_MODULE}}/__init__.py +3 -0
  32. composabl_cli/template/selector_controller/{{NAME_MODULE}}/controller.py +52 -0
  33. composabl_cli/template/selector_teacher/README.md +67 -0
  34. composabl_cli/template/selector_teacher/pyproject.toml +12 -0
  35. composabl_cli/template/selector_teacher/{{NAME_MODULE}}/__init__.py +3 -0
  36. composabl_cli/template/selector_teacher/{{NAME_MODULE}}/teacher.py +70 -0
  37. composabl_cli/template/sim/README.md +39 -0
  38. composabl_cli/template/sim/pyproject.toml +20 -0
  39. composabl_cli/template/sim/{{NAME_MODULE}}/__init__.py +3 -0
  40. composabl_cli/template/sim/{{NAME_MODULE}}/sim.py +253 -0
  41. composabl_cli/template/sim/{{NAME_MODULE}}/sim_impl.py +115 -0
  42. composabl_cli/template/sim_docker/Dockerfile +45 -0
  43. composabl_cli/template/sim_docker/README.md +17 -0
  44. composabl_cli/template/sim_docker/docker/sim-start.sh +14 -0
  45. composabl_cli/template/sim_docker/main.py +55 -0
  46. composabl_cli/template/sim_docker/module/README.md +39 -0
  47. composabl_cli/template/sim_docker/module/pyproject.toml +20 -0
  48. composabl_cli/template/sim_docker/module/{{NAME_MODULE}}/__init__.py +3 -0
  49. composabl_cli/template/sim_docker/module/{{NAME_MODULE}}/sim.py +253 -0
  50. composabl_cli/template/sim_docker/module/{{NAME_MODULE}}/sim_impl.py +115 -0
  51. composabl_cli/template/skill_controller/README.md +67 -0
  52. composabl_cli/template/skill_controller/pyproject.toml +12 -0
  53. composabl_cli/template/skill_controller/{{NAME_MODULE}}/__init__.py +3 -0
  54. composabl_cli/template/skill_controller/{{NAME_MODULE}}/controller.py +40 -0
  55. composabl_cli/template/skill_coordinated_population/README.md +67 -0
  56. composabl_cli/template/skill_coordinated_population/pyproject.toml +12 -0
  57. composabl_cli/template/skill_coordinated_population/{{NAME_MODULE}}/__init__.py +3 -0
  58. composabl_cli/template/skill_coordinated_population/{{NAME_MODULE}}/coach.py +70 -0
  59. composabl_cli/template/skill_coordinated_set/README.md +67 -0
  60. composabl_cli/template/skill_coordinated_set/pyproject.toml +12 -0
  61. composabl_cli/template/skill_coordinated_set/{{NAME_MODULE}}/__init__.py +3 -0
  62. composabl_cli/template/skill_coordinated_set/{{NAME_MODULE}}/coach.py +70 -0
  63. composabl_cli/template/skill_teacher/README.md +67 -0
  64. composabl_cli/template/skill_teacher/pyproject.toml +12 -0
  65. composabl_cli/template/skill_teacher/{{NAME_MODULE}}/__init__.py +3 -0
  66. composabl_cli/template/skill_teacher/{{NAME_MODULE}}/teacher.py +70 -0
  67. composabl_cli_dev-0.19.1.dev1.dist-info/METADATA +49 -0
  68. composabl_cli_dev-0.19.1.dev1.dist-info/RECORD +71 -0
  69. composabl_cli_dev-0.19.1.dev1.dist-info/WHEEL +5 -0
  70. composabl_cli_dev-0.19.1.dev1.dist-info/entry_points.txt +2 -0
  71. composabl_cli_dev-0.19.1.dev1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,20 @@
1
+ [project]
2
+ name = "{{NAME}}"
3
+ version = "0.1.0"
4
+ description = "{{DESCRIPTION}}"
5
+ authors = [{ name = "John Doe", email = "john.doe@composabl.com" }]
6
+ dependencies = [
7
+ "composabl-core"
8
+ ]
9
+
10
+ [composabl]
11
+ type = "sim"
12
+ entrypoint = "{{NAME_MODULE}}.sim_impl:SimImpl"
13
+ dependencies_system = [] # include additional apt-get packages to be installed
14
+
15
+ # Include additional data files
16
+ [tool.setuptools.packages.find]
17
+ where = ["{{NAME_MODULE}}"]
18
+
19
+ [tool.setuptools.package-data]
20
+ "*" = ["*.json", "*.pkl"]
@@ -0,0 +1,3 @@
1
+ # Copyright (C) Composabl, Inc - All Rights Reserved
2
+ # Unauthorized copying of this file, via any medium is strictly prohibited
3
+ # Proprietary and confidential
@@ -0,0 +1,253 @@
1
+ # Copyright (C) Composabl, Inc - All Rights Reserved
2
+ # Unauthorized copying of this file, via any medium is strictly prohibited
3
+ # Proprietary and confidential
4
+
5
+ import math
6
+ import random
7
+ from typing import Optional
8
+
9
+ import gymnasium as gym
10
+ import numpy as np
11
+ from composabl_core.agent.scenario import Scenario
12
+
13
+
14
+ class Env(gym.Env):
15
+ def __init__(self):
16
+ self.obs_space_constraints = {
17
+ "x": {"low": -400, "high": 400},
18
+ "x_speed": {"low": -100, "high": 100},
19
+ "y": {"low": 0, "high": 1000},
20
+ "y_speed": {"low": -1000, "high": 1000},
21
+ "angle": {"low": -3.15 * 2, "high": 3.15 * 2},
22
+ "angle_speed": {"low": -3, "high": 3},
23
+ }
24
+
25
+ deg_to_rad = 0.01745329
26
+ self.max_gimble = 20 * deg_to_rad
27
+ self.min_gimble = -self.max_gimble
28
+
29
+ self.action_constraints = {
30
+ "angle": {"low": self.min_gimble, "high": self.max_gimble},
31
+ "thrust": {"low": 0.4, "high": 1},
32
+ }
33
+
34
+ low_list = [x["low"] for x in self.obs_space_constraints.values()]
35
+ high_list = [x["high"] for x in self.obs_space_constraints.values()]
36
+
37
+ self.sensor_space = gym.spaces.Box(
38
+ low=np.array(low_list), high=np.array(high_list)
39
+ )
40
+
41
+ low_act_list = [x["low"] for x in self.action_constraints.values()]
42
+ high_act_list = [x["high"] for x in self.action_constraints.values()]
43
+
44
+ self.action_space = gym.spaces.Box(
45
+ low=np.array(low_act_list), high=np.array(high_act_list)
46
+ )
47
+
48
+ self.state_models = {}
49
+ self.reward_models = {}
50
+ self.scenario: Scenario = None
51
+
52
+ self.x_obs0 = 0
53
+ self.x_speed0 = 0
54
+ self.y_obs0 = 1000
55
+ self.y_speed0 = -80
56
+ self.angle0 = -np.pi / 2
57
+ self.ang_speed0 = 0
58
+
59
+ def starship_simulation(self, x, u):
60
+ g = 9.8
61
+ m = 100000 # kg
62
+ min_thrust = 880 * 1000 # N
63
+ max_thrust = 1 * 2210 * 1000 # kN
64
+
65
+ length = 50 # m
66
+ width = 10
67
+
68
+ # Inertia for a uniform density rod
69
+ I = (1 / 12) * m * length**2
70
+
71
+ deg_to_rad = 0.01745329
72
+
73
+ max_gimble = 20 * deg_to_rad
74
+ min_gimble = -max_gimble
75
+
76
+ theta = x[4]
77
+
78
+ thrust = u[0]
79
+ thrust_angle = u[1]
80
+
81
+ # Horizontal force
82
+ F_x = max_thrust * thrust * math.sin(thrust_angle + theta)
83
+ x_dot = x[1]
84
+ x_dotdot = (F_x) / m
85
+
86
+ # Vertical force
87
+ F_y = max_thrust * thrust * math.cos(thrust_angle + theta)
88
+ y_dot = x[3]
89
+ y_dotdot = (F_y) / m - g
90
+
91
+ # Torque
92
+ T = -length / 2 * max_thrust * thrust * math.sin(thrust_angle)
93
+ theta_dot = x[5]
94
+ theta_dotdot = T / I
95
+
96
+ return [x_dot, x_dotdot, y_dot, y_dotdot, theta_dot, theta_dotdot]
97
+
98
+ def reset(
99
+ self,
100
+ *,
101
+ seed: Optional[int] = None,
102
+ options: Optional[dict] = None,
103
+ x_obs0: float = 0,
104
+ x_speed0: float = 0,
105
+ y_obs0: float = 1000,
106
+ y_speed0: float = -80,
107
+ angle0: float = -np.pi / 2,
108
+ ang_speed0: float = 0
109
+ ):
110
+ """
111
+ # x[0] = x position (m)
112
+ # x[1] = x velocity (m/)
113
+ # x[2] = y position (m)
114
+ # x[3] = y velocity (m/s)
115
+ # x[4] = angle (rad)
116
+ # x[5] = angular velocity (rad/s)
117
+
118
+ # u[0] = thrust (percent)
119
+ # u[1] = thrust angle (rad)
120
+
121
+ """
122
+ super().reset(seed=seed)
123
+ self.cnt = 0
124
+ self.min_thrust = 880 * 1000 # N
125
+ self.max_thrust = 1 * 2210 * 1000 # kN
126
+
127
+ # Define scenario in the simulation ******
128
+ if isinstance(self.scenario, Scenario):
129
+ sample = self.scenario.sample()
130
+
131
+ for key in list(sample.keys()):
132
+ setattr(self, key, sample[key])
133
+
134
+ # Set the number of steps and the timestep (dt)
135
+ steps = 400
136
+ self.t_step = 0.04
137
+ self.cnt = 0
138
+
139
+ self.x = np.zeros((steps + 1, 6))
140
+ self.u = np.zeros((steps + 1, 2))
141
+
142
+ self.x[0, :] = [
143
+ self.x_obs0,
144
+ self.x_speed0,
145
+ self.y_obs0,
146
+ self.y_speed0,
147
+ self.angle0,
148
+ self.ang_speed0,
149
+ ]
150
+ self.x[steps - 1, :] = [0, 0, 0, 0, 0, 0]
151
+
152
+ self.x_obs = self.x[self.cnt, 0]
153
+ self.x_speed = self.x[self.cnt, 1]
154
+ self.y_obs = self.x[self.cnt, 2]
155
+ self.y_speed = self.x[self.cnt, 3]
156
+ self.angle = self.x[self.cnt, 4]
157
+ self.ang_speed = self.x[self.cnt, 5]
158
+
159
+ self.t = 0.4
160
+ self.a = 0
161
+ self.reward_value = 0
162
+
163
+ self.obs = {
164
+ "x": self.x_obs,
165
+ "x_speed": self.x_speed,
166
+ "y": self.y_obs,
167
+ "y_speed": self.y_speed,
168
+ "angle": self.angle,
169
+ "angle_speed": self.ang_speed,
170
+ }
171
+
172
+ self.obs = np.array(list(self.obs.values()))
173
+ info = {}
174
+ return self.obs, info
175
+
176
+ def set_scenario(self, scenario):
177
+ self.scenario = scenario
178
+
179
+ def step(self, action):
180
+ terminated = False
181
+ discount = 0
182
+ reward = 0
183
+
184
+ def sumsqr(lt):
185
+ v = sum([x**2 for x in lt])
186
+ return v
187
+
188
+ angle = action[0]
189
+ thrust = action[1]
190
+
191
+ actuator_noise = 0
192
+ self.t = thrust + random.uniform(
193
+ -actuator_noise * thrust, actuator_noise * thrust
194
+ )
195
+ self.a = angle + random.uniform(-actuator_noise * angle, actuator_noise * angle)
196
+
197
+ self.t = np.clip(self.t, 0.4, 1)
198
+ self.a = np.clip(self.a, self.min_gimble, self.max_gimble)
199
+
200
+ # update u
201
+ self.u[self.cnt, 0] = self.t
202
+ self.u[self.cnt, 1] = self.a
203
+
204
+ res = self.starship_simulation(self.x[self.cnt, :], self.u[self.cnt, :])
205
+ res = [v * self.t_step for v in res]
206
+
207
+ self.x[self.cnt + 1, :] = [
208
+ sum(value) for value in zip(self.x[self.cnt, :], res)
209
+ ]
210
+
211
+ # Increase time
212
+ self.cnt += 1
213
+ # update values
214
+ self.x_obs = self.x[self.cnt, 0]
215
+ self.x_speed = self.x[self.cnt, 1]
216
+ self.y_obs = self.x[self.cnt, 2]
217
+ self.y_speed = self.x[self.cnt, 3]
218
+ self.angle = self.x[self.cnt, 4]
219
+ self.ang_speed = self.x[self.cnt, 5]
220
+
221
+ # update obs with new state values
222
+ self.obs = {
223
+ "x": self.x_obs,
224
+ "x_speed": self.x_speed,
225
+ "y": self.y_obs,
226
+ "y_speed": self.y_speed,
227
+ "angle": self.angle,
228
+ "angle_speed": self.ang_speed,
229
+ }
230
+ # add noise
231
+ for key in list(self.obs.keys()):
232
+ val = float(self.obs[key])
233
+ sensor_noise = 0.0
234
+ self.obs[key] = val + random.uniform(
235
+ -val * sensor_noise, val * sensor_noise
236
+ )
237
+
238
+ # end the simulation
239
+ if self.y_obs < 0:
240
+ terminated = True
241
+ elif (
242
+ not self.obs_space_constraints["x"]["low"]
243
+ <= self.x_obs
244
+ <= self.obs_space_constraints["x"]["high"]
245
+ ):
246
+ terminated = True
247
+
248
+ self.obs = np.array(list(self.obs.values()))
249
+ info = {}
250
+ return self.obs, reward, terminated, False, info
251
+
252
+ def render(self, mode="auto"):
253
+ pass
@@ -0,0 +1,115 @@
1
+ # Copyright (C) Composabl, Inc - All Rights Reserved
2
+ # Unauthorized copying of this file, via any medium is strictly prohibited
3
+ # Proprietary and confidential
4
+
5
+ from typing import Any, Dict, SupportsFloat, Tuple
6
+
7
+ import composabl_core.utils.logger as logger_util
8
+ import gymnasium as gym
9
+ from composabl_core.agent.scenario import Scenario
10
+ from composabl_core.networking.sim.server_composabl import ServerComposabl
11
+ from gymnasium.envs.registration import EnvSpec
12
+
13
+ from .sim import Env
14
+
15
+ logger = logger_util.get_logger(__name__)
16
+
17
+
18
+ class SimImpl(ServerComposabl):
19
+ def __init__(self):
20
+ self.env = Env()
21
+
22
+ async def make(self, env_id: str, env_init: dict) -> EnvSpec:
23
+ """
24
+ Make the environment
25
+
26
+ Args:
27
+ - env_id (str): Environment ID
28
+ - env_init (dict): Environment Initialization
29
+
30
+ Returns:
31
+ - EnvSpec: Environment Specification
32
+ """
33
+ spec = {"id": "starship", "max_episode_steps": 400}
34
+ return spec
35
+
36
+ async def sensor_space_info(self) -> gym.Space:
37
+ """
38
+ Get the sensor space information
39
+
40
+ Returns:
41
+ - Space: Sensor Space in Gymnasium Specification
42
+ """
43
+ return self.env.sensor_space
44
+
45
+ async def action_space_info(self) -> gym.Space:
46
+ """
47
+ Get the action space information
48
+
49
+ Returns:
50
+ - Space: Action Space in Gymnasium Specification
51
+ """
52
+ return self.env.action_space
53
+
54
+ async def action_space_sample(self) -> Any:
55
+ """
56
+ Get the action space sample
57
+
58
+ Returns:
59
+ - List[Any]: A list of samples
60
+ """
61
+ return self.env.action_space.sample()
62
+
63
+ async def reset(self) -> Tuple[Any, Dict[str, Any]]:
64
+ """
65
+ Reset the environment
66
+
67
+ Returns:
68
+ - Tuple[Any, Dict[str, Any]]: The observation and the info
69
+ """
70
+ sensors, info = self.env.reset()
71
+ return sensors, info
72
+
73
+ async def step(
74
+ self, action
75
+ ) -> Tuple[Any, SupportsFloat, bool, bool, Dict[str, Any]]:
76
+ """
77
+ Step the environment
78
+
79
+ Args:
80
+ - action: The action to take
81
+
82
+ Returns:
83
+ - Tuple[Any, SupportsFloat, bool, bool, Dict[str, Any]]: The observation, reward, is_truncated, is_done, info
84
+ """
85
+ return self.env.step(action)
86
+
87
+ async def close(self):
88
+ """
89
+ Close the environment
90
+ """
91
+ self.env.close()
92
+
93
+ async def set_scenario(self, scenario):
94
+ """
95
+ Set the scenario
96
+ """
97
+ self.env.scenario = scenario
98
+
99
+ async def get_scenario(self):
100
+ """
101
+ Get the scenario
102
+ """
103
+ if self.env.scenario is None:
104
+ return Scenario({"dummy": 0})
105
+
106
+ return self.env.scenario
107
+
108
+ async def get_render(self):
109
+ """
110
+ Get the render
111
+
112
+ Args:
113
+ - render_mode: The render mode
114
+ """
115
+ return self.env.get_render_frame()
@@ -0,0 +1,67 @@
1
+ # README
2
+
3
+ This is a template for creating a new Perceptor. A Perceptor is a component that is responsible for processing data and returning a result. This can be used for example in a Machine Learning model, where the Perceptor is responsible for processing the data and returning the prediction.
4
+
5
+ ## Tree Structure
6
+
7
+ The template is structured as follows:
8
+
9
+ ```bash
10
+ my-perceptor/ # Root folder
11
+ ├── my_perceptor/ # Main package folder
12
+ │ ├── __init__.py # Package init file
13
+ │ └── perceptor.py # Main perceptor file
14
+ ├── pyproject.toml # Project configuration, containing [composabl]
15
+ ```
16
+
17
+ ## PyProject [composabl] Section
18
+
19
+ We add the `[composabl]` section to the `pyproject.toml` file to specify the type of component we are creating as well as its entrypoint. This is used by the Composabl CLI to determine the type of
20
+ component and how to handle it.
21
+
22
+ Example:
23
+
24
+ ```
25
+ [composabl]
26
+ type = "teacher"
27
+ entrypoint = "my_perceptor.perceptor:MyPerceptor"
28
+ ```
29
+
30
+ ## Development
31
+
32
+ To work on the Perceptor, you can simply create a temporary file or main file that starts up and executes the `compute` method of the portable Perceptor. Example, we can create a `test.py` file with:
33
+
34
+ ```python
35
+ from composabl_perceptor_my_perceptor.perceptor import MyPerceptor
36
+
37
+
38
+ async def start():
39
+ p = MyPerceptor()
40
+ res = await t.compute(None, [1.0])
41
+ print(res)
42
+
43
+
44
+ if __name__ == "__main__":
45
+ import asyncio
46
+
47
+ asyncio.run(start())
48
+ ```
49
+
50
+ Which we can then run with
51
+
52
+ ```bash
53
+ # Install the module
54
+ pip install -e my-perceptor
55
+
56
+ # Run the test file
57
+ python my-perceptor/test.py
58
+ ```
59
+
60
+ ### Preparing for Upload
61
+
62
+ Once we are ready for uploading, we can create a `.tar.gz` file that contains the version. This can be done with the following command:
63
+
64
+ ```bash
65
+ # Tar GZ the plugin
66
+ tar -czvf my-perceptor-0.0.1.tar.gz my-perceptor
67
+ ```
@@ -0,0 +1,12 @@
1
+ [project]
2
+ name = "{{NAME}}"
3
+ version = "0.1.0"
4
+ description = "{{DESCRIPTION}}"
5
+ authors = [{ name = "John Doe", email = "john.doe@composabl.com" }]
6
+ dependencies = [
7
+ "composabl-core{{COMPOSABL_DEV}}{{COMPOSABL_CORE_VERSION}}",
8
+ ]
9
+
10
+ [composabl]
11
+ type = "skill-controller"
12
+ entrypoint = "{{NAME_MODULE}}.controller:Controller"
@@ -0,0 +1,3 @@
1
+ # Copyright (C) Composabl, Inc - All Rights Reserved
2
+ # Unauthorized copying of this file, via any medium is strictly prohibited
3
+ # Proprietary and confidential
@@ -0,0 +1,40 @@
1
+ # Copyright (C) Composabl, Inc - All Rights Reserved
2
+ # Unauthorized copying of this file, via any medium is strictly prohibited
3
+ # Proprietary and confidential
4
+
5
+ from random import randint
6
+ from typing import Dict, List
7
+
8
+ from composabl_core import SkillController
9
+
10
+
11
+ class Controller(SkillController):
12
+ """
13
+ We start at 10 reward and count down to 0 the goal is that the agent stays
14
+ above or equal to 0 this means it learned to cound +1 each time
15
+ """
16
+
17
+ def __init__(self, *args, **kwargs):
18
+ self.past_obs = None
19
+ self.counter = 10
20
+ self.sensor_name = "counter"
21
+
22
+ async def compute_action(self, transformed_sensors: Dict, action) -> List[float]:
23
+ # generate a random action between -5 and 5
24
+ action = [randint(-5, 5)]
25
+ return action
26
+
27
+ async def compute_success_criteria(self, transformed_sensors: Dict, action) -> bool:
28
+ return bool(transformed_sensors[self.sensor_name] >= 10)
29
+
30
+ async def compute_termination(self, transformed_sensors: Dict, action) -> bool:
31
+ return bool(transformed_sensors[self.sensor_name] <= -10)
32
+
33
+ async def transform_sensors(self, sensors, action) -> str:
34
+ return sensors
35
+
36
+ async def transform_action(self, transformed_sensors: Dict, action) -> float:
37
+ return action
38
+
39
+ async def filtered_sensor_space(self) -> List[str]:
40
+ return ["counter"]
@@ -0,0 +1,67 @@
1
+ # README
2
+
3
+ This is a template for creating a new Perceptor. A Perceptor is a component that is responsible for processing data and returning a result. This can be used for example in a Machine Learning model, where the Perceptor is responsible for processing the data and returning the prediction.
4
+
5
+ ## Tree Structure
6
+
7
+ The template is structured as follows:
8
+
9
+ ```bash
10
+ my-perceptor/ # Root folder
11
+ ├── my_perceptor/ # Main package folder
12
+ │ ├── __init__.py # Package init file
13
+ │ └── perceptor.py # Main perceptor file
14
+ ├── pyproject.toml # Project configuration, containing [composabl]
15
+ ```
16
+
17
+ ## PyProject [composabl] Section
18
+
19
+ We add the `[composabl]` section to the `pyproject.toml` file to specify the type of component we are creating as well as its entrypoint. This is used by the Composabl CLI to determine the type of
20
+ component and how to handle it.
21
+
22
+ Example:
23
+
24
+ ```
25
+ [composabl]
26
+ type = "teacher"
27
+ entrypoint = "my_perceptor.perceptor:MyPerceptor"
28
+ ```
29
+
30
+ ## Development
31
+
32
+ To work on the Perceptor, you can simply create a temporary file or main file that starts up and executes the `compute` method of the portable Perceptor. Example, we can create a `test.py` file with:
33
+
34
+ ```python
35
+ from composabl_perceptor_my_perceptor.perceptor import MyPerceptor
36
+
37
+
38
+ async def start():
39
+ p = MyPerceptor()
40
+ res = await t.compute(None, [1.0])
41
+ print(res)
42
+
43
+
44
+ if __name__ == "__main__":
45
+ import asyncio
46
+
47
+ asyncio.run(start())
48
+ ```
49
+
50
+ Which we can then run with
51
+
52
+ ```bash
53
+ # Install the module
54
+ pip install -e my-perceptor
55
+
56
+ # Run the test file
57
+ python my-perceptor/test.py
58
+ ```
59
+
60
+ ### Preparing for Upload
61
+
62
+ Once we are ready for uploading, we can create a `.tar.gz` file that contains the version. This can be done with the following command:
63
+
64
+ ```bash
65
+ # Tar GZ the plugin
66
+ tar -czvf my-perceptor-0.0.1.tar.gz my-perceptor
67
+ ```
@@ -0,0 +1,12 @@
1
+ [project]
2
+ name = "{{NAME}}"
3
+ version = "0.1.0"
4
+ description = "{{DESCRIPTION}}"
5
+ authors = [{ name = "John Doe", email = "john.doe@composabl.com" }]
6
+ dependencies = [
7
+ "composabl-core{{COMPOSABL_DEV}}{{COMPOSABL_CORE_VERSION}}",
8
+ ]
9
+
10
+ [composabl]
11
+ type = "skill-coordinated-population"
12
+ entrypoint = "{{NAME_MODULE}}.coach:Coach"
@@ -0,0 +1,3 @@
1
+ # Copyright (C) Composabl, Inc - All Rights Reserved
2
+ # Unauthorized copying of this file, via any medium is strictly prohibited
3
+ # Proprietary and confidential
@@ -0,0 +1,70 @@
1
+ # Copyright (C) Composabl, Inc - All Rights Reserved
2
+ # Unauthorized copying of this file, via any medium is strictly prohibited
3
+ # Proprietary and confidential
4
+
5
+ import math
6
+ from typing import Dict, List
7
+
8
+ from composabl_core.agent.skill.skill_coach import SkillCoach
9
+
10
+
11
+ class Coach(SkillCoach):
12
+ """
13
+ We start at 10 reward and count down to 0 the goal is that the agent stays
14
+ above or equal to 0 this means it learned to cound +1 each time
15
+ """
16
+
17
+ def __init__(self, *args, **kwargs):
18
+ self.past_obs = None
19
+ self.counter = 10
20
+ self.sensor_name = "counter"
21
+
22
+ async def compute_reward(self, transformed_sensors: Dict, action, sim_reward):
23
+ """
24
+ The reward increases the closer it gets to 10, but decreases the
25
+ further it gets from 10 it decreases faster the further it gets
26
+ note: we do this through a piecewise function, where the reward is
27
+ 100 if the counter is 10 and 0 if the counter is 0 everything above
28
+ 10 gets a steep decrease and everything below 10 gets a small increase
29
+ ASCII of the Piecewise Graph
30
+ ***********
31
+ ***** ***
32
+ *** **
33
+ ** **
34
+ *** **
35
+ * *
36
+ **
37
+ *
38
+ *
39
+ *
40
+ """
41
+ counter = transformed_sensors[self.sensor_name]
42
+
43
+ # Small build up if < 10
44
+ # given by e^(counter - 10) + 100
45
+ if counter < 10:
46
+ return math.exp(counter - 10) + 100
47
+ # else steep decent after max reward
48
+ # given by -2 * e^(-|counter - 10|) + 100
49
+ else:
50
+ return -2 * math.exp(-abs(counter - 10)) + 100
51
+
52
+ async def compute_action_mask(
53
+ self, transformed_sensors: Dict, action
54
+ ) -> List[bool]:
55
+ return None
56
+
57
+ async def compute_success_criteria(self, transformed_sensors: Dict, action) -> bool:
58
+ return bool(transformed_sensors[self.sensor_name] >= 10)
59
+
60
+ async def compute_termination(self, transformed_sensors: Dict, action) -> bool:
61
+ return bool(transformed_sensors[self.sensor_name] <= -10)
62
+
63
+ async def transform_sensors(self, sensors, action) -> str:
64
+ return sensors
65
+
66
+ async def transform_action(self, transformed_sensors: Dict, action) -> float:
67
+ return action
68
+
69
+ async def filtered_sensor_space(self) -> List[str]:
70
+ return ["counter"]