dsh-eval-guard 0.7.4 → 0.7.5

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.
Files changed (30) hide show
  1. package/ISSUES.md +2 -2
  2. package/README.md +1 -1
  3. package/assets/neural-pendulum/SPEC.md +2 -0
  4. package/assets/neural-pendulum/TASK.md +3 -1
  5. package/assets/neural-pendulum/sim.cpp +25 -3
  6. package/assets/neural-pendulum/sim_agent +0 -0
  7. package/assets/neural-pendulum/sim_eval +0 -0
  8. package/assets/neural-pendulum/workspace.zip +0 -0
  9. package/neural-pendulum-eval/README.md +4 -2
  10. package/neural-pendulum-eval/run_eval.py +3 -1
  11. package/neural-pendulum-eval/sim_eval +0 -0
  12. package/package.json +1 -1
  13. package/assets/neural-pendulum/rl-feasibility/README.md +0 -60
  14. package/assets/neural-pendulum/rl-feasibility/RESULTS.md +0 -370
  15. package/assets/neural-pendulum/rl-feasibility/evaluate.py +0 -107
  16. package/assets/neural-pendulum/rl-feasibility/finalize_run.py +0 -168
  17. package/assets/neural-pendulum/rl-feasibility/models.py +0 -124
  18. package/assets/neural-pendulum/rl-feasibility/obs.py +0 -205
  19. package/assets/neural-pendulum/rl-feasibility/plot_selected.py +0 -55
  20. package/assets/neural-pendulum/rl-feasibility/reference_controller.py +0 -112
  21. package/assets/neural-pendulum/rl-feasibility/results/curves_selected.png +0 -0
  22. package/assets/neural-pendulum/rl-feasibility/results/reference_controller.json +0 -417
  23. package/assets/neural-pendulum/rl-feasibility/results/summary.json +0 -1599
  24. package/assets/neural-pendulum/rl-feasibility/results/table.md +0 -39
  25. package/assets/neural-pendulum/rl-feasibility/sim.py +0 -324
  26. package/assets/neural-pendulum/rl-feasibility/summarize.py +0 -175
  27. package/assets/neural-pendulum/rl-feasibility/task.py +0 -342
  28. package/assets/neural-pendulum/rl-feasibility/test_contract.py +0 -188
  29. package/assets/neural-pendulum/rl-feasibility/train_ppo.py +0 -403
  30. package/assets/neural-pendulum/rl-feasibility/train_sac.py +0 -406
@@ -1,112 +0,0 @@
1
- """Non-RL feasibility check: a pole-placement stabiliser around upright.
2
-
3
- This is NOT a learned policy and NOT part of the RL results. It answers a
4
- single question: is the upright hold physically reachable with the fixed
5
- torque mapping (tau1, -tau3, tau3) and |u| <= 1?
6
-
7
- The controller uses privileged full state (theta and the simulator omega),
8
- so it is an upper bound / existence proof only. It is deliberately simple:
9
- u = clip(-K [wrap(theta-pi); omega], -1, 1)
10
- with K from pole placement on the linearisation at upright.
11
-
12
- Writes results/reference_controller.json.
13
- """
14
- from __future__ import annotations
15
-
16
- import json
17
- from pathlib import Path
18
-
19
- import numpy as np
20
- from scipy.signal import place_poles
21
-
22
- from sim import EPISODE_STEPS, N_ACT, Params, PendulumSim, make_torch_consts
23
- from task import EVAL_OMEGA0, EVAL_THETA0, NumpyTracker, sample_train_init, wrap_to_pi
24
-
25
- ROOT = Path(__file__).resolve().parent
26
-
27
-
28
- def design(p: Params, poles=(-5.0, -6.0, -7.0, -8.0, -9.0, -10.0)):
29
- M = p.A
30
- K = np.diag(p.g * p.gvec)
31
- Minv = np.linalg.inv(M)
32
- B = np.zeros((3, 2))
33
- B[0, 0] = 1.0
34
- B[1, 1] = -1.0
35
- B[2, 1] = 1.0
36
- Be = Minv @ B
37
- A = np.zeros((6, 6))
38
- A[:3, 3:] = np.eye(3)
39
- A[3:, :3] = Minv @ K
40
- B6 = np.vstack([np.zeros((3, 2)), Be])
41
- res = place_poles(A, B6, np.asarray(poles, dtype=float))
42
- return res.gain_matrix
43
-
44
-
45
- def rollout(p, gain, theta0, omega0, episode_steps=EPISODE_STEPS,
46
- alpha=0.5):
47
- sim = PendulumSim(p, episode_steps=episode_steps)
48
- tr = NumpyTracker()
49
- theta = sim.reset(theta0, omega0)
50
- tr.reset()
51
- sat = 0
52
- uf = np.zeros(2)
53
- for _ in range(episode_steps):
54
- x = np.r_[wrap_to_pi(theta - np.pi), sim._omega]
55
- raw = np.clip(-gain @ x, -1.0, 1.0)
56
- # first-order low-pass on the torque command: the unfiltered
57
- # pole-placement controller chatters at 100 Hz and only holds ~1 s.
58
- uf = alpha * raw + (1.0 - alpha) * uf
59
- sat += int(np.abs(uf).max() > 1.0)
60
- theta = sim.step(uf)
61
- tr.update(theta, 0.0)
62
- summ = tr.summary()
63
- return dict(t_can=float(summ["t_can"]),
64
- ever_up=float(summ["ever_up"]),
65
- final_ang_err=float(np.abs(wrap_to_pi(theta - np.pi)).max()),
66
- sat_frac=float(sat / episode_steps),
67
- final_theta=theta.tolist())
68
-
69
-
70
- def main():
71
- p = Params()
72
- gain = design(p)
73
- # This is a LOCAL stabiliser: start near upright (theta = pi + offset).
74
- fixed_theta0 = np.pi + EVAL_THETA0
75
- fixed = rollout(p, gain, fixed_theta0, EVAL_OMEGA0)
76
- rng = np.random.default_rng(0)
77
- th = np.pi + rng.uniform(-0.05, 0.05, size=(32, 3))
78
- om = np.zeros((32, 3))
79
- rows = [rollout(p, gain, th[i], om[i]) for i in range(th.shape[0])]
80
- tc = np.array([r["t_can"] for r in rows])
81
- out = dict(
82
- note=("Non-RL existence check. Pole-placement stabiliser using "
83
- "privileged full state (theta and simulator omega); not a "
84
- "learned policy. Shows whether the upright hold is physically "
85
- "reachable with the fixed torque mapping. The torque command is "
86
- "low-pass filtered (alpha=0.5); the unfiltered controller "
87
- "chatters and only holds ~1 s."),
88
- poles=[-5.0, -6.0, -7.0, -8.0, -9.0, -10.0],
89
- action_filter_alpha=0.5,
90
- gain=gain.tolist(),
91
- fixed_start=dict(theta0=fixed_theta0.tolist(),
92
- offset_from_upright=EVAL_THETA0.tolist(),
93
- omega0=EVAL_OMEGA0.tolist(), **fixed),
94
- random_starts=dict(n=len(rows), success_rate=float((tc >= 10.0).mean()),
95
- mean_t_can=float(tc.mean()),
96
- median_t_can=float(np.median(tc)),
97
- max_t_can=float(tc.max()),
98
- rows=rows),
99
- )
100
- out_path = ROOT / "results" / "reference_controller.json"
101
- with open(out_path, "w") as f:
102
- json.dump(out, f, indent=2)
103
- print(json.dumps(dict(fixed_t_can=fixed["t_can"],
104
- fixed_final_err=fixed["final_ang_err"],
105
- fixed_sat=fixed["sat_frac"],
106
- random_success=out["random_starts"]["success_rate"],
107
- random_mean_t_can=out["random_starts"]["mean_t_can"]),
108
- indent=2))
109
-
110
-
111
- if __name__ == "__main__":
112
- main()
@@ -1,417 +0,0 @@
1
- {
2
- "note": "Non-RL existence check. Pole-placement stabiliser using privileged full state (theta and simulator omega); not a learned policy. Shows whether the upright hold is physically reachable with the fixed torque mapping. The torque command is low-pass filtered (alpha=0.5); the unfiltered controller chatters and only holds ~1 s.",
3
- "poles": [
4
- -5.0,
5
- -6.0,
6
- -7.0,
7
- -8.0,
8
- -9.0,
9
- -10.0
10
- ],
11
- "action_filter_alpha": 0.5,
12
- "gain": [
13
- [
14
- -17.82008272259022,
15
- -90.53020345591291,
16
- -37.60973879998583,
17
- -17.574950427476214,
18
- -21.006026390694455,
19
- -9.992697352896354
20
- ],
21
- [
22
- 3.4221790257027664,
23
- 6.7210733064834685,
24
- 6.823263521680083,
25
- 1.9296331848889634,
26
- 2.183847052498074,
27
- 1.386819759832599
28
- ]
29
- ],
30
- "fixed_start": {
31
- "theta0": [
32
- 3.154592653589793,
33
- 3.133592653589793,
34
- 3.162592653589793
35
- ],
36
- "offset_from_upright": [
37
- 0.013,
38
- -0.008,
39
- 0.021
40
- ],
41
- "omega0": [
42
- 0.0,
43
- 0.0,
44
- 0.0
45
- ],
46
- "t_can": 29.99000000000189,
47
- "ever_up": 1.0,
48
- "final_ang_err": 2.1760371282653068e-14,
49
- "sat_frac": 0.0,
50
- "final_theta": [
51
- 3.141592653589815,
52
- 3.141592653589791,
53
- 3.141592653589787
54
- ]
55
- },
56
- "random_starts": {
57
- "n": 32,
58
- "success_rate": 1.0,
59
- "mean_t_can": 24.79125000000196,
60
- "median_t_can": 27.840000000001897,
61
- "max_t_can": 29.99000000000189,
62
- "rows": [
63
- {
64
- "t_can": 29.99000000000189,
65
- "ever_up": 1.0,
66
- "final_ang_err": 8.43769498715119e-15,
67
- "sat_frac": 0.0,
68
- "final_theta": [
69
- 3.1415926535898016,
70
- 3.1415926535897905,
71
- 3.1415926535897936
72
- ]
73
- },
74
- {
75
- "t_can": 18.890000000002082,
76
- "ever_up": 1.0,
77
- "final_ang_err": 5.595524044110789e-14,
78
- "sat_frac": 0.0,
79
- "final_theta": [
80
- 3.141592653589849,
81
- 3.1415926535897984,
82
- 3.141592653589774
83
- ]
84
- },
85
- {
86
- "t_can": 18.0500000000021,
87
- "ever_up": 1.0,
88
- "final_ang_err": 5.3290705182007514e-14,
89
- "sat_frac": 0.0,
90
- "final_theta": [
91
- 3.1415926535898464,
92
- 3.1415926535897984,
93
- 3.141592653589776
94
- ]
95
- },
96
- {
97
- "t_can": 11.180000000001748,
98
- "ever_up": 1.0,
99
- "final_ang_err": 5.717648576819556e-12,
100
- "sat_frac": 0.0,
101
- "final_theta": [
102
- 3.1415926535840755,
103
- 3.1415926535880225,
104
- 3.141592653591231
105
- ]
106
- },
107
- {
108
- "t_can": 29.99000000000189,
109
- "ever_up": 1.0,
110
- "final_ang_err": 4.707345624410664e-14,
111
- "sat_frac": 0.0,
112
- "final_theta": [
113
- 3.14159265358984,
114
- 3.141592653589798,
115
- 3.1415926535897785
116
- ]
117
- },
118
- {
119
- "t_can": 21.580000000002023,
120
- "ever_up": 1.0,
121
- "final_ang_err": 2.708944180085382e-14,
122
- "sat_frac": 0.0,
123
- "final_theta": [
124
- 3.141592653589766,
125
- 3.141592653589795,
126
- 3.141592653589803
127
- ]
128
- },
129
- {
130
- "t_can": 28.81000000000189,
131
- "ever_up": 1.0,
132
- "final_ang_err": 1.4210854715202004e-14,
133
- "sat_frac": 0.0,
134
- "final_theta": [
135
- 3.141592653589779,
136
- 3.141592653589796,
137
- 3.1415926535897962
138
- ]
139
- },
140
- {
141
- "t_can": 29.99000000000189,
142
- "ever_up": 1.0,
143
- "final_ang_err": 4.085620730620576e-14,
144
- "sat_frac": 0.0,
145
- "final_theta": [
146
- 3.141592653589834,
147
- 3.1415926535897913,
148
- 3.1415926535897762
149
- ]
150
- },
151
- {
152
- "t_can": 29.99000000000189,
153
- "ever_up": 1.0,
154
- "final_ang_err": 2.5757174171303632e-14,
155
- "sat_frac": 0.0,
156
- "final_theta": [
157
- 3.1415926535897674,
158
- 3.141592653589791,
159
- 3.141592653589812
160
- ]
161
- },
162
- {
163
- "t_can": 16.970000000002123,
164
- "ever_up": 1.0,
165
- "final_ang_err": 3.572708751065079e-08,
166
- "sat_frac": 0.0,
167
- "final_theta": [
168
- 3.1415926893168806,
169
- 3.1415926726829873,
170
- 3.1415926548413156
171
- ]
172
- },
173
- {
174
- "t_can": 14.390000000002178,
175
- "ever_up": 1.0,
176
- "final_ang_err": 5.062616992290714e-14,
177
- "sat_frac": 0.0,
178
- "final_theta": [
179
- 3.1415926535898437,
180
- 3.141592653589805,
181
- 3.141592653589778
182
- ]
183
- },
184
- {
185
- "t_can": 29.99000000000189,
186
- "ever_up": 1.0,
187
- "final_ang_err": 3.952393967665557e-14,
188
- "sat_frac": 0.0,
189
- "final_theta": [
190
- 3.1415926535897536,
191
- 3.141592653589795,
192
- 3.141592653589809
193
- ]
194
- },
195
- {
196
- "t_can": 24.62000000000196,
197
- "ever_up": 1.0,
198
- "final_ang_err": 3.952393967665557e-14,
199
- "sat_frac": 0.0,
200
- "final_theta": [
201
- 3.1415926535898326,
202
- 3.1415926535897913,
203
- 3.1415926535897767
204
- ]
205
- },
206
- {
207
- "t_can": 29.99000000000189,
208
- "ever_up": 1.0,
209
- "final_ang_err": 4.218847493575595e-14,
210
- "sat_frac": 0.0,
211
- "final_theta": [
212
- 3.1415926535898353,
213
- 3.1415926535897922,
214
- 3.141592653589776
215
- ]
216
- },
217
- {
218
- "t_can": 29.99000000000189,
219
- "ever_up": 1.0,
220
- "final_ang_err": 3.907985046680551e-14,
221
- "sat_frac": 0.0,
222
- "final_theta": [
223
- 3.141592653589832,
224
- 3.1415926535897922,
225
- 3.141592653589779
226
- ]
227
- },
228
- {
229
- "t_can": 17.260000000002115,
230
- "ever_up": 1.0,
231
- "final_ang_err": 3.79389852867007e-11,
232
- "sat_frac": 0.0,
233
- "final_theta": [
234
- 3.141592653592213,
235
- 3.141592653561257,
236
- 3.141592653551854
237
- ]
238
- },
239
- {
240
- "t_can": 25.760000000001938,
241
- "ever_up": 1.0,
242
- "final_ang_err": 1.5987211554602254e-14,
243
- "sat_frac": 0.0,
244
- "final_theta": [
245
- 3.141592653589809,
246
- 3.1415926535897936,
247
- 3.1415926535897833
248
- ]
249
- },
250
- {
251
- "t_can": 27.260000000001906,
252
- "ever_up": 1.0,
253
- "final_ang_err": 2.6201263381153694e-14,
254
- "sat_frac": 0.0,
255
- "final_theta": [
256
- 3.141592653589767,
257
- 3.141592653589795,
258
- 3.141592653589802
259
- ]
260
- },
261
- {
262
- "t_can": 14.380000000002179,
263
- "ever_up": 1.0,
264
- "final_ang_err": 7.682743330406083e-14,
265
- "sat_frac": 0.0,
266
- "final_theta": [
267
- 3.1415926535897163,
268
- 3.1415926535897825,
269
- 3.141592653589821
270
- ]
271
- },
272
- {
273
- "t_can": 24.21000000000197,
274
- "ever_up": 1.0,
275
- "final_ang_err": 4.574118861455645e-14,
276
- "sat_frac": 0.0,
277
- "final_theta": [
278
- 3.141592653589839,
279
- 3.1415926535897922,
280
- 3.141592653589775
281
- ]
282
- },
283
- {
284
- "t_can": 25.350000000001945,
285
- "ever_up": 1.0,
286
- "final_ang_err": 3.3306690738754696e-14,
287
- "sat_frac": 0.0,
288
- "final_theta": [
289
- 3.14159265358976,
290
- 3.1415926535897953,
291
- 3.141592653589806
292
- ]
293
- },
294
- {
295
- "t_can": 19.280000000002076,
296
- "ever_up": 1.0,
297
- "final_ang_err": 1.865174681370263e-14,
298
- "sat_frac": 0.0,
299
- "final_theta": [
300
- 3.1415926535898118,
301
- 3.14159265358979,
302
- 3.141592653589787
303
- ]
304
- },
305
- {
306
- "t_can": 29.99000000000189,
307
- "ever_up": 1.0,
308
- "final_ang_err": 3.5083047578154947e-14,
309
- "sat_frac": 0.0,
310
- "final_theta": [
311
- 3.141592653589758,
312
- 3.1415926535897953,
313
- 3.1415926535898073
314
- ]
315
- },
316
- {
317
- "t_can": 29.89000000000189,
318
- "ever_up": 1.0,
319
- "final_ang_err": 1.3322676295501878e-14,
320
- "sat_frac": 0.0,
321
- "final_theta": [
322
- 3.1415926535898064,
323
- 3.14159265358979,
324
- 3.1415926535897896
325
- ]
326
- },
327
- {
328
- "t_can": 28.420000000001888,
329
- "ever_up": 1.0,
330
- "final_ang_err": 2.353672812205332e-14,
331
- "sat_frac": 0.0,
332
- "final_theta": [
333
- 3.1415926535897696,
334
- 3.1415926535897962,
335
- 3.1415926535898024
336
- ]
337
- },
338
- {
339
- "t_can": 29.94000000000189,
340
- "ever_up": 1.0,
341
- "final_ang_err": 1.8207657603852567e-14,
342
- "sat_frac": 0.0,
343
- "final_theta": [
344
- 3.1415926535898113,
345
- 3.1415926535897905,
346
- 3.1415926535897873
347
- ]
348
- },
349
- {
350
- "t_can": 29.53000000000189,
351
- "ever_up": 1.0,
352
- "final_ang_err": 4.263256414560601e-14,
353
- "sat_frac": 0.0,
354
- "final_theta": [
355
- 3.1415926535898357,
356
- 3.1415926535897913,
357
- 3.1415926535897754
358
- ]
359
- },
360
- {
361
- "t_can": 29.99000000000189,
362
- "ever_up": 1.0,
363
- "final_ang_err": 4.4853010194856324e-14,
364
- "sat_frac": 0.0,
365
- "final_theta": [
366
- 3.1415926535897483,
367
- 3.141592653589794,
368
- 3.1415926535898113
369
- ]
370
- },
371
- {
372
- "t_can": 29.88000000000189,
373
- "ever_up": 1.0,
374
- "final_ang_err": 2.6201263381153694e-14,
375
- "sat_frac": 0.0,
376
- "final_theta": [
377
- 3.1415926535898193,
378
- 3.141592653589792,
379
- 3.1415926535897847
380
- ]
381
- },
382
- {
383
- "t_can": 21.020000000002035,
384
- "ever_up": 1.0,
385
- "final_ang_err": 4.1744385725905886e-14,
386
- "sat_frac": 0.0,
387
- "final_theta": [
388
- 3.141592653589835,
389
- 3.1415926535897936,
390
- 3.141592653589775
391
- ]
392
- },
393
- {
394
- "t_can": 17.920000000002105,
395
- "ever_up": 1.0,
396
- "final_ang_err": 3.998623654410949e-11,
397
- "sat_frac": 0.0,
398
- "final_theta": [
399
- 3.141592653549807,
400
- 3.141592653569871,
401
- 3.1415926535902368
402
- ]
403
- },
404
- {
405
- "t_can": 28.82000000000189,
406
- "ever_up": 1.0,
407
- "final_ang_err": 3.419486915845482e-14,
408
- "sat_frac": 0.0,
409
- "final_theta": [
410
- 3.1415926535898273,
411
- 3.1415926535897913,
412
- 3.14159265358978
413
- ]
414
- }
415
- ]
416
- }
417
- }