File size: 2,471 Bytes
168e232
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
"""The release's own promises: cards load and check, tunings cannot reach the model, the model runs, the doctor works."""
from pathlib import Path

import numpy as np
import pytest

from cablepilot.cardrun import SkillGap, apply_tuning, check
from cablepilot.core.cards import CardError, load_card_text

ROOT = Path(__file__).resolve().parents[1]
CARD = """
task: t
lineage: {parent: x, by: y, why: z}
roles: [hand, head_camera]
objects:
  a: {kind: toy, role: held, shape: block, movable: true}
  b: {kind: box, role: site, shape: open_container, movable: false}
parts:
  b.interior: {of: b, part: interior}
stages:
  - {name: s1, goals: [{pre_grasp: [hand, a]}]}
  - {name: s2, goals: [{grasp: [hand, a]}]}
  - {name: s3, goals: [{pre_inside: [a, b.interior]}]}
  - {name: s4, goals: [{release: [hand, a]}]}
done: {inside: [a, b.interior]}
"""


def test_card_checks_and_lineage():
    c = load_card_text(CARD)
    assert c.lineage == {"parent": "x", "by": "y", "why": "z"}
    assert [s for _, s in check(c)["stages"]] == ["approach", "grasp", "carry_over", "release"]
    assert "lineage" in c.to_dict()


def test_lineage_keys_are_closed():
    with pytest.raises(CardError):
        load_card_text(CARD.replace("why: z", "why: z, run: rm"))


def test_skill_gap_is_reported():
    c = load_card_text(CARD.replace("{pre_grasp: [hand, a]}", "{on_top: [a, b.interior]}"))
    with pytest.raises(SkillGap, match="on_top"):
        check(c)


def test_tuning_merges_and_avoid_only_raises():
    tc = {"params": {"weights": {"furniture": 5.0, "walls": 5.0, "xy": 4.0}, "funnel": {"k_xy": 3.0}}}
    c = load_card_text(CARD + "costs: {per_body: {cable: {avoid: 0.1}}}\n")
    out = apply_tuning(tc, c, {"params": {"funnel": {"k_xy": 2.0}}})
    assert out["params"]["funnel"]["k_xy"] == 2.0 and out["params"]["weights"]["furniture"] == 5.0   # never less


def test_model_rolls_out():
    from cablepilot.model.learned import LearnedCDPRModel
    wm = LearnedCDPRModel.load(ROOT / "weights/stringman_g1.pt", dt=0.2)
    wm.set_room(np.array([[2, 2, 2.4], [-2, 2, 2.4], [-2, -2, 2.4], [2, -2, 2.4]], float))
    x = np.zeros(14)
    x[2] = 1.2
    wm.reset_history(x, np.zeros(5))
    out = wm.rollout(None, None, np.zeros((4, 10, 5)))
    assert out.shape == (4, 10, 14)
    assert float(np.abs(out[..., 0:2]).max()) < 0.05     # holding still stays (nearly) still


def test_doctor_quick():
    from cablepilot.rig import doctor
    assert doctor(None, quick=True)["ok"]