safenax 0.4.3__tar.gz → 0.4.4__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.
- {safenax-0.4.3 → safenax-0.4.4}/PKG-INFO +1 -1
- {safenax-0.4.3 → safenax-0.4.4}/pyproject.toml +1 -1
- {safenax-0.4.3 → safenax-0.4.4}/safenax/eco_ant/eco_ant_v1.py +4 -4
- {safenax-0.4.3 → safenax-0.4.4}/safenax/eco_ant/eco_ant_v2.py +12 -4
- {safenax-0.4.3 → safenax-0.4.4}/tests/test_eco_ant_v1.py +7 -12
- {safenax-0.4.3 → safenax-0.4.4}/tests/test_eco_ant_v2.py +4 -10
- {safenax-0.4.3 → safenax-0.4.4}/uv.lock +1 -1
- {safenax-0.4.3 → safenax-0.4.4}/.gitignore +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/.pre-commit-config.yaml +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/.python-version +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/LICENSE +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/PUBLISHING.md +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/README.md +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/safenax/__init__.py +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/safenax/eco_ant/__init__.py +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/safenax/fragile_ant.py +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/safenax/frozen_lake.py +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/safenax/portfolio_optimization/__init__.py +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/safenax/portfolio_optimization/po_crypto.py +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/safenax/portfolio_optimization/po_garch.py +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/safenax/wrappers/__init__.py +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/safenax/wrappers/brax.py +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/safenax/wrappers/log.py +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/scripts/setup_dev.sh +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/tests/__init__.py +0 -0
- {safenax-0.4.3 → safenax-0.4.4}/tests/test_frozen_lake.py +0 -0
|
@@ -27,7 +27,8 @@ class EcoAntV1(Ant):
|
|
|
27
27
|
|
|
28
28
|
def step(self, state: State, action: jax.Array) -> State:
|
|
29
29
|
# 1. RETRIEVE BATTERY FROM CURRENT OBSERVATION
|
|
30
|
-
|
|
30
|
+
current_battery_pct = state.obs[-1]
|
|
31
|
+
current_battery = current_battery_pct * self.battery_limit
|
|
31
32
|
|
|
32
33
|
# 2. HANDLE STOCHASTICITY
|
|
33
34
|
_, noise_key = jax.random.split(state.info["rng"])
|
|
@@ -47,8 +48,7 @@ class EcoAntV1(Ant):
|
|
|
47
48
|
# 4. PHYSICS STEP
|
|
48
49
|
next_state = super().step(state, noisy_action)
|
|
49
50
|
|
|
50
|
-
# 5.
|
|
51
|
-
# Termination: OR with existing done condition
|
|
51
|
+
# 5. Termination: OR with existing done condition
|
|
52
52
|
new_done = jnp.max(jnp.array([next_state.done, is_empty]))
|
|
53
53
|
|
|
54
54
|
# Cost Signal: 1.0 if battery died this step
|
|
@@ -61,7 +61,7 @@ class EcoAntV1(Ant):
|
|
|
61
61
|
**next_state.info,
|
|
62
62
|
"rng": noise_key,
|
|
63
63
|
"cost": cost,
|
|
64
|
-
"battery":
|
|
64
|
+
"battery": new_battery,
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
return next_state.replace(obs=new_obs, done=new_done, info=new_info)
|
|
@@ -27,7 +27,8 @@ class EcoAntV2(Ant):
|
|
|
27
27
|
|
|
28
28
|
def step(self, state: State, action: jax.Array) -> State:
|
|
29
29
|
# 1. RETRIEVE BATTERY FROM CURRENT OBSERVATION
|
|
30
|
-
|
|
30
|
+
current_battery_pct = state.obs[-1]
|
|
31
|
+
current_battery = current_battery_pct * self.battery_limit
|
|
31
32
|
|
|
32
33
|
# 2. HANDLE STOCHASTICITY
|
|
33
34
|
_, noise_key = jax.random.split(state.info["rng"])
|
|
@@ -42,6 +43,7 @@ class EcoAntV2(Ant):
|
|
|
42
43
|
# Check constraints
|
|
43
44
|
is_empty = new_battery <= 0.0
|
|
44
45
|
new_battery = jnp.maximum(new_battery, 0.0)
|
|
46
|
+
new_battery_pct = new_battery / self.battery_limit
|
|
45
47
|
|
|
46
48
|
# 4. PHYSICS STEP
|
|
47
49
|
next_state = super().step(state, noisy_action)
|
|
@@ -49,18 +51,24 @@ class EcoAntV2(Ant):
|
|
|
49
51
|
# 5. Termination: OR with existing done condition
|
|
50
52
|
new_done = jnp.max(jnp.array([next_state.done, is_empty]))
|
|
51
53
|
|
|
54
|
+
# Observation: Append the new battery level to the observation vector
|
|
55
|
+
new_obs = jnp.concatenate([next_state.obs, jnp.array([new_battery_pct])])
|
|
56
|
+
|
|
52
57
|
new_info = {
|
|
53
58
|
**next_state.info,
|
|
54
59
|
"rng": noise_key,
|
|
55
60
|
"cost": energy_used,
|
|
56
|
-
"battery":
|
|
61
|
+
"battery": new_battery,
|
|
57
62
|
}
|
|
58
63
|
|
|
59
|
-
return next_state.replace(done=new_done, info=new_info)
|
|
64
|
+
return next_state.replace(obs=new_obs, done=new_done, info=new_info)
|
|
60
65
|
|
|
61
66
|
def reset(self, rng: jax.Array) -> State:
|
|
62
67
|
state = super().reset(rng)
|
|
63
68
|
|
|
69
|
+
# Append initial battery to observation
|
|
70
|
+
new_obs = jnp.concatenate([state.obs, jnp.array([1.0])])
|
|
71
|
+
|
|
64
72
|
# Initialize info
|
|
65
73
|
new_info = {
|
|
66
74
|
**state.info,
|
|
@@ -69,7 +77,7 @@ class EcoAntV2(Ant):
|
|
|
69
77
|
"battery": jnp.array(self.battery_limit),
|
|
70
78
|
}
|
|
71
79
|
|
|
72
|
-
return state.replace(info=new_info)
|
|
80
|
+
return state.replace(obs=new_obs, info=new_info)
|
|
73
81
|
|
|
74
82
|
|
|
75
83
|
envs.register_environment(EcoAntV2.name, EcoAntV2)
|
|
@@ -87,6 +87,7 @@ def test_termination_and_cost(env: EcoAntV1, key: jax.Array):
|
|
|
87
87
|
# 1. Manually set battery to near-death in INFO (not Obs)
|
|
88
88
|
# The environment logic reads current_battery = state.info["battery"]
|
|
89
89
|
# So to test termination, we must hack the info dict.
|
|
90
|
+
env.battery_limit = 0.1 # Temporarily set limit low for test
|
|
90
91
|
new_info = state.info.copy()
|
|
91
92
|
new_info["battery"] = jnp.array(0.1)
|
|
92
93
|
|
|
@@ -102,7 +103,7 @@ def test_termination_and_cost(env: EcoAntV1, key: jax.Array):
|
|
|
102
103
|
assert next_state.obs[-1] <= 0.0
|
|
103
104
|
|
|
104
105
|
# Check Raw Battery Floor
|
|
105
|
-
assert next_state.info["battery"] ==
|
|
106
|
+
assert next_state.info["battery"] == 0.0
|
|
106
107
|
|
|
107
108
|
# Check Cost Signal
|
|
108
109
|
assert next_state.info["cost"] == 1.0
|
|
@@ -143,7 +144,7 @@ def test_wrapper_step_api(wrapped_env: BraxToGymnaxWrapper, key: jax.Array):
|
|
|
143
144
|
assert info["battery"] < 10.0
|
|
144
145
|
|
|
145
146
|
|
|
146
|
-
def test_wrapper_autoreset_logic(
|
|
147
|
+
def test_wrapper_autoreset_logic(key: jax.Array):
|
|
147
148
|
"""
|
|
148
149
|
CRITICAL TEST: Verifies AutoResetWrapper behavior on battery death.
|
|
149
150
|
|
|
@@ -154,16 +155,10 @@ def test_wrapper_autoreset_logic(wrapped_env: BraxToGymnaxWrapper, key: jax.Arra
|
|
|
154
155
|
- Returns `done=True` (signaling the end of the dying episode)
|
|
155
156
|
- Returns `obs` from the NEW reset state (Battery=1.0, not 0.0!)
|
|
156
157
|
"""
|
|
158
|
+
brax_env = EcoAntV1(battery_limit=0.1, noise_scale=0.1)
|
|
159
|
+
wrapped_env = BraxToGymnaxWrapper(env=brax_env, episode_length=10)
|
|
157
160
|
obs, state = wrapped_env.reset(key)
|
|
158
161
|
|
|
159
|
-
# 1. Force near-death
|
|
160
|
-
new_info = state.info.copy()
|
|
161
|
-
new_info["battery"] = jnp.array(0.1)
|
|
162
|
-
# We must also update 'obs' because the Wrapper might use 'obs' for something,
|
|
163
|
-
# though usually physics uses 'state'. Let's keep obs as is (1.0) to prove
|
|
164
|
-
# the physics engine checks 'info', not 'obs'.
|
|
165
|
-
state = state.replace(info=new_info)
|
|
166
|
-
|
|
167
162
|
# 2. Kill the agent
|
|
168
163
|
action = jnp.ones(wrapped_env.action_size)
|
|
169
164
|
next_obs, next_state, reward, done, info = wrapped_env.step(key, state, action)
|
|
@@ -176,7 +171,7 @@ def test_wrapper_autoreset_logic(wrapped_env: BraxToGymnaxWrapper, key: jax.Arra
|
|
|
176
171
|
# B. The 'info' contains the terminal cost of the DEAD agent
|
|
177
172
|
# But includes the battery reset
|
|
178
173
|
assert info["cost"] == 1.0
|
|
179
|
-
assert info["battery"] ==
|
|
174
|
+
assert info["battery"] == 0.0
|
|
180
175
|
|
|
181
176
|
# C. The 'next_obs' is from the NEW alive agent (AutoReset happened)
|
|
182
177
|
# The observation returned is for the *next* step.
|
|
@@ -184,4 +179,4 @@ def test_wrapper_autoreset_logic(wrapped_env: BraxToGymnaxWrapper, key: jax.Arra
|
|
|
184
179
|
|
|
185
180
|
# D. The 'next_state' is the NEW alive state
|
|
186
181
|
assert next_state.info["cost"] == 1.0
|
|
187
|
-
assert next_state.info["battery"] ==
|
|
182
|
+
assert next_state.info["battery"] == 0.0
|
|
@@ -78,18 +78,12 @@ def test_battery_depletion_in_info(env: EcoAntV2, key: jax.Array):
|
|
|
78
78
|
assert jnp.allclose(start_battery - energy_used, current_battery, atol=1e-5)
|
|
79
79
|
|
|
80
80
|
|
|
81
|
-
def test_termination_logic(
|
|
81
|
+
def test_termination_logic(key: jax.Array):
|
|
82
82
|
"""
|
|
83
83
|
Verifies that the episode terminates when info['battery'] hits zero.
|
|
84
84
|
"""
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
# 1. Manually set battery to be very low in the info dict
|
|
88
|
-
# This simulates a "near death" state
|
|
89
|
-
low_battery_info = state.info.copy()
|
|
90
|
-
low_battery_info["battery"] = jnp.array(0.1)
|
|
91
|
-
|
|
92
|
-
near_death_state = state.replace(info=low_battery_info)
|
|
85
|
+
env = EcoAntV2(battery_limit=0.1, noise_scale=0.1)
|
|
86
|
+
near_death_state = env.reset(key)
|
|
93
87
|
|
|
94
88
|
# 2. Take a large step to consume > 0.1 energy
|
|
95
89
|
# Action of 1.0s usually consumes ~4.0 energy
|
|
@@ -100,7 +94,7 @@ def test_termination_logic(env: EcoAntV2, key: jax.Array):
|
|
|
100
94
|
assert next_state.done == 1.0
|
|
101
95
|
|
|
102
96
|
# 4. Verify Battery Floor
|
|
103
|
-
assert next_state.info["battery"] ==
|
|
97
|
+
assert next_state.info["battery"] == 0.0
|
|
104
98
|
|
|
105
99
|
|
|
106
100
|
def test_stochasticity_impact(env: EcoAntV2, key: jax.Array):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|