diff --git a/docs/examples/examples/thermostat.md b/docs/examples/examples/thermostat.md index 8503592..9a54192 100644 --- a/docs/examples/examples/thermostat.md +++ b/docs/examples/examples/thermostat.md @@ -41,6 +41,15 @@ flowchart TD ## Files -- [model.py](https://github.com/DynamicalSystemsGroup/gds-examples/blob/main/thermostat/model.py) -- [test_model.py](https://github.com/DynamicalSystemsGroup/gds-examples/blob/main/thermostat/test_model.py) -- [VIEWS.md](https://github.com/DynamicalSystemsGroup/gds-examples/blob/main/thermostat/VIEWS.md) +- [model.py](https://github.com/DynamicalSystemsGroup/gds-core/blob/main/packages/gds-examples/control/thermostat/model.py) +- [test_model.py](https://github.com/DynamicalSystemsGroup/gds-core/blob/main/packages/gds-examples/control/thermostat/test_model.py) +- [VIEWS.md](https://github.com/DynamicalSystemsGroup/gds-core/blob/main/packages/gds-examples/control/thermostat/VIEWS.md) + +## Experimental SysML v2 view + +The [SysML export experiment](../sysml/README.md) projects this model into four +parts and three forward connections, with a companion mapping/loss manifest. +That artifact passed the pinned official Pilot validator with zero diagnostics. +The backward Energy Cost feedback is omitted with diagnostics; the view does +not reproduce the thermostat's execution behavior. See the +[interoperability guide](../../guides/sysml-v2.md) for tool integration status. diff --git a/docs/examples/sysml/README.md b/docs/examples/sysml/README.md new file mode 100644 index 0000000..ca5109a --- /dev/null +++ b/docs/examples/sysml/README.md @@ -0,0 +1,92 @@ +# Thermostat SysML v2 structural export + +This first interoperability experiment projects the existing +[thermostat](../examples/thermostat.md) into a +flat architecture view. It generates [thermostat.sysml](thermostat.sysml) and +[thermostat.mapping.json](thermostat.mapping.json). Keep the two files together. + +## Generate + +Generation requires a development checkout containing the experimental +`gds_interchange.sysml` exporter and `thermostat.export_sysml` example; a released +PyPI package is not sufficient. The downloadable artifacts above can be +inspected without installing the exporter. + +Run from that repository root with the workspace environment already installed: + +```bash +PYTHONPATH=packages/gds-examples/control uv run --no-sync python -m thermostat.export_sysml --output-dir docs/examples/sysml +``` + +The command replaces these two generated files in the selected directory. +The source revision is the SHA-256 of `model.py`; it identifies those source +bytes, not the complete Python environment. The manifest records the mapping +version and all caller-supplied wire mappings. + +## What the view means + +| Generated part | GDS block | +|---|---| +| `block0` | PID Controller | +| `block1` | Room Plant | +| `block2` | Temperature Sensor | +| `block3` | Update Room | + +Three `connect` relationships describe forward connectivity. Payload spaces +become item definitions containing scalar attributes; outgoing ports use a +channel definition and incoming ports use its conjugate. These connections do +not encode transfer scheduling or state updates. The representation deliberately +chooses parts as an architecture view, rather than claiming GDS blocks are +universally equivalent to SysML parts. + +The manifest maps generated identifiers back to source registry entries and +port slots using JSON pointers. Names appear as data in the manifest, so spaces, +punctuation, keywords, and repeated port names cannot inject syntax or merge +elements. Generated identifiers are snapshot-local and may change after edits; +they are not persistent SysML repository identities. All exports currently use +the `GDSExport` package name; load them separately to avoid namespace collisions. + +## Explicit limits + +- The backward Energy Cost ports and feedback connection are omitted with + diagnostics. Temporal connections are likewise unsupported. +- Entities, state, parameters, execution contracts, admissibility constraints, + metrics, and transition signatures are outside this projection. +- Only built-in Python `bool`, `int`, `float`, and `str` payloads are projected. + `Real` does not preserve IEEE floating-point behavior. Units and value + constraints are not enforced; custom payload types are rejected from the view + with diagnostics. Unbound forward ports are emitted untyped with diagnostics. +- Only flat atomic-block registries are accepted. Hierarchical composition and + reusable component definitions/usages remain future work. +- There is no importer, API synchronization, or execution-equivalence claim. + +## Validation status + +The exported thermostat was accepted by the official SysML v2 Pilot on +**2026-09-25**, using release `2026-08`, editor build +`0.62.0.202609111953`, and Temurin Java `21.0.12.1+1`. The validator loaded +94 standard-library resources and reported **0 errors and 0 diagnostics**. +Malformed syntax and an unresolved type were rejected as negative controls. + +The [validation evidence](validation/README.md) includes the original logs, +artifact hashes, negative-control models, and Java harness. The recorded model +hash matches the downloadable `thermostat.sysml` above. This is a recorded +validation of one structural artifact, not a claim that every generated model +passes or that GDS and SysML execution are equivalent. + +Python tests separately cover endpoint preservation, manifest serialization, +identifier safety, unsupported semantics, and rejection of invalid or ambiguous +mappings. They do not substitute for a SysML validator. + +The manifest's `validation` field describes generation-time status. Exporting +alone does not invoke a validator, so that field remains unchanged; subsequent +validation belongs in a separate record associated with the artifact hash. + +The next gate is to load the same file and negative controls in a pinned +OpenSysML version, compare diagnostics, and inspect the four parts and three +connection endpoints. OpenSysML, repository synchronization, and reverse import +remain untested integrations. + +See the [SysML interoperability guide](../../guides/sysml-v2.md) for the tool +roles and next steps, and the [comparison study](../../research/sysml-v2-overlap.md) +for the mapping rationale. diff --git a/docs/examples/sysml/thermostat.mapping.json b/docs/examples/sysml/thermostat.mapping.json new file mode 100644 index 0000000..e9d189a --- /dev/null +++ b/docs/examples/sysml/thermostat.mapping.json @@ -0,0 +1,270 @@ +{ + "mapping_version": "gds-sysml-structural/0.1", + "source": { + "uri": "repo:packages/gds-examples/control/thermostat/model.py", + "revision": "sha256:8df2face868474aa60f657b17bfdc35116435106eae0346c96869ec66dc86a55", + "name": "Thermostat PID" + }, + "scope": "flat architecture projection; no execution semantics", + "validation": "not validated by a SysML implementation", + "elements": [ + { + "source_pointer": "", + "target": "GDSExport", + "name": "Thermostat PID" + }, + { + "source_pointer": "/spaces/CommandSpace", + "target": "GDSExport::Payload0", + "name": "CommandSpace" + }, + { + "source_pointer": "/spaces/CommandSpace/fields/heater_power", + "target": "GDSExport::Payload0::field0", + "name": "heater_power", + "type_name": "HeaterPower", + "units": null + }, + { + "source_pointer": "/spaces/EnergyCostSpace", + "target": "GDSExport::Payload1", + "name": "EnergyCostSpace" + }, + { + "source_pointer": "/spaces/EnergyCostSpace/fields/cost", + "target": "GDSExport::Payload1::field0", + "name": "cost", + "type_name": "EnergyCost", + "units": null + }, + { + "source_pointer": "/spaces/RoomStateSpace", + "target": "GDSExport::Payload2", + "name": "RoomStateSpace" + }, + { + "source_pointer": "/spaces/RoomStateSpace/fields/energy", + "target": "GDSExport::Payload2::field0", + "name": "energy", + "type_name": "EnergyCost", + "units": null + }, + { + "source_pointer": "/spaces/RoomStateSpace/fields/temperature", + "target": "GDSExport::Payload2::field1", + "name": "temperature", + "type_name": "Temperature", + "units": null + }, + { + "source_pointer": "/spaces/TemperatureSpace", + "target": "GDSExport::Payload3", + "name": "TemperatureSpace" + }, + { + "source_pointer": "/spaces/TemperatureSpace/fields/temperature", + "target": "GDSExport::Payload3::field0", + "name": "temperature", + "type_name": "Temperature", + "units": null + }, + { + "source_pointer": "/blocks/PID Controller", + "target": "GDSExport::system::block0", + "name": "PID Controller", + "role": "policy" + }, + { + "source_pointer": "/blocks/PID Controller/interface/forward_in/0", + "target": "GDSExport::system::block0::forward_in0", + "name": "Measured Temperature", + "slot": "forward_in" + }, + { + "source_pointer": "/blocks/PID Controller/interface/forward_out/0", + "target": "GDSExport::system::block0::forward_out0", + "name": "Heater Command", + "slot": "forward_out" + }, + { + "source_pointer": "/blocks/Room Plant", + "target": "GDSExport::system::block1", + "name": "Room Plant", + "role": "control" + }, + { + "source_pointer": "/blocks/Room Plant/interface/forward_in/0", + "target": "GDSExport::system::block1::forward_in0", + "name": "Heater Command", + "slot": "forward_in" + }, + { + "source_pointer": "/blocks/Room Plant/interface/forward_out/0", + "target": "GDSExport::system::block1::forward_out0", + "name": "Room State", + "slot": "forward_out" + }, + { + "source_pointer": "/blocks/Temperature Sensor", + "target": "GDSExport::system::block2", + "name": "Temperature Sensor", + "role": "boundary" + }, + { + "source_pointer": "/blocks/Temperature Sensor/interface/forward_out/0", + "target": "GDSExport::system::block2::forward_out0", + "name": "Measured Temperature", + "slot": "forward_out" + }, + { + "source_pointer": "/blocks/Update Room", + "target": "GDSExport::system::block3", + "name": "Update Room", + "role": "mechanism" + }, + { + "source_pointer": "/blocks/Update Room/interface/forward_in/0", + "target": "GDSExport::system::block3::forward_in0", + "name": "Room State", + "slot": "forward_in" + }, + { + "source_pointer": "/wirings/Thermostat Loop/wires/0", + "target": "GDSExport::system::wire0", + "source_port": "block2.forward_out0", + "target_port": "block0.forward_in0", + "kind": "forward" + }, + { + "source_pointer": "/wirings/Thermostat Loop/wires/1", + "target": "GDSExport::system::wire1", + "source_port": "block0.forward_out0", + "target_port": "block1.forward_in0", + "kind": "forward" + }, + { + "source_pointer": "/wirings/Thermostat Loop/wires/2", + "target": "GDSExport::system::wire2", + "source_port": "block1.forward_out0", + "target_port": "block3.forward_in0", + "kind": "forward" + } + ], + "diagnostics": [ + { + "code": "STRUCTURAL_ONLY", + "source_pointer": "", + "message": "Behavior, roles and scheduling are not executable." + }, + { + "code": "ANNOTATIONS_OMITTED", + "source_pointer": "", + "message": "Descriptions, tags and logic are not projected." + }, + { + "code": "OUT_OF_SCOPE", + "source_pointer": "/entities", + "message": "entities is not projected." + }, + { + "code": "OUT_OF_SCOPE", + "source_pointer": "/parameter_schema", + "message": "parameter_schema is not projected." + }, + { + "code": "OUT_OF_SCOPE", + "source_pointer": "/admissibility_constraints", + "message": "admissibility_constraints is not projected." + }, + { + "code": "SCALAR_APPROXIMATION", + "source_pointer": "/spaces/CommandSpace/fields/heater_power", + "message": "Python float projected as Real." + }, + { + "code": "TYPE_SEMANTICS_OMITTED", + "source_pointer": "/spaces/CommandSpace/fields/heater_power", + "message": "Units and value constraints are not enforced in this view." + }, + { + "code": "SCALAR_APPROXIMATION", + "source_pointer": "/spaces/EnergyCostSpace/fields/cost", + "message": "Python float projected as Real." + }, + { + "code": "TYPE_SEMANTICS_OMITTED", + "source_pointer": "/spaces/EnergyCostSpace/fields/cost", + "message": "Units and value constraints are not enforced in this view." + }, + { + "code": "SCALAR_APPROXIMATION", + "source_pointer": "/spaces/RoomStateSpace/fields/energy", + "message": "Python float projected as Real." + }, + { + "code": "TYPE_SEMANTICS_OMITTED", + "source_pointer": "/spaces/RoomStateSpace/fields/energy", + "message": "Units and value constraints are not enforced in this view." + }, + { + "code": "SCALAR_APPROXIMATION", + "source_pointer": "/spaces/RoomStateSpace/fields/temperature", + "message": "Python float projected as Real." + }, + { + "code": "SCALAR_APPROXIMATION", + "source_pointer": "/spaces/TemperatureSpace/fields/temperature", + "message": "Python float projected as Real." + }, + { + "code": "TYPE_REGISTRY_PROJECTED", + "source_pointer": "/types", + "message": "Only space field scalar types are projected; named types are not defined." + }, + { + "code": "UNSUPPORTED_CONNECTION", + "source_pointer": "/wirings/Thermostat Loop/wires/3", + "message": "feedback connection omitted; no execution interpretation." + }, + { + "code": "BACKWARD_PORT", + "source_pointer": "/blocks/PID Controller/interface/backward_in/0", + "message": "Backward channel omitted." + }, + { + "code": "BACKWARD_PORT", + "source_pointer": "/blocks/Room Plant/interface/backward_out/0", + "message": "Backward channel omitted." + } + ], + "connections": [ + { + "wiring": "Thermostat Loop", + "wire_index": 0, + "source_port": "Measured Temperature", + "target_port": "Measured Temperature", + "kind": "forward" + }, + { + "wiring": "Thermostat Loop", + "wire_index": 1, + "source_port": "Heater Command", + "target_port": "Heater Command", + "kind": "forward" + }, + { + "wiring": "Thermostat Loop", + "wire_index": 2, + "source_port": "Room State", + "target_port": "Room State", + "kind": "forward" + }, + { + "wiring": "Thermostat Loop", + "wire_index": 3, + "source_port": "Energy Cost", + "target_port": "Energy Cost", + "kind": "feedback" + } + ] +} diff --git a/docs/examples/sysml/thermostat.sysml b/docs/examples/sysml/thermostat.sysml new file mode 100644 index 0000000..4458258 --- /dev/null +++ b/docs/examples/sysml/thermostat.sysml @@ -0,0 +1,47 @@ +// Experimental GDS structural view; see companion mapping manifest. +package GDSExport { + item def Payload0 { + attribute field0 : ScalarValues::Real; + } + port def Channel0 { + out item payload : Payload0; + } + item def Payload1 { + attribute field0 : ScalarValues::Real; + } + port def Channel1 { + out item payload : Payload1; + } + item def Payload2 { + attribute field0 : ScalarValues::Real; + attribute field1 : ScalarValues::Real; + } + port def Channel2 { + out item payload : Payload2; + } + item def Payload3 { + attribute field0 : ScalarValues::Real; + } + port def Channel3 { + out item payload : Payload3; + } + part system { + part block0 { + port forward_in0 : ~Channel3; + port forward_out0 : Channel0; + } + part block1 { + port forward_in0 : ~Channel0; + port forward_out0 : Channel2; + } + part block2 { + port forward_out0 : Channel3; + } + part block3 { + port forward_in0 : ~Channel2; + } + connection wire0 connect block2.forward_out0 to block0.forward_in0; + connection wire1 connect block0.forward_out0 to block1.forward_in0; + connection wire2 connect block1.forward_out0 to block3.forward_in0; + } +} diff --git a/docs/examples/sysml/validation/README.md b/docs/examples/sysml/validation/README.md new file mode 100644 index 0000000..9b8516a --- /dev/null +++ b/docs/examples/sysml/validation/README.md @@ -0,0 +1,49 @@ +# Thermostat Pilot validation evidence + +These files preserve the local validation run from **2026-09-25**. They were +copied from the SysML validation lab on 2026-10-04; validation was not rerun as +part of that documentation update. + +| Setting | Recorded value | +|---|---| +| Official Pilot release | `2026-08` | +| Editor build | `0.62.0.202609111953` | +| Java | Temurin `21.0.12.1+1` | +| Loaded standard-library resources | 94 | +| Thermostat result | 0 errors, 0 diagnostics | +| Unresolved-type control | 4 errors; rejected | +| Malformed-syntax control | 1 error; rejected | + +## Download the evidence + +- [Original validation record and SHA-256 hashes](validation-record.json) +- [Thermostat validator output](thermostat-validation.txt) +- [Unresolved-type output](unresolved.txt) and [input model](unresolved.sysml) +- [Malformed-syntax output](syntax-error.txt) and [input model](syntax-error.sysml) +- [Java validation harness](ValidateSysML.java) +- [Validated thermostat](../thermostat.sysml) and [mapping manifest](../thermostat.mapping.json) + +The record retains paths from the original lab. The unresolved-reference log +likewise contains original local file URIs; these are not website endpoints. +The copied logs and harness retain their recorded hashes. The thermostat's +SHA-256 is: + +```text +1caafbc77103bfb50312fbf5d696b622da11507eaaab7d9babbd09049be1a1e4 +``` + +## What was checked + +The local Java harness invokes the official Pilot's `IResourceValidator` after +loading the matching standard libraries. It validates one user model; it does +not automatically load sibling user models or validate every library file. +The lab recorded nonzero exits for both negative controls. + +This evidence establishes acceptance of this structural view by that validator +and version. It does not establish behavior, timing, units, simulation +equivalence, round-trip preservation, or compatibility with OpenSysML. + +To repeat the check, use the pinned Pilot distribution and matching libraries +with a compatible Java installation and the supplied harness. The large Java, +Eclipse, and library distributions are not bundled here. A new run should retain +its own tool versions, diagnostics, and artifact hashes. diff --git a/docs/examples/sysml/validation/ValidateSysML.java b/docs/examples/sysml/validation/ValidateSysML.java new file mode 100644 index 0000000..ce61103 --- /dev/null +++ b/docs/examples/sysml/validation/ValidateSysML.java @@ -0,0 +1,46 @@ +import java.nio.file.Path; +import com.google.inject.Injector; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.diagnostics.Severity; +import org.eclipse.xtext.util.CancelIndicator; +import org.eclipse.xtext.validation.CheckMode; +import org.eclipse.xtext.validation.IResourceValidator; +import org.omg.kerml.xtext.KerMLStandaloneSetup; +import org.omg.sysml.io.SysMLUtil; +import org.omg.sysml.util.SysMLLibraryUtil; +import org.omg.sysml.xtext.SysMLStandaloneSetup; + +/** Small local harness around the unmodified official Pilot validator. */ +public class ValidateSysML extends SysMLUtil { + public ValidateSysML() { + addExtension(".kerml"); + addExtension(".sysml"); + setVerbose(false); + } + public static void main(String[] args) throws Exception { + if (args.length != 2) { + System.err.println("Usage: ValidateSysML "); + System.exit(2); + } + KerMLStandaloneSetup.doSetup(); + Injector injector = new SysMLStandaloneSetup().createInjectorAndDoEMFRegistration(); + ValidateSysML loader = new ValidateSysML(); + String library = Path.of(args[0]).toAbsolutePath().toString(); + SysMLLibraryUtil.setModelLibraryDirectory(library + "/"); + loader.readAll(library + "/Kernel Libraries", false); + loader.readAll(library + "/Systems Library", false); + loader.readAll(library + "/Domain Libraries", false); + System.out.println("Loaded library resources: " + loader.getResourceSet().getResources().size()); + Resource model = loader.readResource(Path.of(args[1]).toAbsolutePath().toString()); + loader.addInputResource(model); + var issues = injector.getInstance(IResourceValidator.class) + .validate(model, CheckMode.ALL, CancelIndicator.NullImpl); + long errors = 0; + for (var issue : issues) { + System.out.printf("%s line %s: %s%n", issue.getSeverity(), issue.getLineNumber(), issue.getMessage()); + if (issue.getSeverity() == Severity.ERROR) errors++; + } + System.out.printf("Validation complete: %d errors, %d total diagnostics.%n", errors, issues.size()); + System.exit(errors == 0 ? 0 : 1); + } +} diff --git a/docs/examples/sysml/validation/syntax-error.sysml b/docs/examples/sysml/validation/syntax-error.sysml new file mode 100644 index 0000000..01979aa --- /dev/null +++ b/docs/examples/sysml/validation/syntax-error.sysml @@ -0,0 +1,3 @@ +package NegativeControl { + part p : ; +} diff --git a/docs/examples/sysml/validation/syntax-error.txt b/docs/examples/sysml/validation/syntax-error.txt new file mode 100644 index 0000000..37ddf17 --- /dev/null +++ b/docs/examples/sysml/validation/syntax-error.txt @@ -0,0 +1,3 @@ +Loaded library resources: 94 +ERROR line 2: no viable alternative at input ';' +Validation complete: 1 errors, 1 total diagnostics. diff --git a/docs/examples/sysml/validation/thermostat-validation.txt b/docs/examples/sysml/validation/thermostat-validation.txt new file mode 100644 index 0000000..b344b8b --- /dev/null +++ b/docs/examples/sysml/validation/thermostat-validation.txt @@ -0,0 +1,2 @@ +Loaded library resources: 94 +Validation complete: 0 errors, 0 total diagnostics. diff --git a/docs/examples/sysml/validation/unresolved.sysml b/docs/examples/sysml/validation/unresolved.sysml new file mode 100644 index 0000000..344e718 --- /dev/null +++ b/docs/examples/sysml/validation/unresolved.sysml @@ -0,0 +1,3 @@ +package NegativeControl { + part broken : MissingDefinition; +} diff --git a/docs/examples/sysml/validation/unresolved.txt b/docs/examples/sysml/validation/unresolved.txt new file mode 100644 index 0000000..9b2461a --- /dev/null +++ b/docs/examples/sysml/validation/unresolved.txt @@ -0,0 +1,6 @@ +Loaded library resources: 94 +ERROR line 2: Couldn't resolve reference to Type 'MissingDefinition'. +ERROR line 2: An occurrence, item or part must be typed by occurrence definitions. +ERROR line 2: The feature 'relatedElement' of 'org.omg.sysml.lang.sysml.impl.FeatureTypingImpl@79992e2f{file:/home/rohan/Documents/Github/work/dsg/sysml-v2-lab/tests/unresolved.sysml#//@ownedRelationship.0/@ownedRelatedElement.0/@ownedRelationship.0/@ownedRelatedElement.0/@ownedRelationship.0}' contains an unresolved proxy 'org.omg.sysml.lang.sysml.impl.TypeImpl@33ae1d53{file:/home/rohan/Documents/Github/work/dsg/sysml-v2-lab/tests/unresolved.sysml#|0}' +ERROR line 2: The feature 'type' of 'org.omg.sysml.lang.sysml.impl.FeatureTypingImpl@79992e2f{file:/home/rohan/Documents/Github/work/dsg/sysml-v2-lab/tests/unresolved.sysml#//@ownedRelationship.0/@ownedRelatedElement.0/@ownedRelationship.0/@ownedRelatedElement.0/@ownedRelationship.0}' contains an unresolved proxy 'org.omg.sysml.lang.sysml.impl.TypeImpl@33ae1d53{file:/home/rohan/Documents/Github/work/dsg/sysml-v2-lab/tests/unresolved.sysml#|0}' +Validation complete: 4 errors, 4 total diagnostics. diff --git a/docs/examples/sysml/validation/validation-record.json b/docs/examples/sysml/validation/validation-record.json new file mode 100644 index 0000000..d89b02b --- /dev/null +++ b/docs/examples/sysml/validation/validation-record.json @@ -0,0 +1,15 @@ +{ + "timestamp_utc": "2026-09-25T05:54:55.778873+00:00", + "pilot_release": "2026-08", + "pilot_build": "0.62.0.202609111953", + "java": "Temurin 21.0.12.1+1", + "result": "thermostat accepted; syntax and unresolved-reference controls rejected", + "sha256": { + "projects/gds-interop/src/thermostat.sysml": "1caafbc77103bfb50312fbf5d696b622da11507eaaab7d9babbd09049be1a1e4", + "projects/gds-interop/src/thermostat.mapping.json": "0700f2e182c66c44b61c1f08cc7e229edf1e0a8cf39f0f450118d2093e6787b6", + "src/ValidateSysML.java": "11c44f25d87e31a38dec5d38d2d6755f0d12cd680f4bcaec2827a9cc1278c987", + "logs/thermostat-validation.log": "abb880ab96fc96d38c8dd62517175f9fb063c29958cb3111b06bf28e987975da", + "logs/unresolved.log": "d40aaa695e6c99b4b9b779e3ed98dde89e53fec16861c86ee45f09eff279821f", + "logs/syntax-error.log": "eff7509119d1b64b9f8d826d6ac1d07e13fc426edd4a45cc08775832043d8ff0" + } +} diff --git a/docs/framework/design/proposals/entity-redesign.md b/docs/framework/design/proposals/entity-redesign.md index e71fb63..4245e8f 100644 --- a/docs/framework/design/proposals/entity-redesign.md +++ b/docs/framework/design/proposals/entity-redesign.md @@ -4,6 +4,15 @@ **Authors:** [core team] **Date:** 2026-02-16 +!!! note "Current implementation status (2026-10-04)" + This document preserves the original design proposal. Its SysML import, + unit-library, rich entity, and round-trip mappings are proposed capabilities, + not established integrations. Subsequent development provides a bounded + one-way [structural export](../../../guides/sysml-v2.md); the + [thermostat artifact](../../../examples/sysml/README.md) passed the official + Pilot validator. That result does not establish the broader mappings or + execution equivalence described below. + --- ## Summary diff --git a/docs/framework/ecosystem.md b/docs/framework/ecosystem.md index e68b94c..9faab5b 100644 --- a/docs/framework/ecosystem.md +++ b/docs/framework/ecosystem.md @@ -13,6 +13,8 @@ The GDS ecosystem is a family of composable packages for specifying, visualizing | | `gds_domains.games` | Typed DSL for compositional game theory (Open Games) | | | `gds_domains.software` | Software architecture DSL (DFD, state machine, C4, ERD, etc.) | | | `gds_domains.business` | Business dynamics DSL (CLD, supply chain, value stream map) | +| | `gds_domains.symbolic` | Symbolic equations and linearization; install `gds-domains[symbolic]` | +| **gds-interchange** | `gds_interchange.owl` | OWL/Turtle, SHACL, SPARQL, and RDF round-trip tooling | | **gds-sim** | `gds_sim` | Simulation engine (standalone, Pydantic-only) | | **gds-continuous** | `gds_continuous` | Continuous-time ODE simulation engine | | **gds-analysis** | `gds_analysis` | GDSSpec-to-gds-sim bridge, reachability, trajectory metrics | @@ -20,6 +22,12 @@ The GDS ecosystem is a family of composable packages for specifying, visualizing | **gds-psuu** | `gds_psuu` | Deprecated compatibility package for `gds_analysis.psuu` | | **gds-examples** | — | Tutorial models demonstrating framework features | +An experimental development exporter at `gds_interchange.sysml` projects flat +GDS architectures into SysML v2 text with a mapping/loss manifest. See +[SysML v2 interoperability](../guides/sysml-v2.md) for recorded Pilot validation, +unsupported semantics, and the untested OpenSysML and repository integrations. +Use the [package map](../packages/index.md) for current installation choices. + ## Dependency Graph ```mermaid diff --git a/docs/guides/interoperability.md b/docs/guides/interoperability.md index 703de7f..af9f0c5 100644 --- a/docs/guides/interoperability.md +++ b/docs/guides/interoperability.md @@ -1,5 +1,9 @@ # Interoperability: From Specification to Computation +For engineering architecture exchange, see the experimental +[SysML v2 interoperability guide](sysml-v2.md), including the recorded Pilot +validation and the boundaries for OpenSysML and repository integration. + > GDS specifications are not just documentation — they are structured representations that project cleanly onto domain-specific computation. This guide demonstrates two concrete projections: **Nash equilibrium computation** (game theory) and **iterated tournament simulation** (evolutionary dynamics), both built on the same OGS game structure without modifying the framework. --- diff --git a/docs/guides/sysml-v2.md b/docs/guides/sysml-v2.md new file mode 100644 index 0000000..de1ccae --- /dev/null +++ b/docs/guides/sysml-v2.md @@ -0,0 +1,106 @@ +# SysML v2 interoperability + +GDS can project a specification into a SysML v2 architecture view for inspection +by engineering tools. The experimental `gds_interchange.sysml` exporter produces +text and a mapping/loss manifest. The thermostat export has passed the official +Pilot validator; OpenSysML and repository-backed exchange remain untested. + +The exporter remains unmerged development work. The downloadable artifacts +and validation evidence below are available for inspection, but generation +requires a development checkout containing the exporter. It is not part of the +published symbolic security releases. + +## What is available + +`spec_to_sysml` accepts a flat registry of atomic blocks and explicit wire +mappings. It exports parts, forward ports, scalar payload definitions, and +forward connections. Its result contains `text` and `manifest_json()`. + +Keep the `.sysml` file and manifest together. The manifest records source URI, +source revision, mapping version, source-to-target entries, and diagnostics for +omitted semantics. Third-party tools do not automatically interpret this +GDS-specific manifest. + +The [thermostat example](../examples/sysml/README.md) includes downloadable +artifacts and a generation command. Its four parts and three forward connections +were accepted by the official Pilot on 2026-09-25, with zero errors and zero +diagnostics. The [validation evidence](../examples/sysml/validation/README.md) +records the versions, hashes, logs, and negative controls. + +## How the tools fit together + +| Tool or repository | Role alongside GDS | Integration status | +|---|---|---| +| GDS / `gds-interchange` | Generate a structural view and preserve mapping provenance | Experimental exporter exists | +| Official SysML v2 Pilot | Parse, resolve references, and validate SysML against matching libraries | Thermostat accepted by a pinned version | +| OpenSysML | An additional language implementation with validation, model inspection, execution, and client APIs | Candidate consumer; GDS compatibility untested | +| Flexo / MMS | Store engineering models in repositories with projects, branches, and revisions | Proposed GDS exchange target | +| SysML v2 Web Modeler | Edit and render models through a SysML v2 API-backed service | Proposed consumer; GDS exchange untested | +| Eclipse SysON | An alternative SysML v2 modeling environment | Import/export capabilities must be checked for a chosen release | + +[OpenSysML](https://github.com/Open-MBEE/opensysml) provides a Go implementation, +language server, REPL, runtime, and programmatic clients. Its execution support +creates overlap with GDS analysis, but equivalent results require explicit +behavioral mappings and tests. Acceptance by the Pilot does not establish +acceptance by OpenSysML. + +[SysML v2 Web Modeler](https://github.com/Open-MBEE/sysmlv2-web-modeler) provides +text editing and model rendering against a repository API. +[Eclipse SysON](https://projects.eclipse.org/projects/modeling.syson) provides +web-based modeling. They are possible ways to inspect or edit an exchanged +architecture; neither has been tested with this GDS export. + +A possible workflow is: + +```mermaid +flowchart LR + G["GDS specification"] --> E["SysML text + mapping manifest"] + E --> P["Pilot validation: thermostat tested"] + E -.-> O["OpenSysML validation and inspection: proposed"] + P -.-> R["Versioned model repository: proposed"] + O -.-> R + R -.-> V["Engineering editor and views: proposed"] +``` + +Dashed connections describe proposed integrations. The manifest must remain +associated with the source snapshot even when a repository stores the SysML +elements separately from the original text. + +## Boundaries that matter + +- **Behavior:** forward connectivity does not specify scheduling or state + updates. Backward feedback and temporal wiring are omitted with diagnostics. + GDS roles and execution contracts are not executable SysML behavior. +- **Types:** built-in scalar payloads are supported. Units, constraints, custom + payload types, and IEEE floating-point semantics are not preserved by this + projection. +- **Composition:** only flat atomic-block registries are accepted. Hierarchical + composition and reusable definition/usage mappings need further design. +- **Identity:** generated identifiers are snapshot-local. They are not stable + repository element identities, so edits cannot yet be reliably synchronized. +- **Direction:** there is no SysML importer, round-trip editing, API + synchronization, or demonstrated simulation equivalence. + +OpenSysML documents repository comparison and synchronization through its +[CLI](https://opensysml.org/reference/cli/). These operate on element identities; +transport support alone does not solve GDS identity or semantic mapping. +The [SysML v2 API reference implementation](https://github.com/Systems-Modeling/SysML-v2-API-Services) +is a separate integration boundary from the textual language. + +## Next acceptance gates + +1. Pin an OpenSysML version and its compatible libraries. Load the unchanged + thermostat and both negative-control files; retain diagnostics and hashes. +2. Inspect the four parts and all three connection endpoint pairs. Compare them + with the GDS manifest and the recorded Pilot result. +3. Test a repository import on a separate branch, preserving source text, + manifest, source revision, and validation evidence. Check identity and + revision behavior before attempting synchronization. +4. Define a selected reverse mapping only after structural exchange works. + Executable analysis additionally requires explicit units, time contracts, + supported functions, and behavior-equivalence tests. + +The [comparison study](../research/sysml-v2-overlap.md) explains the underlying +mapping choices. Use the existing [OWL bridge](../owl/index.md) when RDF, +SHACL, or SPARQL is the required interface; RDF output by itself does not +establish SysML v2 API compatibility. diff --git a/docs/index.md b/docs/index.md index 658c9b3..0b5bac0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,6 +25,7 @@ GDS gives you a composition algebra for modeling complex systems — from epidem | Understand specification vs execution | [Concepts](concepts/specification-vs-execution.md) | | Bridge `GDSSpec` structures to runtime models | [gds-analysis](analysis/index.md) | | Sweep or optimize parameters | [Parameter Sweep](guides/parameter-sweep.md) | +| Exchange a structural model with SysML v2 tools | [SysML v2 Interoperability](guides/sysml-v2.md) (experimental) | ## Interactive Notebooks @@ -51,6 +52,12 @@ names, import paths, and how the pieces fit together. | [`gds-viz`](viz/index.md) | `gds_viz` | Mermaid diagrams + [phase portraits](viz/index.md) `[phase]` | | [`gds-interchange`](owl/index.md) | `gds_interchange.owl` | OWL/SHACL/SPARQL export for formal representability | +Development work also includes an experimental +[SysML v2 structural exporter](guides/sysml-v2.md). Its thermostat artifact has +passed the official Pilot validator. This does not establish behavioral +equivalence or tested OpenSysML/repository synchronization, and the exporter is +not part of the published symbolic security releases. + ### Domain DSLs | Package | Import | Description | diff --git a/docs/owl/index.md b/docs/owl/index.md index ff794bd..3688f69 100644 --- a/docs/owl/index.md +++ b/docs/owl/index.md @@ -15,6 +15,11 @@ ## What is this? +This page covers `gds_interchange.owl`. For the experimental SysML v2 structural +projection, see [SysML v2 interoperability](../guides/sysml-v2.md). The two +formats have separate mapping and validation boundaries; RDF output alone does +not establish SysML v2 API compatibility. + `gds-owl` exports GDS specifications to RDF/OWL and imports them back, enabling interoperability with semantic web tooling. It provides: - **OWL ontology** — class hierarchy mirroring GDS types (blocks, roles, entities, spaces, parameters) diff --git a/docs/packages/index.md b/docs/packages/index.md index 7c50754..3f0674d 100644 --- a/docs/packages/index.md +++ b/docs/packages/index.md @@ -40,6 +40,7 @@ graph TD | Use a domain vocabulary | [Choosing a DSL](../guides/choosing-a-dsl.md) | `gds-domains.*` | | Render diagrams | [Visualization](../viz/index.md) | `gds-viz` | | Export OWL, SHACL, or SPARQL | [OWL](../owl/index.md) | `gds-interchange` | +| Inspect a SysML v2 architecture view | [SysML v2 interoperability](../guides/sysml-v2.md) (experimental development work) | `gds_interchange.sysml` | | Run discrete-time simulations | [Simulation](../sim/index.md) | `gds-sim` | | Run ODE simulations | [Continuous-Time](../continuous/index.md) | `gds-continuous` | | Bridge `GDSSpec` to simulation | [Analysis](../analysis/index.md) | `gds-analysis` | @@ -52,6 +53,7 @@ graph TD | [`gds-framework`](../framework/index.md) | `gds` | Core specification, composition, compilation, and structural verification | | [`gds-viz`](../viz/index.md) | `gds_viz` | Mermaid diagrams and visual projections of GDS specifications | | [`gds-interchange`](../owl/index.md) | `gds_interchange.owl` | OWL, SHACL, SPARQL, and semantic-web interchange | +| Experimental development exporter | `gds_interchange.sysml` | [SysML v2 structural projection](../guides/sysml-v2.md) with a mapping/loss manifest; not a released integration | | [`gds-proof`](../proof/index.md) | `gds_proof` | Deterministic model identity and symbolic invariant proof checks | ## Domain DSLs diff --git a/docs/research/sysml-v2-overlap.md b/docs/research/sysml-v2-overlap.md new file mode 100644 index 0000000..7c88d74 --- /dev/null +++ b/docs/research/sysml-v2-overlap.md @@ -0,0 +1,90 @@ +# SysML v2: ideas and interoperability with GDS + +Initial research: 2026-09-24. Status updated: 2026-10-04. + +The original source study below informed an experimental structural exporter. +The [thermostat export](../examples/sysml/README.md) subsequently passed the +official Pilot validator on 2026-09-25. See the +[interoperability guide](../guides/sysml-v2.md) for current tool roles and limits. + +## Assessment + +The strongest opportunity is to connect SysML architecture and engineering context to GDS specifications and analysis through a deliberately bounded mapping. Shared concepts include typed interfaces, composition, state, behavior, validation, and multiple views. Those similarities do **not** establish interchangeable semantics. GDS's four block roles, directional composition, and canonical dynamical decomposition need an explicit interpretation in a SysML model; a generic SysML model does not automatically supply one. Evidence and proposed mappings are separated below. + +Scope: the official [Pilot Implementation][pilot], its [release distribution][release], and the separate [API and Services implementation][api]. Pilot source links below are pinned to commit `5cca16d846016e62bb1e54e0e50e675254a022ef`; release/API documentation was read on the research date. Local comparison uses the current working tree. + +## What to study in the reference implementation + +| Layer | Evidence | Relevance to GDS | +|---|---|---| +| Textual language | [KerML grammar][kerml-grammar], [SysML grammar][sysml-grammar] | A broad modeling language built around reusable semantic concepts. Both grammars use the KerML expression grammar and reference the EMF model; do not mistake the SysML grammar for a direct subclass of the KerML grammar. Compare with GDS's Python DSLs and shared compilation target. | +| Semantic objects | [Definition][definition], [Usage][usage] | Reusable definitions and contextual usages, including nested usages. This distinction is richer than merely repeating a block name or copying a Python object. | +| Semantic processing | [FeatureAdapter][feature-adapter] | Derived features and relationships require semantic processing beyond parsing surface syntax. An importer needs resolved meanings, not just keyword matching. | +| Validation | [SysMLValidator][validator] | Checks definition/usage typing, ports, and other language constraints. Compare its separation from the model with GDS's [generic checks](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/verification/generic_checks.py) and [spec checks](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/verification/spec_checks.py). | +| Evaluation | [ExpressionEvaluator][evaluator] | The inspected execution module evaluates expressions and function invocations, with numerical/collection library functions. This establishes expression evaluation, not a demonstrated general event simulator or ODE solver. No execution equivalence with GDS was established. | +| Distribution and persistence | [Release documentation][release], [API documentation][api] | Examples, normative libraries, editors, and model archives are distinct from the REST service. A file exchange experiment need not introduce the service or its PostgreSQL deployment. | + +## Overlap and the important mismatches + +| Topic | GDS evidence | Interpretation for interoperability | +|---|---|---| +| Types and reusable components | [TypeDef](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/types/typedef.py), [Interface](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/types/interface.py), [blocks](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/blocks/base.py) | SysML definition/usage is an idea worth borrowing for repeated component instances. A GDS `TypeDef` is a data type, not a universal equivalent of a SysML definition. | +| Ports and connections | [Interface](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/types/interface.py), [IR](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/ir/models.py); SysML [port validation][validator] | GDS uses four forward/backward input/output slots and token sets. SysML has typed port usages and conjugation. Similar names or opposite arrow directions do not prove equivalent type or variance semantics. | +| State and behavior | [state](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/state.py), [canonical projection](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/canonical.py); SysML [grammar][sysml-grammar] | SysML parts, attributes, actions, states, and transitions can describe relevant context, but mapping them to `Entity`, `Policy`, or `Mechanism` requires a modeling convention. A SysML action need not be a GDS policy or state updater. | +| Time | [ExecutionContract](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/execution.py), [composition](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/blocks/composition.py); SysML [successions/transitions][sysml-grammar] | GDS temporal loops and within-evaluation feedback differ; neither automatically means a SysML succession or state transition. Require an explicit time interpretation before importing executable behavior. | +| Simulation | [analysis adapter](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-analysis/gds_analysis/adapter.py) | The current adapter groups policies and state updates into one update block and documents that sequential tier dependencies are not yet modeled. It does not enforce the `ExecutionContract` requirement stated in that class's documentation. A syntactically valid structural import therefore cannot promise preserved execution. | +| Constraints and results | [TypeDef](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/types/typedef.py), [OWL importer](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-interchange/gds_interchange/owl/import_.py); SysML [requirements/constraints/analysis cases][sysml-grammar] | Recognized bounds and enumerations are plausible portable subsets. Arbitrary Python predicates and transitions need external implementations or an agreed expression subset. A linked GDS check result is evidence about its stated check, not automatic satisfaction of a SysML requirement. | +| Identity and interchange | [OWL export](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-interchange/gds_interchange/owl/export.py), [IR serialization](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/ir/serialization.py) | GDS already exports model structure and findings. Its RDF URIs are derived from names; a bridge should preserve source identity and revision independently of display names. RDF output alone does not confer SysML API compatibility. | + +## Ideas worth borrowing + +These are design proposals inferred from the comparison, not features already implemented here. + +1. **Separate reusable definitions from usages where reuse becomes painful.** Start in a bridge's mapping records: component definition, contextual occurrence, and qualified owner. This avoids changing the whole GDS core before a repeated-component example proves the need. Study [Usage][usage] alongside GDS's [block/IR identity model](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/ir/models.py). +2. **Make semantic libraries explicit and versioned.** A small mapping library can declare which GDS roles, data types, units, and execution conventions a SysML model assumes. SysML's release already distributes normative libraries; GDS already records type units and constraint metadata. Those are foundations for a mapping, not automatic unit conversion. Sources: [release][release], [TypeDef](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/types/typedef.py). +3. **Treat provenance and unsupported semantics as data.** Carry source element identity, source revision, mapping version, and diagnostics alongside exported/imported objects. Distinguish preserved, approximated, and unsupported fields. Existing [IR metadata](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/ir/serialization.py) and [OWL loss handling](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-interchange/gds_interchange/owl/import_.py) give useful local precedents. +4. **Preserve separate structural and behavioral claims.** Successfully resolving and validating a SysML model proves neither GDS role correctness nor simulation equivalence. Run each validator at its own boundary and retain its findings. Sources: [SysMLValidator][validator], [GDS checks](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-framework/gds/verification/spec_checks.py), [analysis adapter](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-analysis/gds_analysis/adapter.py). + +## Practical interoperability routes + +| Route | Proposed scope | Main boundary | Priority | +|---|---|---|---| +| GDS → `.sysml` architecture view | Export a declared subset of hierarchy, components, port payloads, and explicit connections; retain GDS roles and wire classifications in mapping metadata. | This is a structural projection. Choosing parts versus actions is an explicit view decision, not a universal mapping. Validate with the Pilot and matching libraries. | First | +| SysML → GDS analysis input | Select a model subset, preserve its source IDs, bind supported attributes/parameters and approved GDS functions, run a specified analysis, and produce source-linked findings/results. | Arbitrary actions, transitions, units, inheritance, multiplicity, and timing cannot be silently collapsed. Resolve or reject each unsupported case. | After one structural example | +| API-backed exchange | Read model elements from a chosen repository and exchange selected model/result artifacts using its supported API. | REST is transport/persistence; it does not solve the semantic mapping. Pin server/schema versions and test actual capabilities before designing synchronization. | Later, if a real tool requires it | + +The experiment now lives in the `gds_interchange.sysml` subpackage. It is an experimental one-way structural exporter alongside the existing OWL tooling, with a mapping/loss manifest. See the [thermostat example](../examples/sysml/README.md). Reuse GDS's structural serializers where appropriate, but keep mapping decisions explicit rather than routing everything through RDF by default. + +### A bounded first experiment + +Use the existing [thermostat example](https://github.com/DynamicalSystemsGroup/gds-core/blob/2d5d3c7/packages/gds-examples/control/thermostat/model.py) to answer: *Can an engineering architecture tool inspect our components and interfaces while retaining enough provenance to trace back to GDS?* + +1. Define the supported structural subset and a mapping manifest. Include declared payload types, ownership, source identity, and wire classification. Do not infer a physical quantity type from a port's display name. +2. Export a forward-connection structural view plus the manifest. Keep backward `Energy Cost` and temporal-loop relationships explicit as unsupported or separately described semantics; do not relabel them as ordinary connections and claim equivalence. +3. Parse, resolve, and validate the output using one pinned Pilot/library version. Check component/port ownership and selected connection endpoints against the original GDS model, including repeated names under different owners. +4. Require an explicit diagnostic for each excluded construct. Successful parsing is the first gate; structural preservation and traceability are separate gates. +5. Only then try a reverse projection of that same bounded subset. Executable import is a separate experiment with an explicit time contract, function bindings, and analysis-adapter limitations. + +A successful spike would provide a small `.sysml` artifact, mapping/loss manifest, and validation evidence. It would not claim full SysML support, unrestricted round trips, or simulation equivalence. + +## Suggested reading sequence + +1. Read release examples and libraries before setting up the full developer environment: [release contents][release]. Pick parts, ports, connections, then actions and states. +2. Follow one definition and its usage through [model objects][usage], [grammar][sysml-grammar], [FeatureAdapter][feature-adapter], and [validator][validator]. Compare against GDS's DSL → spec/IR path. +3. Specify the thermostat mapping and identify each intentional loss before writing an exporter. +4. Read the separate [API service][api] only when a target repository/tool makes API integration concrete. + +## Verification and open questions + +The original study was based on source/document inspection. Subsequent implementation and the [recorded Pilot validation](../examples/sysml/validation/README.md) establish one structural export accepted by the official validator. OpenSysML validation, runtime equivalence, reverse import, and repository synchronization have not been tested. Outstanding decisions: target engineering tool, whether architecture exchange or executable analysis matters first, required quantity/unit coverage, and whether model editing must round-trip. These determine the mapping scope; the first export proposal can proceed as a disposable experiment without assuming all four answers. + +[pilot]: https://github.com/Systems-Modeling/SysML-v2-Pilot-Implementation/tree/5cca16d846016e62bb1e54e0e50e675254a022ef +[release]: https://github.com/Systems-Modeling/SysML-v2-Release/blob/master/README.md +[api]: https://github.com/Systems-Modeling/SysML-v2-API-Services/blob/master/README.md +[kerml-grammar]: https://github.com/Systems-Modeling/SysML-v2-Pilot-Implementation/blob/5cca16d846016e62bb1e54e0e50e675254a022ef/org.omg.kerml.xtext/src/org/omg/kerml/xtext/KerML.xtext +[sysml-grammar]: https://github.com/Systems-Modeling/SysML-v2-Pilot-Implementation/blob/5cca16d846016e62bb1e54e0e50e675254a022ef/org.omg.sysml.xtext/src/org/omg/sysml/xtext/SysML.xtext +[definition]: https://github.com/Systems-Modeling/SysML-v2-Pilot-Implementation/blob/5cca16d846016e62bb1e54e0e50e675254a022ef/org.omg.sysml.model/src/main/java/org/omg/sysml/lang/sysml/Definition.java +[usage]: https://github.com/Systems-Modeling/SysML-v2-Pilot-Implementation/blob/5cca16d846016e62bb1e54e0e50e675254a022ef/org.omg.sysml.model/src/main/java/org/omg/sysml/lang/sysml/Usage.java +[feature-adapter]: https://github.com/Systems-Modeling/SysML-v2-Pilot-Implementation/blob/5cca16d846016e62bb1e54e0e50e675254a022ef/org.omg.sysml.logic/src/main/java/org/omg/sysml/adapter/FeatureAdapter.java +[validator]: https://github.com/Systems-Modeling/SysML-v2-Pilot-Implementation/blob/5cca16d846016e62bb1e54e0e50e675254a022ef/org.omg.sysml.xtext/src/org/omg/sysml/xtext/validation/SysMLValidator.xtend +[evaluator]: https://github.com/Systems-Modeling/SysML-v2-Pilot-Implementation/blob/5cca16d846016e62bb1e54e0e50e675254a022ef/org.omg.sysml.execution/src/org/omg/sysml/execution/expressions/ExpressionEvaluator.java diff --git a/docs/symbolic/getting-started.md b/docs/symbolic/getting-started.md index 9fedadc..3a2de1e 100644 --- a/docs/symbolic/getting-started.md +++ b/docs/symbolic/getting-started.md @@ -2,73 +2,108 @@ ## Installation +For new projects, install the current symbolic implementation: + ```bash -uv add "gds-symbolic[sympy]" +uv add "gds-domains[symbolic]>=0.1.1" ``` -For development (monorepo): +`gds-symbolic` is a deprecated compatibility package. Existing users should +upgrade it to at least `0.99.1`; new code uses `gds_domains.symbolic`. + +For development in the monorepo: ```bash git clone https://github.com/DynamicalSystemsGroup/gds-core.git cd gds-core -uv sync --all-packages +uv sync --all-packages --all-extras ``` ## Your First Symbolic Model -Define a damped harmonic oscillator symbolically: two state variables (position and velocity), one input (external force). +Declare the states, input, sensor, and symbolic parameter names before writing +expressions. This damped oscillator has position `x1`, velocity `x2`, and an +external force `u`. ```python +from gds_domains.control import Input, Sensor, State from gds_domains.symbolic import ( - SymbolicControlModel, - StateEquation, OutputEquation, - compile_to_ode, + StateEquation, + SymbolicControlModel, ) -# 1. Declare symbolic state equations -# dx1/dt = x2 (velocity) -# dx2/dt = -k*x1 - c*x2 + u (acceleration with damping) model = SymbolicControlModel( name="DampedOscillator", + states=[State(name="x1", initial=1.0), State(name="x2", initial=0.0)], + inputs=[Input(name="u")], + sensors=[Sensor(name="position", observes=["x1"])], + symbolic_params=["k", "c"], state_equations=[ - StateEquation(state="x1", expr="x2"), - StateEquation(state="x2", expr="-k * x1 - c * x2 + u"), + StateEquation(state_name="x1", expr_str="x2"), + StateEquation(state_name="x2", expr_str="-k*x1 - c*x2 + u"), ], - output_equations=[ - OutputEquation(output="position", expr="x1"), - ], - parameters={"k": 4.0, "c": 0.5}, + output_equations=[OutputEquation(sensor_name="position", expr_str="x1")], ) -# 2. Compile to a callable ODE function -ode_fn = compile_to_ode(model) - -# 3. Evaluate at a point -dx = ode_fn(t=0.0, state={"x1": 1.0, "x2": 0.0}, params={"k": 4.0, "c": 0.5, "u": 0.0}) -print(dx) # {"x1": 0.0, "x2": -4.0} +ode_fn, state_order = model.to_ode_function() +print(state_order) # ['x1', 'x2'] +dx = ode_fn(0.0, [1.0, 0.0], {"k": 4.0, "c": 0.5, "u": 0.0}) +print(dx) # [0.0, -4.0] ``` +The callable takes `(t, y, params)` and returns a derivative list. `y` follows +`state_order`; input and parameter values are supplied in `params`. Declaring +`symbolic_params` does not bind their numerical values. Pass all values needed +for an analysis explicitly; unspecified inputs and parameters default to zero. + +Expressions use the [restricted mathematical grammar](index.md#expression-grammar-and-security). +Use `state_name` / `sensor_name` and `expr_str` for equation fields. Arbitrary +Python calls and unknown symbols are rejected when expressions are consumed. + ## Integration with gds-continuous -Plug the compiled ODE function directly into `gds-continuous`: +Install the SciPy integration extra for this section: + +```bash +uv add "gds-continuous[scipy]" +``` + +Continue with the `model`, `ode_fn`, and `state_order` from above: ```python from gds_continuous import ODEModel, ODESimulation ode_model = ODEModel( - state_names=["x1", "x2"], + state_names=state_order, initial_state={"x1": 1.0, "x2": 0.0}, rhs=ode_fn, - params={"k": 4.0, "c": 0.5, "u": 0.0}, + params={"k": [4.0], "c": [0.5], "u": [0.0]}, ) -sim = ODESimulation(model=ode_model, t_span=(0.0, 20.0), solver="RK45") +sim = ODESimulation( + model=ode_model, + t_span=(0.0, 20.0), + t_eval=[i / 10 for i in range(201)], + solver="RK45", +) results = sim.run() +print(results.times[0], results.state_array("x1")[0]) # 0.0 1.0 +``` + +`ODEModel.params` takes lists of candidate values and expands their Cartesian +product into simulation subsets. Singleton lists above request one trajectory. +Use `results.times` and `results.state_array(name)` to read a trajectory. +`results.to_list()` exposes row dictionaries with `time`, `run`, `subset`, and +state columns; `results.to_dataframe()` additionally requires the pandas extra. +For an optional plot, install Matplotlib with `uv add matplotlib` and run: + +```python import matplotlib.pyplot as plt -plt.plot(results.t, results["x1"], label="position") -plt.plot(results.t, results["x2"], label="velocity") + +plt.plot(results.times, results.state_array("x1"), label="position") +plt.plot(results.times, results.state_array("x2"), label="velocity") plt.legend() plt.title("Damped Harmonic Oscillator") plt.xlabel("Time") @@ -78,58 +113,60 @@ plt.show() ## Linearization -Compute Jacobian matrices at an operating point to get the standard state-space form `(A, B, C, D)`: +Use state and input vectors in declaration order, with explicit parameter +values, to compute the Jacobian matrices at an operating point: ```python -from gds_domains.symbolic import linearize - -# Linearize around the equilibrium (x1=0, x2=0, u=0) -lin = linearize( - model, - operating_point={"x1": 0.0, "x2": 0.0}, - input_point={"u": 0.0}, +lin = model.linearize( + x0=[0.0, 0.0], + u0=[0.0], + param_values={"k": 4.0, "c": 0.5}, ) -print("A =", lin.A) # [[ 0. 1.], [-4. -0.5]] -print("B =", lin.B) # [[0.], [1.]] -print("C =", lin.C) # [[1. 0.]] -print("D =", lin.D) # [[0.]] +print("A =", lin.A) # [[0.0, 1.0], [-4.0, -0.5]] +print("B =", lin.B) # [[0.0], [1.0]] +print("C =", lin.C) # [[1.0, 0.0]] +print("D =", lin.D) # [[0.0]] ``` -The `LinearSystem` object holds NumPy arrays for each matrix: +`LinearizedSystem` stores matrices as lists of lists. NumPy can analyze them; +it is also installed by the SciPy extra used above: ```python import numpy as np -# Check eigenvalues for stability -eigenvalues = np.linalg.eigvals(lin.A) +eigenvalues = np.linalg.eigvals(np.asarray(lin.A)) print(f"Eigenvalues: {eigenvalues}") -print(f"Stable: {all(e.real < 0 for e in eigenvalues)}") +print(f"Stable: {all(e.real < 0 for e in eigenvalues)}") # Stable: True ``` ## Nonlinear Example: Van der Pol Oscillator -A classic nonlinear system where linearization reveals local stability: +This example is independent of the damped oscillator: ```python -from gds_domains.symbolic import SymbolicControlModel, StateEquation, linearize +from gds_domains.control import State +from gds_domains.symbolic import StateEquation, SymbolicControlModel vdp = SymbolicControlModel( name="VanDerPol", + states=[State(name="x1", initial=1.0), State(name="x2", initial=0.0)], + symbolic_params=["mu"], state_equations=[ - StateEquation(state="x1", expr="x2"), - StateEquation(state="x2", expr="mu * (1 - x1**2) * x2 - x1"), + StateEquation(state_name="x1", expr_str="x2"), + StateEquation(state_name="x2", expr_str="mu*(1 - x1**2)*x2 - x1"), ], - parameters={"mu": 1.0}, ) -# Linearize at the origin -lin = linearize(vdp, operating_point={"x1": 0.0, "x2": 0.0}) -print("A =", lin.A) # [[0, 1], [-1, mu]] -- unstable for mu > 0 +lin_vdp = vdp.linearize(x0=[0.0, 0.0], u0=[], param_values={"mu": 1.0}) +print("A =", lin_vdp.A) # [[0.0, 1.0], [-1.0, 1.0]] ``` +The origin is unstable for this positive value of `mu`. This is a local +linearization result, not a claim about the nonlinear system's entire trajectory. + ## Next Steps -- [Symbolic Overview](index.md) -- architecture and key types -- [Continuous-Time](../continuous/index.md) -- ODE simulation engine for running compiled models -- [Control](../control/index.md) -- the underlying control DSL +- [Symbolic Overview](index.md) -- architecture, types, and expression grammar +- [Continuous-Time](../continuous/index.md) -- ODE simulation engine +- [Control](../control/index.md) -- underlying structural control DSL diff --git a/docs/symbolic/index.md b/docs/symbolic/index.md index 6f39aa4..e76e29e 100644 --- a/docs/symbolic/index.md +++ b/docs/symbolic/index.md @@ -1,45 +1,45 @@ -# gds-symbolic +# Symbolic Math (`gds-domains`) -[![PyPI](https://img.shields.io/pypi/v/gds-symbolic)](https://pypi.org/project/gds-symbolic/) -[![Python](https://img.shields.io/pypi/pyversions/gds-symbolic)](https://pypi.org/project/gds-symbolic/) +[![PyPI](https://img.shields.io/pypi/v/gds-domains)](https://pypi.org/project/gds-domains/) +[![Python](https://img.shields.io/pypi/pyversions/gds-domains)](https://pypi.org/project/gds-domains/) [![License](https://img.shields.io/github/license/DynamicalSystemsGroup/gds-core)](https://github.com/DynamicalSystemsGroup/gds-core/blob/main/LICENSE) -**SymPy bridge for gds-control** -- symbolic state equations, automatic linearization, and ODE code generation. +**SymPy bridge for `gds_domains.control`** -- symbolic state equations, automatic linearization, and ODE code generation. ## Package Identity | Distribution | Import | Role | |---|---|---| -| `gds-symbolic` | `gds_domains.symbolic` | SymPy bridge for `gds-control` models | -| `gds-domains` | `gds_domains.symbolic` | Consolidated domain package distribution | +| `gds-domains[symbolic]` | `gds_domains.symbolic` | Current symbolic implementation for control models | +| `gds-symbolic` | `gds_symbolic` | Deprecated compatibility package; use `gds-domains[symbolic]` for new projects | ## What is this? -`gds-symbolic` extends `gds-control`'s `ControlModel` with symbolic mathematics. Instead of writing numerical right-hand side functions by hand, you declare state and output equations as symbolic expressions and let the compiler do the rest. +`gds_domains.symbolic` extends `gds_domains.control`'s `ControlModel` with symbolic mathematics. Instead of writing numerical right-hand side functions by hand, you declare state and output equations as symbolic expressions and let the compiler do the rest. - **`StateEquation`** -- symbolic expression for `dx/dt` (e.g., `"-k * x + b * u"`) - **`OutputEquation`** -- symbolic expression for sensor output `y` (e.g., `"x + noise"`) -- **`compile_to_ode()`** -- lambdifies symbolic equations into a callable `ODEFunction` compatible with `gds-continuous` -- **`linearize()`** -- computes Jacobian matrices (A, B, C, D) at an operating point +- **`model.to_ode_function()`** -- returns an ODE callable and its state order, compatible with `gds-continuous` +- **`model.linearize()`** -- computes Jacobian matrices (A, B, C, D) at an operating point - **Restricted expression grammar** -- constructs SymPy expressions directly from validated syntax ## When to Use It -Use `gds-symbolic` when a control model's dynamics should be specified as +Use `gds_domains.symbolic` when a control model's dynamics should be specified as symbolic equations and then linearized or compiled to ODE functions. Use -`gds-control` alone when numerical callables are enough. +`gds_domains.control` alone when numerical callables are enough. ## Architecture ``` -gds-control (pip install gds-domains) +gds_domains.control (pip install gds-domains) | | State-space control DSL: State, Input, Sensor, Controller. | -+-- gds-symbolic (uv add gds-symbolic[sympy]) ++-- gds_domains.symbolic (uv add "gds-domains[symbolic]>=0.1.1") | | Symbolic layer: StateEquation, OutputEquation, - | compile_to_ode(), linearize(). + | model.to_ode_function(), model.linearize(). | +-- gds-continuous (optional integration) | @@ -53,25 +53,25 @@ gds-control (pip install gds-domains) | `StateEquation` | Symbolic `dx_i/dt = expr(x, u, params)` | | `OutputEquation` | Symbolic `y_i = expr(x, u, params)` | | `SymbolicControlModel` | Extends `ControlModel` with symbolic equations | -| `ODEFunction` | Lambdified callable: `f(t, x, params) -> dx/dt` | -| `LinearSystem` | Matrices `(A, B, C, D)` from Jacobian linearization | +| `ODEFunction` | Lambdified callable: `f(t, y, params) -> list[float]`, with states in the returned order | +| `LinearizedSystem` | Matrices `(A, B, C, D)` as lists of lists from Jacobian linearization | ## How It Works -``` -Symbolic expressions (strings) - | - v -Validated AST --> SymPy Expr objects +```text +SymbolicControlModel: declared states, inputs, parameters, and expressions | - v -compile_to_ode() --> ODEFunction (lambdified, math-backed) - | | - v v -linearize() gds-continuous ODEModel - | - v -LinearSystem(A, B, C, D) --> eigenvalue analysis, controllability, etc. + +-- validated AST --> directly constructed SymPy expressions + | + +-- to_ode_function() --> (ode_fn, state_order) + | | + | v + | gds-continuous ODEModel + | + +-- linearize(x0, u0, param_values) + | + v + LinearizedSystem(A, B, C, D) ``` ## Expression grammar and security @@ -111,17 +111,20 @@ memory limits in an isolated worker. ## Quick Start ```bash -uv add "gds-symbolic[sympy]" +uv add "gds-domains[symbolic]>=0.1.1" ``` +`gds-symbolic>=0.99.1` remains available for existing applications using the +legacy `gds_symbolic` import. It requires the fixed `gds-domains` implementation. + See [Getting Started](getting-started.md) for a full walkthrough. ## Relationship to the Ecosystem -`gds-symbolic` sits between the control DSL and continuous-time simulation. It -extends `gds-control` models with SymPy expressions and can produce ODE +`gds_domains.symbolic` sits between the control DSL and continuous-time simulation. It +extends `gds_domains.control` models with SymPy expressions and can produce ODE functions for `gds-continuous`. ## Credits -Built on [gds-control](../control/index.md) by [DynamicalSystemsGroup](https://dynamicalsystemsgroup.com). +Built on the [control DSL](../control/index.md) by [DynamicalSystemsGroup](https://dynamicalsystemsgroup.com). diff --git a/mkdocs.yml b/mkdocs.yml index a37c77f..b27be72 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -108,6 +108,9 @@ plugins: - guides/real-world-patterns.md - guides/troubleshooting.md - guides/interoperability.md + - {guides/sysml-v2.md: "Experimental SysML structural export, recorded Pilot validation, and OpenSysML integration boundaries"} + - examples/sysml/README.md + - examples/sysml/validation/README.md - guides/architecture-milestone-layer0.md - guides/dsl-roadmap.md - research/research-boundaries.md @@ -165,6 +168,7 @@ plugins: - research/deep_research.md - research/paper-implementation-gap.md - research/semantic-web-summary.md + - research/sysml-v2-overlap.md - research/formal-representability.md - research/representation-gap.md - research/verification-plan.md @@ -222,6 +226,9 @@ nav: - gds-interchange / OWL: - Overview: owl/index.md - Getting Started: owl/getting-started.md + - SysML v2 Interoperability: guides/sysml-v2.md + - Thermostat SysML Export: examples/sysml/README.md + - Pilot Validation Evidence: examples/sysml/validation/README.md - Representability: owl/guide/representability.md - Formal Analysis: research/formal-representability.md - gds-proof: @@ -461,6 +468,7 @@ nav: - Paper Implementation Gap: research/paper-implementation-gap.md - Representation Gap: research/representation-gap.md - Semantic Web Integration: research/semantic-web-summary.md + - SysML v2 Mapping Study: research/sysml-v2-overlap.md - Formal Representability: research/formal-representability.md - Formal Verification: - Verification Plan: research/verification-plan.md