planetbridging 0.7.0__py3-none-any.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.
@@ -0,0 +1,91 @@
1
+ """Planet Bridging — stream AI engine weights into Loom .entity checkpoints."""
2
+
3
+ from .bedrocks import BEDROCK_IDS, BEDROCK_PLANETS, BEDROCKS, BedrockInfo, STREAM_MODEL_IDS
4
+ from .bedrock_ladder import LadderResult, run_all_bedrock_ladders, run_bedrock_ladder
5
+ from .bedrock_smoke import SmokeResult, run_all_bedrock_smokes, run_bedrock_smoke
6
+ from .compare import compare_outputs, diff_label
7
+ from . import absorb
8
+ from . import engines
9
+ from .engines import EngineStreamResult
10
+ from .stream import (
11
+ StreamResult,
12
+ stream_bedrock,
13
+ stream_cnn1,
14
+ stream_cnn2,
15
+ stream_cnn3,
16
+ stream_dense,
17
+ stream_embedding,
18
+ stream_layernorm,
19
+ stream_lstm,
20
+ stream_mha,
21
+ stream_mixer,
22
+ stream_residual,
23
+ stream_rmsnorm,
24
+ stream_rnn,
25
+ stream_swiglu,
26
+ )
27
+
28
+ try:
29
+ from .welvet_infer import (
30
+ import_welvet,
31
+ infer_bedrock_entity,
32
+ infer_dense_entity,
33
+ infer_mixer_v1_entity,
34
+ print_compare_ladder,
35
+ try_infer_bedrock_entity,
36
+ WELVET_RELOAD_BEDROCKS,
37
+ WELVET_RELOAD_SKIP,
38
+ )
39
+ except ImportError: # pragma: no cover
40
+ import_welvet = None # type: ignore
41
+ infer_bedrock_entity = None # type: ignore
42
+ infer_dense_entity = None # type: ignore
43
+ infer_mixer_v1_entity = None # type: ignore
44
+ print_compare_ladder = None # type: ignore
45
+ try_infer_bedrock_entity = None # type: ignore
46
+ WELVET_RELOAD_BEDROCKS = frozenset() # type: ignore
47
+ WELVET_RELOAD_SKIP = frozenset() # type: ignore
48
+
49
+ __version__ = "0.7.0"
50
+ __all__ = [
51
+ "__version__",
52
+ "BEDROCK_IDS",
53
+ "BEDROCK_PLANETS",
54
+ "BEDROCKS",
55
+ "BedrockInfo",
56
+ "STREAM_MODEL_IDS",
57
+ "StreamResult",
58
+ "EngineStreamResult",
59
+ "SmokeResult",
60
+ "LadderResult",
61
+ "engines",
62
+ "absorb",
63
+ "run_bedrock_ladder",
64
+ "run_all_bedrock_ladders",
65
+ "stream_bedrock",
66
+ "stream_dense",
67
+ "stream_cnn1",
68
+ "stream_cnn2",
69
+ "stream_cnn3",
70
+ "stream_mha",
71
+ "stream_lstm",
72
+ "stream_rnn",
73
+ "stream_layernorm",
74
+ "stream_embedding",
75
+ "stream_rmsnorm",
76
+ "stream_swiglu",
77
+ "stream_residual",
78
+ "stream_mixer",
79
+ "run_bedrock_smoke",
80
+ "run_all_bedrock_smokes",
81
+ "compare_outputs",
82
+ "diff_label",
83
+ "import_welvet",
84
+ "infer_dense_entity",
85
+ "infer_bedrock_entity",
86
+ "try_infer_bedrock_entity",
87
+ "infer_mixer_v1_entity",
88
+ "print_compare_ladder",
89
+ "WELVET_RELOAD_BEDROCKS",
90
+ "WELVET_RELOAD_SKIP",
91
+ ]
@@ -0,0 +1,86 @@
1
+ """Locate the loom-stream Go binary (stdlib subprocess backend)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ import platform
8
+ import shutil
9
+ import stat
10
+ import subprocess
11
+ from pathlib import Path
12
+
13
+
14
+ def repo_root() -> Path:
15
+ """Planetbridging repo root (../../ from src/planetbridging/)."""
16
+ return Path(__file__).resolve().parents[2]
17
+
18
+
19
+ def default_binary_path() -> Path:
20
+ name = "loom-stream.exe" if platform.system() == "Windows" else "loom-stream"
21
+ return repo_root() / "bin" / name
22
+
23
+
24
+ def find_loom_stream(explicit: str | Path | None = None) -> Path:
25
+ """Resolve loom-stream: explicit → env → PATH → repo bin/."""
26
+ if explicit is not None:
27
+ path = Path(explicit).expanduser().resolve()
28
+ if not path.is_file():
29
+ raise FileNotFoundError(f"loom-stream not found: {path}")
30
+ return path
31
+
32
+ env = os.environ.get("PLANETBRIDGING_LOOM_STREAM")
33
+ if env:
34
+ path = Path(env).expanduser().resolve()
35
+ if path.is_file():
36
+ return path
37
+
38
+ which = shutil.which("loom-stream")
39
+ if which:
40
+ return Path(which)
41
+
42
+ candidate = default_binary_path()
43
+ if candidate.is_file():
44
+ return candidate
45
+
46
+ raise FileNotFoundError(
47
+ "loom-stream binary not found. Build from the planetbridging repo:\n"
48
+ " go build -o bin/loom-stream ./cmd/loom-stream/\n"
49
+ "Or set PLANETBRIDGING_LOOM_STREAM=/path/to/loom-stream"
50
+ )
51
+
52
+
53
+ def ensure_executable(path: Path) -> None:
54
+ if not os.access(path, os.X_OK):
55
+ path.chmod(path.stat().st_mode | stat.S_IXUSR)
56
+
57
+
58
+ def run_loom_stream(
59
+ *,
60
+ binary: Path | None,
61
+ envelope: dict,
62
+ payload: dict,
63
+ timeout: float = 120.0,
64
+ ) -> dict:
65
+ """Invoke loom-stream with JSON on stdin, parse JSON stdout."""
66
+ exe = find_loom_stream(binary)
67
+ ensure_executable(exe)
68
+
69
+ body = {**envelope, "payload": payload}
70
+ proc = subprocess.run(
71
+ [str(exe)],
72
+ input=json.dumps(body).encode("utf-8"),
73
+ capture_output=True,
74
+ timeout=timeout,
75
+ check=False,
76
+ )
77
+ if proc.returncode != 0:
78
+ stderr = proc.stderr.decode("utf-8", errors="replace").strip()
79
+ stdout = proc.stdout.decode("utf-8", errors="replace").strip()
80
+ detail = stderr or stdout or f"exit {proc.returncode}"
81
+ raise RuntimeError(f"loom-stream failed: {detail}")
82
+
83
+ try:
84
+ return json.loads(proc.stdout.decode("utf-8"))
85
+ except json.JSONDecodeError as exc:
86
+ raise RuntimeError(f"loom-stream returned invalid JSON: {proc.stdout!r}") from exc
@@ -0,0 +1,188 @@
1
+ """High-level absorb API — stream live models into Loom .entity for any bedrock."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import Any, Sequence
7
+
8
+ import numpy as np
9
+
10
+ from . import engines
11
+ from .engines import EngineStreamResult
12
+ from .layers.dense import LayerSpec, layers_from_jax, layers_from_keras, layers_from_pytorch, layers_from_sklearn
13
+ from .stream import StreamResult, stream_dense
14
+
15
+
16
+ def stream(
17
+ bedrock: str,
18
+ planet: str,
19
+ *,
20
+ model_id: str | None = None,
21
+ **kwargs: Any,
22
+ ) -> EngineStreamResult:
23
+ """Stream any bedrock layer type from a live AI engine (pytorch/tensorflow/jax/sklearn)."""
24
+ return engines.stream(bedrock, planet, model_id=model_id, **kwargs)
25
+
26
+
27
+ def stream_all_bedrocks(planet: str, **kwargs: Any) -> list[EngineStreamResult]:
28
+ return engines.stream_all_bedrocks(planet, **kwargs)
29
+
30
+
31
+ def stream_all_planets(bedrock: str, **kwargs: Any) -> list[EngineStreamResult]:
32
+ return engines.stream_all_planets(bedrock, **kwargs)
33
+
34
+
35
+ def _default_specs(units: Sequence[int], *, activation: str = "relu") -> tuple[LayerSpec, ...]:
36
+ return tuple(LayerSpec(u, activation) for u in units)
37
+
38
+
39
+ def pytorch(
40
+ net: Any,
41
+ *,
42
+ planet: str = "pytorch",
43
+ model_id: str = "model",
44
+ input_dim: int,
45
+ layer_specs: Sequence[LayerSpec] | None = None,
46
+ layer_units: Sequence[int] | None = None,
47
+ activation: str = "relu",
48
+ inputs: np.ndarray | None = None,
49
+ native_outputs: np.ndarray | None = None,
50
+ output_path: str | Path | None = None,
51
+ models_dir: str | Path | None = None,
52
+ fixture_version: str = "",
53
+ root: str | Path | None = None,
54
+ **kwargs: Any,
55
+ ) -> StreamResult:
56
+ """Stream a PyTorch nn.Module (sequential Dense stack) into Loom .entity."""
57
+ specs = _resolve_specs(layer_specs, layer_units, activation)
58
+ layers = layers_from_pytorch(net, specs, input_dim=input_dim)
59
+ return stream_dense(
60
+ planet=planet,
61
+ model_id=model_id,
62
+ layers=layers,
63
+ input_dim=input_dim,
64
+ inputs=inputs,
65
+ native_outputs=native_outputs,
66
+ output_path=output_path,
67
+ models_dir=models_dir,
68
+ fixture_version=fixture_version,
69
+ root=root,
70
+ **kwargs,
71
+ )
72
+
73
+
74
+ def keras(
75
+ net: Any,
76
+ *,
77
+ planet: str = "tensorflow",
78
+ model_id: str = "model",
79
+ input_dim: int,
80
+ layer_specs: Sequence[LayerSpec] | None = None,
81
+ layer_units: Sequence[int] | None = None,
82
+ activation: str = "relu",
83
+ inputs: np.ndarray | None = None,
84
+ native_outputs: np.ndarray | None = None,
85
+ output_path: str | Path | None = None,
86
+ models_dir: str | Path | None = None,
87
+ fixture_version: str = "",
88
+ root: str | Path | None = None,
89
+ **kwargs: Any,
90
+ ) -> StreamResult:
91
+ """Stream a Keras / TensorFlow model into Loom .entity."""
92
+ specs = _resolve_specs(layer_specs, layer_units, activation)
93
+ layers = layers_from_keras(net, specs, input_dim=input_dim)
94
+ return stream_dense(
95
+ planet=planet,
96
+ model_id=model_id,
97
+ layers=layers,
98
+ input_dim=input_dim,
99
+ inputs=inputs,
100
+ native_outputs=native_outputs,
101
+ output_path=output_path,
102
+ models_dir=models_dir,
103
+ fixture_version=fixture_version,
104
+ root=root,
105
+ **kwargs,
106
+ )
107
+
108
+
109
+ def jax(
110
+ params: Any,
111
+ *,
112
+ planet: str = "jax",
113
+ model_id: str = "model",
114
+ input_dim: int,
115
+ layer_specs: Sequence[LayerSpec] | None = None,
116
+ layer_units: Sequence[int] | None = None,
117
+ activation: str = "relu",
118
+ inputs: np.ndarray | None = None,
119
+ native_outputs: np.ndarray | None = None,
120
+ output_path: str | Path | None = None,
121
+ models_dir: str | Path | None = None,
122
+ fixture_version: str = "",
123
+ root: str | Path | None = None,
124
+ **kwargs: Any,
125
+ ) -> StreamResult:
126
+ """Stream Flax/JAX params dict into Loom .entity."""
127
+ specs = _resolve_specs(layer_specs, layer_units, activation)
128
+ layers = layers_from_jax(params, specs, input_dim=input_dim)
129
+ return stream_dense(
130
+ planet=planet,
131
+ model_id=model_id,
132
+ layers=layers,
133
+ input_dim=input_dim,
134
+ inputs=inputs,
135
+ native_outputs=native_outputs,
136
+ output_path=output_path,
137
+ models_dir=models_dir,
138
+ fixture_version=fixture_version,
139
+ root=root,
140
+ **kwargs,
141
+ )
142
+
143
+
144
+ def sklearn(
145
+ reg: Any,
146
+ *,
147
+ planet: str = "sklearn",
148
+ model_id: str = "model",
149
+ input_dim: int,
150
+ layer_specs: Sequence[LayerSpec] | None = None,
151
+ layer_units: Sequence[int] | None = None,
152
+ activation: str = "linear",
153
+ inputs: np.ndarray | None = None,
154
+ native_outputs: np.ndarray | None = None,
155
+ output_path: str | Path | None = None,
156
+ models_dir: str | Path | None = None,
157
+ fixture_version: str = "",
158
+ root: str | Path | None = None,
159
+ **kwargs: Any,
160
+ ) -> StreamResult:
161
+ """Stream sklearn MLPRegressor into Loom .entity."""
162
+ specs = _resolve_specs(layer_specs, layer_units, activation)
163
+ layers = layers_from_sklearn(reg, specs, input_dim=input_dim)
164
+ return stream_dense(
165
+ planet=planet,
166
+ model_id=model_id,
167
+ layers=layers,
168
+ input_dim=input_dim,
169
+ inputs=inputs,
170
+ native_outputs=native_outputs,
171
+ output_path=output_path,
172
+ models_dir=models_dir,
173
+ fixture_version=fixture_version,
174
+ root=root,
175
+ **kwargs,
176
+ )
177
+
178
+
179
+ def _resolve_specs(
180
+ layer_specs: Sequence[LayerSpec] | None,
181
+ layer_units: Sequence[int] | None,
182
+ activation: str,
183
+ ) -> tuple[LayerSpec, ...]:
184
+ if layer_specs is not None:
185
+ return tuple(layer_specs)
186
+ if layer_units is None:
187
+ raise ValueError("layer_specs or layer_units required")
188
+ return _default_specs(layer_units, activation=activation)
@@ -0,0 +1,173 @@
1
+ """Full compare ladder per bedrock: native → loom-stream → welvet reload."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import numpy as np
10
+
11
+ from .bedrock_smoke import (
12
+ _SMOKE_RUNNERS,
13
+ _load_bedrock_module,
14
+ _load_fixture_npz,
15
+ _repo,
16
+ )
17
+ from .bedrocks import BEDROCK_IDS, BEDROCKS, BedrockInfo
18
+ from .compare import compare_outputs, diff_label
19
+ from .stream import StreamResult
20
+ from .welvet_infer import (
21
+ WELVET_RELOAD_SKIP,
22
+ try_infer_bedrock_entity,
23
+ )
24
+
25
+
26
+ @dataclass(frozen=True)
27
+ class LadderResult:
28
+ bedrock: str
29
+ model_id: str
30
+ planet: str
31
+ layer_count: int
32
+ entity_path: str
33
+ native: np.ndarray
34
+ loom_stream: np.ndarray
35
+ welvet: np.ndarray | None
36
+ native_vs_loom: str
37
+ native_vs_welvet: str | None
38
+ loom_vs_welvet: str | None
39
+ welvet_note: str | None = None
40
+
41
+
42
+ def _fixture_inputs(
43
+ bedrock: str,
44
+ root: Path,
45
+ model: Any,
46
+ manifest: Any,
47
+ fixtures_mod: Any,
48
+ data: dict[str, np.ndarray],
49
+ out_dim: int,
50
+ ) -> tuple[np.ndarray, int | None]:
51
+ """Return (x_test, input_dim_for_dense)."""
52
+ if bedrock == "dense":
53
+ x = fixtures_mod.ensure_fixtures(manifest)["x_test"][:, : model.input_dim]
54
+ return x, int(model.input_dim)
55
+ if bedrock == "mixer":
56
+ return data["x_test"], None
57
+ if bedrock == "residual":
58
+ _, _, _, xm, xs, _ = fixtures_mod.slice_model_inputs(data, model, out_dim)
59
+ # Residual infer uses paired tensors; welvet skip uses main only for display.
60
+ return xm, None
61
+ sliced = fixtures_mod.slice_model_inputs(data, model, out_dim)
62
+ return sliced[2], None
63
+
64
+
65
+ def run_bedrock_ladder(
66
+ bedrock: str,
67
+ *,
68
+ root: Path | None = None,
69
+ model_id: str | None = None,
70
+ binary: Path | None = None,
71
+ out_dir: Path | None = None,
72
+ max_samples: int = 5,
73
+ try_welvet: bool = True,
74
+ planet: str = "numpy",
75
+ ) -> LadderResult:
76
+ """Stream one bedrock model and compare native / loom-stream / welvet reload."""
77
+ bedrock = bedrock.lower()
78
+ if bedrock not in BEDROCKS:
79
+ raise ValueError(f"unknown bedrock {bedrock!r}")
80
+
81
+ info = BEDROCKS[bedrock]
82
+ mid = model_id or info.smoke_model_id
83
+ root = _repo(root)
84
+ runner = _SMOKE_RUNNERS.get(bedrock)
85
+ if runner is None:
86
+ raise ValueError(f"no smoke runner for {bedrock}")
87
+
88
+ stream: StreamResult = runner(root, mid, info, binary=binary, out_dir=out_dir)
89
+ native = stream.native_reference
90
+ if native is None:
91
+ raise RuntimeError(f"{bedrock}: stream result missing native_reference")
92
+
93
+ manifest_mod = _load_bedrock_module(root, bedrock, "manifest")
94
+ fixtures_mod = _load_bedrock_module(root, bedrock, "fixtures")
95
+ manifest = manifest_mod.load_manifest()
96
+ model = next(m for m in manifest.models if m.id == mid)
97
+ data = _load_fixture_npz(root, bedrock, info.fixture_version)
98
+ out_dim = manifest_mod.model_output_dim(model)
99
+ x_test, input_dim = _fixture_inputs(bedrock, root, model, manifest, fixtures_mod, data, out_dim)
100
+
101
+ n = min(max_samples, len(native), len(stream.outputs))
102
+ native_s = native[:n]
103
+ loom_s = stream.outputs[:n]
104
+ x_s = x_test[:n]
105
+
106
+ n_max, _, n_exact = compare_outputs(native_s, loom_s)
107
+ native_vs_loom = diff_label(n_max, exact=n_exact)
108
+
109
+ welvet_out: np.ndarray | None = None
110
+ native_vs_welvet: str | None = None
111
+ loom_vs_welvet: str | None = None
112
+ welvet_note: str | None = None
113
+
114
+ if bedrock in WELVET_RELOAD_SKIP:
115
+ welvet_note = "welvet reload skipped (C ABI gap on this bedrock)"
116
+ elif not try_welvet:
117
+ welvet_note = "welvet not requested"
118
+ else:
119
+ welvet_out = try_infer_bedrock_entity(
120
+ bedrock,
121
+ stream.entity_path,
122
+ x_s,
123
+ output_dim=out_dim if bedrock != "dense" else native_s.shape[-1],
124
+ input_dim=input_dim,
125
+ )
126
+ if welvet_out is None:
127
+ welvet_note = "welvet reload failed or unavailable"
128
+ else:
129
+ w_max, _, w_exact = compare_outputs(native_s, welvet_out)
130
+ lw_max, _, lw_exact = compare_outputs(loom_s, welvet_out)
131
+ native_vs_welvet = diff_label(w_max, exact=w_exact)
132
+ loom_vs_welvet = diff_label(lw_max, exact=lw_exact)
133
+
134
+ return LadderResult(
135
+ bedrock=bedrock,
136
+ model_id=mid,
137
+ planet=planet,
138
+ layer_count=stream.layer_count,
139
+ entity_path=stream.entity_path,
140
+ native=native_s,
141
+ loom_stream=loom_s,
142
+ welvet=welvet_out,
143
+ native_vs_loom=native_vs_loom,
144
+ native_vs_welvet=native_vs_welvet,
145
+ loom_vs_welvet=loom_vs_welvet,
146
+ welvet_note=welvet_note,
147
+ )
148
+
149
+
150
+ def run_all_bedrock_ladders(**kwargs: Any) -> list[LadderResult]:
151
+ results: list[LadderResult] = []
152
+ for bid in BEDROCK_IDS:
153
+ try:
154
+ results.append(run_bedrock_ladder(bid, **kwargs))
155
+ except Exception as exc:
156
+ info = BEDROCKS[bid]
157
+ results.append(
158
+ LadderResult(
159
+ bedrock=bid,
160
+ model_id=info.smoke_model_id,
161
+ planet=str(kwargs.get("planet", "numpy")),
162
+ layer_count=0,
163
+ entity_path=str(exc),
164
+ native=np.zeros((0, 0)),
165
+ loom_stream=np.zeros((0, 0)),
166
+ welvet=None,
167
+ native_vs_loom="ERROR",
168
+ native_vs_welvet=None,
169
+ loom_vs_welvet=None,
170
+ welvet_note=str(exc),
171
+ )
172
+ )
173
+ return results