clm-kernel 0.0.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.
- clm/__init__.py +230 -0
- clm/__main__.py +25 -0
- clm/cross_cutting/__init__.py +50 -0
- clm/cross_cutting/_test_runner.py +36 -0
- clm/cross_cutting/async_utils.py +25 -0
- clm/cross_cutting/cel_builder.py +123 -0
- clm/cross_cutting/cel_converter.py +697 -0
- clm/cross_cutting/cel_engine.py +252 -0
- clm/cross_cutting/cel_ops.py +72 -0
- clm/cross_cutting/cel_ops_db.py +157 -0
- clm/cross_cutting/cel_ops_files.py +99 -0
- clm/cross_cutting/cel_ops_state.py +71 -0
- clm/cross_cutting/cel_ops_strings.py +64 -0
- clm/cross_cutting/cel_resolver.py +63 -0
- clm/cross_cutting/cel_slices.py +56 -0
- clm/cross_cutting/cel_store.py +330 -0
- clm/cross_cutting/clm_logger.py +140 -0
- clm/cross_cutting/config/__init__.py +155 -0
- clm/cross_cutting/config/config_constants.py +392 -0
- clm/cross_cutting/config/env_parameters.py +90 -0
- clm/cross_cutting/config/logging.py +378 -0
- clm/cross_cutting/config/settings.py +504 -0
- clm/cross_cutting/context.py +5 -0
- clm/cross_cutting/domain_models.py +55 -0
- clm/cross_cutting/domain_types.py +61 -0
- clm/cross_cutting/effects.py +67 -0
- clm/cross_cutting/errors.py +153 -0
- clm/cross_cutting/governance.py +331 -0
- clm/cross_cutting/guards.py +41 -0
- clm/cross_cutting/mcard.py +321 -0
- clm/cross_cutting/native.py +185 -0
- clm/cross_cutting/observability.py +289 -0
- clm/cross_cutting/pcard.py +434 -0
- clm/cross_cutting/registry.py +71 -0
- clm/cross_cutting/resources.py +84 -0
- clm/cross_cutting/secrets.py +44 -0
- clm/cross_cutting/subprocess_utils.py +118 -0
- clm/cross_cutting/telemetry.py +164 -0
- clm/cross_cutting/testing/__init__.py +8 -0
- clm/cross_cutting/testing/comparator.py +187 -0
- clm/cross_cutting/testing/datasets.py +87 -0
- clm/cross_cutting/timeutil.py +20 -0
- clm/cross_cutting/types/new_type_check.py +0 -0
- clm/cross_cutting/utils/__init__.py +1 -0
- clm/cross_cutting/utils/url_safety.py +50 -0
- clm/cross_cutting/vcard.py +560 -0
- clm/cross_cutting/writer.py +118 -0
- clm/layer0/README.md +50 -0
- clm/layer0/__init__.py +223 -0
- clm/layer0/algebra.py +60 -0
- clm/layer0/algebra_baldwin.py +133 -0
- clm/layer0/algebra_baldwin_generators.py +36 -0
- clm/layer0/algebra_equivalence.py +262 -0
- clm/layer0/algebra_ingest.py +306 -0
- clm/layer0/algebra_manifest_io.py +156 -0
- clm/layer0/assembler.py +481 -0
- clm/layer0/cel/__init__.py +23 -0
- clm/layer0/cel_eval.py +491 -0
- clm/layer0/codec.py +106 -0
- clm/layer0/context.py +122 -0
- clm/layer0/db.py +160 -0
- clm/layer0/exceptions.py +73 -0
- clm/layer0/fibration.py +106 -0
- clm/layer0/gates.py +50 -0
- clm/layer0/hash.py +80 -0
- clm/layer0/loader.py +826 -0
- clm/layer0/math_utils.py +163 -0
- clm/layer0/mcard.py +96 -0
- clm/layer0/model/__init__.py +0 -0
- clm/layer0/model/action.py +223 -0
- clm/layer0/model/card.py +280 -0
- clm/layer0/model/card_triad.py +427 -0
- clm/layer0/model/compatibility.py +60 -0
- clm/layer0/model/dictionary.py +46 -0
- clm/layer0/model/dots.py +331 -0
- clm/layer0/model/event_producer.py +88 -0
- clm/layer0/model/g_time.py +89 -0
- clm/layer0/model/handle.py +163 -0
- clm/layer0/model/hash/__init__.py +6 -0
- clm/layer0/model/hash/algorithms/__init__.py +3 -0
- clm/layer0/model/hash/algorithms/custom_hash.py +7 -0
- clm/layer0/model/hash/algorithms/local_sha256.py +178 -0
- clm/layer0/model/hash/constants.py +53 -0
- clm/layer0/model/hash/enums.py +60 -0
- clm/layer0/model/hash/validator.py +307 -0
- clm/layer0/model/interpreter.py +275 -0
- clm/layer0/model/pagination.py +45 -0
- clm/layer0/model/pcard.py +716 -0
- clm/layer0/model/schema.py +44 -0
- clm/layer0/model/utils/__init__.py +1 -0
- clm/layer0/model/utils/content_analyzer.py +152 -0
- clm/layer0/model/validators/__init__.py +1 -0
- clm/layer0/model/validators/base_validator.py +44 -0
- clm/layer0/model/validators/binary_validator.py +66 -0
- clm/layer0/model/validators/text_validator.py +82 -0
- clm/layer0/model/validators/validation_registry.py +49 -0
- clm/layer0/model/vcard.py +823 -0
- clm/layer0/model/vcard_ext/__init__.py +39 -0
- clm/layer0/model/vcard_ext/core.py +60 -0
- clm/layer0/model/vcard_ext/network.py +23 -0
- clm/layer0/model/vcard_ext/observability.py +63 -0
- clm/layer0/model/vcard_ext/storage.py +60 -0
- clm/layer0/model/vcard_ext/vendors.py +211 -0
- clm/layer0/model/vcard_sandwich.py +119 -0
- clm/layer0/model/vcard_vocabulary.py +463 -0
- clm/layer0/model/workflow.py +274 -0
- clm/layer0/narrative.py +431 -0
- clm/layer0/ontology/collection.py +125 -0
- clm/layer0/parser.py +429 -0
- clm/layer0/relations.py +73 -0
- clm/layer0/rule_evaluator.py +251 -0
- clm/layer0/schema/__init__.py +38 -0
- clm/layer0/schema/ddl.py +97 -0
- clm/layer0/templates/abstract.yaml +99 -0
- clm/layer0/templates/balanced.yaml +253 -0
- clm/layer0/templates/concrete.yaml +172 -0
- clm/layer0/type_registry.py +223 -0
- clm/layer0/types.py +204 -0
- clm/layer0/utils.py +886 -0
- clm/layer0/verifier_core.py +262 -0
- clm/layer1/__init__.py +31 -0
- clm/layer1/action_dispatcher.py +275 -0
- clm/layer1/adapter_registry.py +233 -0
- clm/layer1/algebra_baldwin_generators.py +192 -0
- clm/layer1/arrow_compiler.py +525 -0
- clm/layer1/batch_processor.py +152 -0
- clm/layer1/cel/__init__.py +27 -0
- clm/layer1/cel/builder.py +173 -0
- clm/layer1/engine.py +759 -0
- clm/layer1/engine_async.py +89 -0
- clm/layer1/eval_callback.py +49 -0
- clm/layer1/gate_composer.py +229 -0
- clm/layer1/hoare_sandwich.py +298 -0
- clm/layer1/identity_guard.py +348 -0
- clm/layer1/matrix.py +138 -0
- clm/layer1/neural_runtime.py +221 -0
- clm/layer1/operations/__init__.py +123 -0
- clm/layer1/operations/augment.py +156 -0
- clm/layer1/operations/base.py +109 -0
- clm/layer1/operations/builtins.py +338 -0
- clm/layer1/operations/dispatch.py +144 -0
- clm/layer1/operations/exclude.py +107 -0
- clm/layer1/operations/handle.py +197 -0
- clm/layer1/operations/identity.py +139 -0
- clm/layer1/operations/invert.py +66 -0
- clm/layer1/operations/loader.py +116 -0
- clm/layer1/operations/manipulators/__init__.py +23 -0
- clm/layer1/operations/manipulators/document.py +211 -0
- clm/layer1/operations/manipulators/media.py +134 -0
- clm/layer1/operations/manipulators/structured.py +159 -0
- clm/layer1/operations/manipulators/tabular.py +334 -0
- clm/layer1/operations/port.py +65 -0
- clm/layer1/operations/services.py +529 -0
- clm/layer1/operations/split.py +117 -0
- clm/layer1/operations/substitute.py +75 -0
- clm/layer1/petri.py +1052 -0
- clm/layer1/pocketflow_orchestrator.py +408 -0
- clm/layer1/pocketflow_scheduler.py +519 -0
- clm/layer1/protocols.py +197 -0
- clm/layer1/runtime_adapter.py +718 -0
- clm/layer1/runtimes/__init__.py +71 -0
- clm/layer1/runtimes/_generated_assertions.py +125 -0
- clm/layer1/runtimes/_generated_types.py +42 -0
- clm/layer1/runtimes/base.py +265 -0
- clm/layer1/runtimes/binary.py +101 -0
- clm/layer1/runtimes/factory.py +203 -0
- clm/layer1/runtimes/javascript.py +321 -0
- clm/layer1/runtimes/javascript_runtime.js +33 -0
- clm/layer1/runtimes/js_scripts/isomorphism.mjs +22 -0
- clm/layer1/runtimes/js_scripts/loader.mjs +52 -0
- clm/layer1/runtimes/lambda_calc.py +126 -0
- clm/layer1/runtimes/python.py +288 -0
- clm/layer1/runtimes/python_runtime.py +41 -0
- clm/layer1/runtimes/script.py +114 -0
- clm/layer1/sandbox.py +334 -0
- clm/layer1/savepoint_guard.py +136 -0
- clm/layer1/sparse_net.py +122 -0
- clm/layer1/spec_tester.py +165 -0
- clm/layer1/store.py +295 -0
- clm/layer1/test_runner.py +498 -0
- clm/layer1/type_inspector.py +166 -0
- clm/layer1/verifier.py +772 -0
- clm/layer1/vm.py +91 -0
- clm/layer2/__init__.py +78 -0
- clm/layer2/card_collection.py +678 -0
- clm/layer2/classifier.py +479 -0
- clm/layer2/engine/__init__.py +1 -0
- clm/layer2/engine/abstract_sql_engine.py +320 -0
- clm/layer2/engine/base.py +193 -0
- clm/layer2/engine/duckdb_engine.py +576 -0
- clm/layer2/engine/sqlite_engine.py +518 -0
- clm/layer2/fiber/__init__.py +31 -0
- clm/layer2/fiber/context.py +89 -0
- clm/layer2/fiber/disposable.py +163 -0
- clm/layer2/fiber/fiber.py +125 -0
- clm/layer2/fiber/hoare.py +191 -0
- clm/layer2/file_io.py +376 -0
- clm/layer2/file_registrar.py +77 -0
- clm/layer2/ingest.py +202 -0
- clm/layer2/lineage.py +322 -0
- clm/layer2/mcard_fs.py +262 -0
- clm/layer2/merkle.py +11 -0
- clm/layer2/mime.py +244 -0
- clm/layer2/mime_detector.py +245 -0
- clm/layer2/private_collection.py +118 -0
- clm/layer2/shared_store.py +11 -0
- clm/layer2/storage/__init__.py +190 -0
- clm/layer2/storage/db_bitemporal.py +141 -0
- clm/layer2/storage/db_driver.py +331 -0
- clm/layer2/storage/db_hyperlinks.py +214 -0
- clm/layer2/storage/db_pool.py +139 -0
- clm/layer2/storage/db_repository.py +229 -0
- clm/layer2/storage/savepoint.py +78 -0
- clm/layer2/storage/sqlite_wal.py +74 -0
- clm/layer2/tridb.py +245 -0
- clm/layer2/vcard_receipt.py +71 -0
- clm/layer2/vfs.py +17 -0
- clm/layer3/__init__.py +141 -0
- clm/layer3/agency/__init__.py +19 -0
- clm/layer3/agency/config.py +220 -0
- clm/layer3/agency/providers/__init__.py +15 -0
- clm/layer3/agency/providers/base.py +91 -0
- clm/layer3/agency/providers/mlc_llm.py +169 -0
- clm/layer3/agency/providers/ollama.py +203 -0
- clm/layer3/agency/router.py +71 -0
- clm/layer3/agency/runtime.py +524 -0
- clm/layer3/gateway.py +353 -0
- clm/layer3/open_interpreter_adapter.py +159 -0
- clm/layer3/rag/__init__.py +70 -0
- clm/layer3/rag/cli.py +228 -0
- clm/layer3/rag/config.py +153 -0
- clm/layer3/rag/embeddings/__init__.py +16 -0
- clm/layer3/rag/embeddings/base.py +79 -0
- clm/layer3/rag/embeddings/ollama.py +211 -0
- clm/layer3/rag/embeddings/vision.py +290 -0
- clm/layer3/rag/engine.py +276 -0
- clm/layer3/rag/graph/__init__.py +22 -0
- clm/layer3/rag/graph/community.py +198 -0
- clm/layer3/rag/graph/engine.py +433 -0
- clm/layer3/rag/graph/extractor.py +255 -0
- clm/layer3/rag/graph/schema.py +115 -0
- clm/layer3/rag/graph/store.py +641 -0
- clm/layer3/rag/indexer.py +333 -0
- clm/layer3/rag/llm_providers.json +52 -0
- clm/layer3/rag/semantic_versioning.py +313 -0
- clm/layer3/rag/vector/__init__.py +28 -0
- clm/layer3/rag/vector/handle_vector_store.py +749 -0
- clm/layer3/rag/vector/schema.py +151 -0
- clm/layer3/rag/vector/store.py +632 -0
- clm/layer3/reticulum/__init__.py +55 -0
- clm/layer3/reticulum/bridge.py +74 -0
- clm/layer3/reticulum/daemon.py +88 -0
- clm/layer3/reticulum/discovery.py +164 -0
- clm/layer3/reticulum/identity.py +107 -0
- clm/layer3/reticulum/media.py +148 -0
- clm/layer3/reticulum/transport.py +133 -0
- clm/layer3/satori/__init__.py +209 -0
- clm/layer3/satori/alpha_conversion.py +168 -0
- clm/layer3/satori/beta_reduction.py +359 -0
- clm/layer3/satori/continuation.py +38 -0
- clm/layer3/satori/eta_conversion.py +205 -0
- clm/layer3/satori/free_variables.py +163 -0
- clm/layer3/satori/io_effects.py +370 -0
- clm/layer3/satori/lambda_runtime.py +726 -0
- clm/layer3/satori/lambda_term.py +230 -0
- clm/layer3/satori/sheaf_audit.py +261 -0
- clm/layer3/satori/speech_act.py +279 -0
- clm/layer4/README.md +9 -0
- clm/layer4/__init__.py +67 -0
- clm/layer4/_sovereign_executor.py +580 -0
- clm/layer4/action_commands.py +719 -0
- clm/layer4/api.py +236 -0
- clm/layer4/bootstrap/__init__.py +13 -0
- clm/layer4/bootstrap/bootstrapper.py +118 -0
- clm/layer4/bootstrap/cleanup.py +44 -0
- clm/layer4/bootstrap/clm_hooks.py +49 -0
- clm/layer4/bootstrap/genesis.py +77 -0
- clm/layer4/bootstrap/injection.py +125 -0
- clm/layer4/cli.py +549 -0
- clm/layer4/collection_manager.py +553 -0
- clm/layer4/commands/__init__.py +81 -0
- clm/layer4/commands/action_cmd.py +42 -0
- clm/layer4/commands/check_cmd.py +82 -0
- clm/layer4/commands/envelope.py +73 -0
- clm/layer4/commands/evaluate_cmd.py +224 -0
- clm/layer4/commands/mcard_cmd.py +24 -0
- clm/layer4/commands/petri_cmd.py +92 -0
- clm/layer4/commands/tridb_cmd.py +319 -0
- clm/layer4/commands/version_cmd.py +27 -0
- clm/layer4/diff_commands.py +167 -0
- clm/layer4/eoa_sponsor.py +232 -0
- clm/layer4/events.py +69 -0
- clm/layer4/flux_gateway.py +133 -0
- clm/layer4/gateway.py +91 -0
- clm/layer4/loader.py +307 -0
- clm/layer4/mcard_commands.py +166 -0
- clm/layer4/membrane.py +273 -0
- clm/layer4/navigation.py +50 -0
- clm/layer4/protocol/protocol_entry_python.py +108 -0
- clm/layer4/protocol/python_sync.py +126 -0
- clm/layer4/runner.py +150 -0
- clm/layer4/satori.py +262 -0
- clm/layer4/server/python_sync_client.py +150 -0
- clm/layer4/server/python_sync_server.py +139 -0
- clm/layer4/server/service_api.py +315 -0
- clm/layer4/server/start_servers.py +107 -0
- clm/layer4/server/stop_servers.py +24 -0
- clm/layer4/simulated_optimization_fix.py +0 -0
- clm/layer4/storage.py +463 -0
- clm/layer4/tridb_admin.py +268 -0
- clm/layer4/websocket/test_ws_client.py +104 -0
- clm/layer4/websocket/test_ws_server.py +138 -0
- clm/layer4/websocket/ws_server_local.py +160 -0
- clm/layer5/__init__.py +51 -0
- clm/layer5/async_batch_writer.py +133 -0
- clm/layer5/learning.py +276 -0
- clm/layer5/telemetry_hook.py +107 -0
- clm/layer5/type_lattice.py +238 -0
- clm/py.typed +0 -0
- clm/schemas/__init__.py +652 -0
- clm/schemas/abstract_face_schema.yaml +77 -0
- clm/schemas/cel_schema.yaml +416 -0
- clm/schemas/lifecycle/__init__.py +45 -0
- clm/schemas/lifecycle/models.py +123 -0
- clm/schemas/lifecycle/service.py +364 -0
- clm/schemas/mcard_schema.sql +192 -0
- clm/schemas/mcard_vector_schema.sql +283 -0
- clm/schemas/mlp-context-v1.json +91 -0
- clm_kernel-0.0.0.dist-info/METADATA +121 -0
- clm_kernel-0.0.0.dist-info/RECORD +333 -0
- clm_kernel-0.0.0.dist-info/WHEEL +4 -0
- clm_kernel-0.0.0.dist-info/entry_points.txt +3 -0
- clm_kernel-0.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Beta Reduction - Function application in Lambda Calculus
|
|
3
|
+
|
|
4
|
+
Beta reduction (β-reduction) is the computational rule:
|
|
5
|
+
(λx.M) N →β M[x:=N]
|
|
6
|
+
|
|
7
|
+
This module provides:
|
|
8
|
+
- Single-step beta reduction
|
|
9
|
+
- Full normalization with multiple strategies
|
|
10
|
+
- Capture-avoiding substitution
|
|
11
|
+
- Redex detection and search
|
|
12
|
+
|
|
13
|
+
This module provides Python parity with mcard-js/src/ptr/lambda/BetaReduction.ts
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from collections.abc import Callable
|
|
17
|
+
from dataclasses import dataclass
|
|
18
|
+
from typing import Literal
|
|
19
|
+
|
|
20
|
+
from clm.layer2.card_collection import CardCollection
|
|
21
|
+
from clm.layer3.satori.alpha_conversion import alpha_rename
|
|
22
|
+
from clm.layer3.satori.free_variables import generate_fresh_for, is_free_in
|
|
23
|
+
from clm.layer3.satori.lambda_term import (
|
|
24
|
+
is_abs,
|
|
25
|
+
is_app,
|
|
26
|
+
is_var,
|
|
27
|
+
load_term,
|
|
28
|
+
mk_abs,
|
|
29
|
+
mk_app,
|
|
30
|
+
store_term,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
34
|
+
# Types
|
|
35
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
ReductionStrategy = Literal["normal", "applicative", "lazy"]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class NormalizationResult:
|
|
42
|
+
"""Result of normalization"""
|
|
43
|
+
|
|
44
|
+
normal_form: str # Hash of the normal form
|
|
45
|
+
steps: int # Number of reduction steps
|
|
46
|
+
reduction_path: list[str] # Hashes of intermediate forms
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
50
|
+
# Substitution with Capture Avoidance
|
|
51
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def substitute_with_capture(
|
|
55
|
+
collection: CardCollection, term_hash: str, var_name: str, replacement_hash: str
|
|
56
|
+
) -> str | None:
|
|
57
|
+
"""
|
|
58
|
+
Perform capture-avoiding substitution: M[x:=N]
|
|
59
|
+
|
|
60
|
+
This is the core operation that replaces all free occurrences of x in M with N,
|
|
61
|
+
while avoiding variable capture by renaming bound variables as needed.
|
|
62
|
+
"""
|
|
63
|
+
term = load_term(collection, term_hash)
|
|
64
|
+
if term is None:
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
if is_var(term):
|
|
68
|
+
if term.name == var_name:
|
|
69
|
+
return replacement_hash
|
|
70
|
+
return term_hash
|
|
71
|
+
|
|
72
|
+
elif is_abs(term):
|
|
73
|
+
if term.param == var_name:
|
|
74
|
+
# x is bound here - no substitution in body
|
|
75
|
+
return term_hash
|
|
76
|
+
|
|
77
|
+
# Check for capture: if param is free in replacement
|
|
78
|
+
param_free_in_repl = is_free_in(collection, term.param, replacement_hash)
|
|
79
|
+
if param_free_in_repl is None:
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
if param_free_in_repl:
|
|
83
|
+
# Need to alpha-rename to avoid capture
|
|
84
|
+
fresh = generate_fresh_for(
|
|
85
|
+
collection, term.param, term.body, replacement_hash
|
|
86
|
+
)
|
|
87
|
+
renamed_body = alpha_rename(collection, term.body, term.param, fresh)
|
|
88
|
+
if renamed_body is None:
|
|
89
|
+
return None
|
|
90
|
+
|
|
91
|
+
new_body = substitute_with_capture(
|
|
92
|
+
collection, renamed_body, var_name, replacement_hash
|
|
93
|
+
)
|
|
94
|
+
if new_body is None:
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
return store_term(collection, mk_abs(fresh, new_body))
|
|
98
|
+
|
|
99
|
+
# Safe to substitute directly
|
|
100
|
+
new_body = substitute_with_capture(
|
|
101
|
+
collection, term.body, var_name, replacement_hash
|
|
102
|
+
)
|
|
103
|
+
if new_body is None:
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
return store_term(collection, mk_abs(term.param, new_body))
|
|
107
|
+
|
|
108
|
+
elif is_app(term):
|
|
109
|
+
new_func = substitute_with_capture(
|
|
110
|
+
collection, term.func, var_name, replacement_hash
|
|
111
|
+
)
|
|
112
|
+
new_arg = substitute_with_capture(
|
|
113
|
+
collection, term.arg, var_name, replacement_hash
|
|
114
|
+
)
|
|
115
|
+
if new_func is None or new_arg is None:
|
|
116
|
+
return None
|
|
117
|
+
return store_term(collection, mk_app(new_func, new_arg))
|
|
118
|
+
|
|
119
|
+
return term_hash
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
123
|
+
# Redex Detection
|
|
124
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def is_redex(collection: CardCollection, hash_value: str) -> bool | None:
|
|
128
|
+
"""
|
|
129
|
+
Check if a term is a beta-redex: (λx.M) N
|
|
130
|
+
"""
|
|
131
|
+
term = load_term(collection, hash_value)
|
|
132
|
+
if term is None:
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
if is_app(term):
|
|
136
|
+
func = load_term(collection, term.func)
|
|
137
|
+
if func is not None and is_abs(func):
|
|
138
|
+
return True
|
|
139
|
+
|
|
140
|
+
return False
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def find_leftmost_redex(collection: CardCollection, hash_value: str) -> str | None:
|
|
144
|
+
"""
|
|
145
|
+
Find the leftmost-outermost beta-redex (normal order).
|
|
146
|
+
Returns the hash of the redex, or None if none found.
|
|
147
|
+
"""
|
|
148
|
+
term = load_term(collection, hash_value)
|
|
149
|
+
if term is None:
|
|
150
|
+
return None
|
|
151
|
+
|
|
152
|
+
if is_app(term):
|
|
153
|
+
# Check if this is a redex
|
|
154
|
+
func = load_term(collection, term.func)
|
|
155
|
+
if func is not None and is_abs(func):
|
|
156
|
+
return hash_value
|
|
157
|
+
|
|
158
|
+
# Try left subtree first
|
|
159
|
+
left_redex = find_leftmost_redex(collection, term.func)
|
|
160
|
+
if left_redex:
|
|
161
|
+
return left_redex
|
|
162
|
+
|
|
163
|
+
# Then right subtree
|
|
164
|
+
return find_leftmost_redex(collection, term.arg)
|
|
165
|
+
|
|
166
|
+
elif is_abs(term):
|
|
167
|
+
return find_leftmost_redex(collection, term.body)
|
|
168
|
+
|
|
169
|
+
return None
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def find_innermost_redex(collection: CardCollection, hash_value: str) -> str | None:
|
|
173
|
+
"""
|
|
174
|
+
Find the innermost-leftmost beta-redex (applicative order).
|
|
175
|
+
Returns the hash of the redex, or None if none found.
|
|
176
|
+
"""
|
|
177
|
+
term = load_term(collection, hash_value)
|
|
178
|
+
if term is None:
|
|
179
|
+
return None
|
|
180
|
+
|
|
181
|
+
if is_app(term):
|
|
182
|
+
# Try subtrees first
|
|
183
|
+
left_redex = find_innermost_redex(collection, term.func)
|
|
184
|
+
if left_redex:
|
|
185
|
+
return left_redex
|
|
186
|
+
|
|
187
|
+
right_redex = find_innermost_redex(collection, term.arg)
|
|
188
|
+
if right_redex:
|
|
189
|
+
return right_redex
|
|
190
|
+
|
|
191
|
+
# Check if this is a redex
|
|
192
|
+
func = load_term(collection, term.func)
|
|
193
|
+
if func is not None and is_abs(func):
|
|
194
|
+
return hash_value
|
|
195
|
+
|
|
196
|
+
elif is_abs(term):
|
|
197
|
+
return find_innermost_redex(collection, term.body)
|
|
198
|
+
|
|
199
|
+
return None
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
203
|
+
# Beta Reduction
|
|
204
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def beta_reduce(collection: CardCollection, hash_value: str) -> str | None:
|
|
208
|
+
"""
|
|
209
|
+
Perform a single beta reduction step on a redex.
|
|
210
|
+
|
|
211
|
+
(λx.M) N →β M[x:=N]
|
|
212
|
+
|
|
213
|
+
Returns the hash of the reduced term, or None if not a redex.
|
|
214
|
+
"""
|
|
215
|
+
term = load_term(collection, hash_value)
|
|
216
|
+
if term is None:
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
if not is_app(term):
|
|
220
|
+
return None
|
|
221
|
+
|
|
222
|
+
func = load_term(collection, term.func)
|
|
223
|
+
if func is None or not is_abs(func):
|
|
224
|
+
return None
|
|
225
|
+
|
|
226
|
+
# Perform substitution: body[param:=arg]
|
|
227
|
+
return substitute_with_capture(collection, func.body, func.param, term.arg)
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def reduce_step(
|
|
231
|
+
collection: CardCollection, hash_value: str, strategy: ReductionStrategy = "normal"
|
|
232
|
+
) -> str | None:
|
|
233
|
+
"""
|
|
234
|
+
Perform a single reduction step using the specified strategy.
|
|
235
|
+
Returns None if no reduction is possible.
|
|
236
|
+
"""
|
|
237
|
+
term = load_term(collection, hash_value)
|
|
238
|
+
if term is None:
|
|
239
|
+
return None
|
|
240
|
+
|
|
241
|
+
# Find redex based on strategy
|
|
242
|
+
if strategy == "normal":
|
|
243
|
+
redex_hash = find_leftmost_redex(collection, hash_value)
|
|
244
|
+
elif strategy == "applicative":
|
|
245
|
+
redex_hash = find_innermost_redex(collection, hash_value)
|
|
246
|
+
else: # lazy
|
|
247
|
+
redex_hash = find_leftmost_redex(collection, hash_value)
|
|
248
|
+
|
|
249
|
+
if not redex_hash:
|
|
250
|
+
return None
|
|
251
|
+
|
|
252
|
+
# Reduce the redex
|
|
253
|
+
reduced = beta_reduce(collection, redex_hash)
|
|
254
|
+
if reduced is None:
|
|
255
|
+
return None
|
|
256
|
+
|
|
257
|
+
# Replace the redex in the original term
|
|
258
|
+
return replace_subterm(collection, hash_value, redex_hash, reduced)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def replace_subterm(
|
|
262
|
+
collection: CardCollection, term_hash: str, target_hash: str, replacement_hash: str
|
|
263
|
+
) -> str | None:
|
|
264
|
+
"""
|
|
265
|
+
Replace a subterm (identified by hash) with another term.
|
|
266
|
+
"""
|
|
267
|
+
if term_hash == target_hash:
|
|
268
|
+
return replacement_hash
|
|
269
|
+
|
|
270
|
+
term = load_term(collection, term_hash)
|
|
271
|
+
if term is None:
|
|
272
|
+
return None
|
|
273
|
+
|
|
274
|
+
if is_var(term):
|
|
275
|
+
return term_hash
|
|
276
|
+
|
|
277
|
+
elif is_abs(term):
|
|
278
|
+
new_body = replace_subterm(collection, term.body, target_hash, replacement_hash)
|
|
279
|
+
if new_body is None:
|
|
280
|
+
return None
|
|
281
|
+
if new_body == term.body:
|
|
282
|
+
return term_hash
|
|
283
|
+
return store_term(collection, mk_abs(term.param, new_body))
|
|
284
|
+
|
|
285
|
+
elif is_app(term):
|
|
286
|
+
new_func = replace_subterm(collection, term.func, target_hash, replacement_hash)
|
|
287
|
+
new_arg = replace_subterm(collection, term.arg, target_hash, replacement_hash)
|
|
288
|
+
if new_func is None or new_arg is None:
|
|
289
|
+
return None
|
|
290
|
+
if new_func == term.func and new_arg == term.arg:
|
|
291
|
+
return term_hash
|
|
292
|
+
return store_term(collection, mk_app(new_func, new_arg))
|
|
293
|
+
|
|
294
|
+
return term_hash
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
298
|
+
# Normalization
|
|
299
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def normalize(
|
|
303
|
+
collection: CardCollection,
|
|
304
|
+
hash_value: str,
|
|
305
|
+
strategy: ReductionStrategy = "normal",
|
|
306
|
+
max_steps: int = 1000,
|
|
307
|
+
on_step: Callable[[int, str], None] | None = None,
|
|
308
|
+
) -> NormalizationResult | None:
|
|
309
|
+
"""
|
|
310
|
+
Normalize a Lambda term by repeatedly applying reduction steps.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
collection: The card collection containing terms
|
|
314
|
+
hash_value: Hash of the term to normalize
|
|
315
|
+
strategy: Reduction strategy ('normal', 'applicative', 'lazy')
|
|
316
|
+
max_steps: Maximum number of reduction steps
|
|
317
|
+
on_step: Optional callback for IO effects, called after each step
|
|
318
|
+
|
|
319
|
+
Returns the normal form if found within max_steps, or None if:
|
|
320
|
+
- Term not found
|
|
321
|
+
- Reduction diverges (exceeds max_steps)
|
|
322
|
+
"""
|
|
323
|
+
current = hash_value
|
|
324
|
+
path = [current]
|
|
325
|
+
steps = 0
|
|
326
|
+
|
|
327
|
+
while steps < max_steps:
|
|
328
|
+
next_term = reduce_step(collection, current, strategy)
|
|
329
|
+
|
|
330
|
+
if next_term is None:
|
|
331
|
+
# No more reductions - we're in normal form
|
|
332
|
+
return NormalizationResult(
|
|
333
|
+
normal_form=current, steps=steps, reduction_path=path
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
steps += 1
|
|
337
|
+
current = next_term
|
|
338
|
+
path.append(current)
|
|
339
|
+
|
|
340
|
+
# IO Effect: emit step event
|
|
341
|
+
if on_step is not None:
|
|
342
|
+
on_step(steps, current)
|
|
343
|
+
|
|
344
|
+
# Exceeded max steps - possibly divergent
|
|
345
|
+
return None
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def is_normal_form(collection: CardCollection, hash_value: str) -> bool | None:
|
|
349
|
+
"""Check if a term is in normal form (contains no redexes)"""
|
|
350
|
+
redex = find_leftmost_redex(collection, hash_value)
|
|
351
|
+
return redex is None
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def has_normal_form(
|
|
355
|
+
collection: CardCollection, hash_value: str, max_steps: int = 1000
|
|
356
|
+
) -> bool | None:
|
|
357
|
+
"""Check if a term has a normal form (within max_steps)"""
|
|
358
|
+
result = normalize(collection, hash_value, "normal", max_steps)
|
|
359
|
+
return result is not None
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Layer 3 Satori Delimited Continuations (DEL-390-02).
|
|
2
|
+
|
|
3
|
+
Provides delimited continuation tokens and multi-turn state resumption
|
|
4
|
+
for Satori conversational speech-act threads.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import time
|
|
9
|
+
import uuid
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Any, Dict, List, Optional
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class ContinuationToken:
|
|
16
|
+
"""Represents a suspended execution turn in a conversational speech-act thread."""
|
|
17
|
+
turn_id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
|
18
|
+
timestamp: float = field(default_factory=time.time)
|
|
19
|
+
captured_state: Dict[str, Any] = field(default_factory=dict)
|
|
20
|
+
prompt_history: List[Dict[str, Any]] = field(default_factory=list)
|
|
21
|
+
resume_target: Optional[str] = None
|
|
22
|
+
is_resumed: bool = False
|
|
23
|
+
|
|
24
|
+
def resume(self, response_act: Dict[str, Any]) -> Dict[str, Any]:
|
|
25
|
+
"""Resumes the suspended continuation by appending the new speech act."""
|
|
26
|
+
if self.is_resumed:
|
|
27
|
+
raise RuntimeError(f"ContinuationToken {self.turn_id} has already been resumed.")
|
|
28
|
+
self.is_resumed = True
|
|
29
|
+
self.prompt_history.append(response_act)
|
|
30
|
+
return {
|
|
31
|
+
"turn_id": self.turn_id,
|
|
32
|
+
"resumed_at": time.time(),
|
|
33
|
+
"history_depth": len(self.prompt_history),
|
|
34
|
+
"state": self.captured_state,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
__all__ = ["ContinuationToken"]
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Eta Conversion - Extensional equality in Lambda Calculus
|
|
3
|
+
|
|
4
|
+
Eta conversion (η-conversion) captures extensional equivalence:
|
|
5
|
+
λx.(M x) ≡η M (when x is not free in M)
|
|
6
|
+
|
|
7
|
+
This expresses that two functions are equal if they produce the same
|
|
8
|
+
result for all inputs.
|
|
9
|
+
|
|
10
|
+
This module provides Python parity with mcard-js/src/ptr/lambda/EtaConversion.ts
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from clm.layer2.card_collection import CardCollection
|
|
14
|
+
from clm.layer3.satori.alpha_conversion import alpha_equivalent
|
|
15
|
+
from clm.layer3.satori.free_variables import generate_fresh_for, is_free_in
|
|
16
|
+
from clm.layer3.satori.lambda_term import (
|
|
17
|
+
is_abs,
|
|
18
|
+
is_app,
|
|
19
|
+
is_var,
|
|
20
|
+
load_term,
|
|
21
|
+
mk_abs,
|
|
22
|
+
mk_app,
|
|
23
|
+
mk_var,
|
|
24
|
+
store_term,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
28
|
+
# Eta Reduction
|
|
29
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def eta_reduce(collection: CardCollection, hash_value: str) -> str | None:
|
|
33
|
+
"""
|
|
34
|
+
Perform eta reduction on a term.
|
|
35
|
+
|
|
36
|
+
λx.(M x) →η M (when x is not free in M)
|
|
37
|
+
|
|
38
|
+
Returns the reduced term hash, or the original if not reducible.
|
|
39
|
+
"""
|
|
40
|
+
term = load_term(collection, hash_value)
|
|
41
|
+
if term is None:
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
if is_abs(term):
|
|
45
|
+
# Check if body is application
|
|
46
|
+
body = load_term(collection, term.body)
|
|
47
|
+
if body is None:
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
if is_app(body):
|
|
51
|
+
# Check if arg is the bound variable
|
|
52
|
+
arg = load_term(collection, body.arg)
|
|
53
|
+
if arg is None:
|
|
54
|
+
return None
|
|
55
|
+
|
|
56
|
+
if is_var(arg) and arg.name == term.param:
|
|
57
|
+
# Check if param is NOT free in func
|
|
58
|
+
free_check = is_free_in(collection, term.param, body.func)
|
|
59
|
+
if free_check is not None and not free_check:
|
|
60
|
+
# η-reduction applies!
|
|
61
|
+
return body.func
|
|
62
|
+
|
|
63
|
+
# No reduction possible at top level, try subterms
|
|
64
|
+
if is_abs(term):
|
|
65
|
+
new_body = eta_reduce(collection, term.body)
|
|
66
|
+
if new_body is None:
|
|
67
|
+
return None
|
|
68
|
+
if new_body != term.body:
|
|
69
|
+
return store_term(collection, mk_abs(term.param, new_body))
|
|
70
|
+
return hash_value
|
|
71
|
+
|
|
72
|
+
elif is_app(term):
|
|
73
|
+
new_func = eta_reduce(collection, term.func)
|
|
74
|
+
new_arg = eta_reduce(collection, term.arg)
|
|
75
|
+
if new_func is None or new_arg is None:
|
|
76
|
+
return None
|
|
77
|
+
if new_func != term.func or new_arg != term.arg:
|
|
78
|
+
return store_term(collection, mk_app(new_func, new_arg))
|
|
79
|
+
return hash_value
|
|
80
|
+
|
|
81
|
+
return hash_value
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
85
|
+
# Eta Expansion
|
|
86
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def eta_expand(
|
|
90
|
+
collection: CardCollection, hash_value: str, fresh_var: str | None = None
|
|
91
|
+
) -> str | None:
|
|
92
|
+
"""
|
|
93
|
+
Perform eta expansion on a term.
|
|
94
|
+
|
|
95
|
+
M →η λx.(M x) (where x is fresh)
|
|
96
|
+
|
|
97
|
+
Returns the expanded term hash.
|
|
98
|
+
"""
|
|
99
|
+
term = load_term(collection, hash_value)
|
|
100
|
+
if term is None:
|
|
101
|
+
return None
|
|
102
|
+
|
|
103
|
+
# Generate fresh variable if not provided
|
|
104
|
+
if fresh_var is None:
|
|
105
|
+
fresh_var = generate_fresh_for(collection, "η", hash_value)
|
|
106
|
+
|
|
107
|
+
# Create variable term
|
|
108
|
+
var_hash = store_term(collection, mk_var(fresh_var))
|
|
109
|
+
|
|
110
|
+
# Create application: M x
|
|
111
|
+
app_hash = store_term(collection, mk_app(hash_value, var_hash))
|
|
112
|
+
|
|
113
|
+
# Create abstraction: λx.(M x)
|
|
114
|
+
return store_term(collection, mk_abs(fresh_var, app_hash))
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
118
|
+
# Eta Equivalence
|
|
119
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def eta_equivalent(collection: CardCollection, hash1: str, hash2: str) -> bool | None:
|
|
123
|
+
"""
|
|
124
|
+
Check if two terms are η-equivalent.
|
|
125
|
+
|
|
126
|
+
Performs full η-reduction on both terms and checks α-equivalence.
|
|
127
|
+
"""
|
|
128
|
+
# Fully eta-reduce both terms
|
|
129
|
+
reduced1 = fully_eta_reduce(collection, hash1)
|
|
130
|
+
reduced2 = fully_eta_reduce(collection, hash2)
|
|
131
|
+
|
|
132
|
+
if reduced1 is None or reduced2 is None:
|
|
133
|
+
return None
|
|
134
|
+
|
|
135
|
+
# Check alpha equivalence
|
|
136
|
+
return alpha_equivalent(collection, reduced1, reduced2)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def fully_eta_reduce(
|
|
140
|
+
collection: CardCollection, hash_value: str, max_steps: int = 100
|
|
141
|
+
) -> str | None:
|
|
142
|
+
"""
|
|
143
|
+
Repeatedly apply eta reduction until no more reductions apply.
|
|
144
|
+
"""
|
|
145
|
+
current = hash_value
|
|
146
|
+
steps = 0
|
|
147
|
+
|
|
148
|
+
while steps < max_steps:
|
|
149
|
+
reduced = eta_reduce(collection, current)
|
|
150
|
+
if reduced is None:
|
|
151
|
+
return None
|
|
152
|
+
|
|
153
|
+
if reduced == current:
|
|
154
|
+
# No more reductions
|
|
155
|
+
return current
|
|
156
|
+
|
|
157
|
+
current = reduced
|
|
158
|
+
steps += 1
|
|
159
|
+
|
|
160
|
+
return current
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
164
|
+
# Combined Beta-Eta Reduction
|
|
165
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def beta_eta_reduce(collection: CardCollection, hash_value: str) -> str | None:
|
|
169
|
+
"""
|
|
170
|
+
Perform one step of beta or eta reduction.
|
|
171
|
+
Tries beta first, then eta.
|
|
172
|
+
"""
|
|
173
|
+
from clm.layer3.satori.beta_reduction import reduce_step
|
|
174
|
+
|
|
175
|
+
# Try beta reduction first
|
|
176
|
+
beta_result = reduce_step(collection, hash_value, "normal")
|
|
177
|
+
if beta_result is not None:
|
|
178
|
+
return beta_result
|
|
179
|
+
|
|
180
|
+
# Try eta reduction
|
|
181
|
+
eta_result = eta_reduce(collection, hash_value)
|
|
182
|
+
if eta_result is not None and eta_result != hash_value:
|
|
183
|
+
return eta_result
|
|
184
|
+
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def beta_eta_normalize(
|
|
189
|
+
collection: CardCollection, hash_value: str, max_steps: int = 1000
|
|
190
|
+
) -> str | None:
|
|
191
|
+
"""
|
|
192
|
+
Normalize a term using both beta and eta reductions.
|
|
193
|
+
"""
|
|
194
|
+
current = hash_value
|
|
195
|
+
steps = 0
|
|
196
|
+
|
|
197
|
+
while steps < max_steps:
|
|
198
|
+
reduced = beta_eta_reduce(collection, current)
|
|
199
|
+
if reduced is None:
|
|
200
|
+
return current
|
|
201
|
+
|
|
202
|
+
current = reduced
|
|
203
|
+
steps += 1
|
|
204
|
+
|
|
205
|
+
return None
|