⚖️ SyntraLine++: A Customized DSL Based Compiler for Machine Learning and Advanced Synthesized Training Pipelines with C++ and Python Integration
Modern machine learning pipelines involve complex coordination of datasets, model definitions, hyperparameters, experiment configurations, distributed compute strategies, and evaluation logic. Typical frameworks (PyTorch, JAX, TensorFlow) provide powerful numerical backends, yet they lack a unified, formal language for describing training workflows at a high level of abstraction. As ML projects grow, so does the burden of boilerplate code, duplicated logic, hidden defaults, and non-reproducible experiment configurations.
SyntraLine++ introduces a domain-specific compiler and language designed to unify ML pipeline definitions into a structured, statically validated program. The goal is to provide the expressive clarity of DSLs, the safety guarantees of compiler passes, and the practical flexibility of modern ML frameworks.
The SyntraLine++ compiler:
- Parses
.syntraprograms and constructs a strongly typed Abstract Syntax Tree (AST). - Lowers programs into an Intermediate Representation (IR) consisting of datasets, models, and experiment pipelines.
- Performs semantic validation & normalization, including architecture collapsing, dataset–model consistency checks, hyperparameter inference, and experiment correctness.
- Emits fully runnable execution code in either PyTorch or JAX, matching the user’s backend selection.
- Supports advanced experimentation constructs such as automatic version comparison, hypergrid search, evaluation suites, and real-data CSV integration.
- Provides reproducible experiment workflows with structured output dictionaries for downstream logging, visualization, and benchmarking.
SyntraLine++ is positioned as a research-grade, compiler-oriented abstraction that bridges the gap between theory and practice. It is engineered for:
- Reproducible ML experimentation
- Educational clarity for ML and compiler courses
- Research prototypes for extensible pipeline definitions
- Potential integration with distributed training, compiler-based optimization, or embedded inference runtimes
By elevating ML workflows to a declarative, validated, and formally structured language, SyntraLine++ aims to make machine learning pipelines more transparent, extensible, and robust—while preserving full compatibility with industry-standard execution frameworks.
Building modern machine learning systems requires coordinating many moving parts:
- Dataset loading and preprocessing
- Model selection, architecture configuration, and hyperparameter tuning
- Training loops and evaluation pipelines
- Experiment reproducibility and result tracking
- Switching between backends (e.g., PyTorch, JAX)
- Exploring model variations, data versions, or hyperparameter grids
- Managing distributed or multi-stage workflows
While frameworks like PyTorch or JAX offer expressive numerical programming tools, they do not provide an overarching language for describing pipelines at a high level. As complexity grows, ML codebases become:
- Verbose — boilerplate training loops scattered across scripts
- Error-prone — experiment logic duplicated or inconsistently modified
- Difficult to reproduce — even small changes require manual synchronization
- Hard to version — comparing multiple datasets or model variants requires parallel scripts
- Non-declarative — the intent of an experiment is hidden inside imperative Python code
A Domain-Specific Language (DSL) provides the following components:
- Declarative clarity: experiments become explicit, structured programs
- Static validation: the compiler detects missing datasets, mismatched models, invalid metrics, etc.
- Reproducibility:
.syntrafiles capture complete experiment definitions - Backend flexibility: the same DSL program can generate both PyTorch and JAX execution code
- Separation of concerns: researchers write pipelines, not boilerplate
- Extensibility: new backends (e.g., ONNX Runtime, TensorRT, TPU) can be implemented without touching the DSL
Most ML systems research tools fall into two extremes:
-
High-level pipelines like Keras/Lightning
- Easy to use, but limited control and lacking static semantics.
-
Low-level research code in raw PyTorch/JAX
- Fully flexible, but verbose and not declarative.
SyntraLine++ bridges these extremes by introducing:
- A compiler that reads human-written experiment definitions
- A typed IR representing datasets, models, and operations
- A code generation layer emitting runnable backend scripts
- A semantic checking pass ensuring correctness before execution
SyntraLine++ is motivated by practical and academic needs:
- For researchers: easy versioning, comparison, and replicability
- For students: a clear model of ML pipeline structure
- For systems engineers: a testbed for compiler techniques meeting ML execution
- For experiment-heavy workflows: the DSL eliminates dozens of lines of boilerplate
- For future extensions: distributed training, mixed precision, memory routing, dynamic computation graphs, etc.
SyntraLine++ aims to make ML pipelines:
- Readable — “What is this experiment doing?” becomes obvious
- Reproducible — experiments are standalone programs
- Analyzable — the compiler understands the structure and checks correctness
- Portable — backend-agnostic execution
- Composable — datasets, models, and pipeline stages are modular units
By treating ML experimentation as a language design problem, SyntraLine++ establishes a foundation for fully programmable, statically validated machine learning workflows.
Machine learning research has evolved into an engineering discipline that demands precision, reproducibility, modularity, and consistency across experiments. While deep learning frameworks such as PyTorch and JAX provide expressive numerical computation primitives, they do not offer a unified language for describing full ML pipelines. As a result, researchers and engineers routinely manage:
- Multiple dataset variants
- Model architecture configurations and hyperparameters
- Experiment-specific training loops
- Evaluation logic scattered across scripts
- Backend-specific code duplication
- Ad-hoc experiment versioning
- Fragile file-based reproducibility practices
SyntraLine++ reframes this problem through a compiler lens, introducing a Domain-Specific Language (DSL) designed to express ML workflows declaratively. Instead of writing lengthy boilerplate training code, users describe what a pipeline should do, and the SyntraLine++ compiler determines how to execute it by generating fully runnable backend scripts.
SyntraLine++ brings the formality of language/compiler design to machine-learning experimentation: structured syntax, static validation, backend portability, and reproducibility.
SyntraLine++ is:
- A DSL for defining datasets, models, hyperparameters, experiments, and evaluation logic
- A compiler that translates
.syntraprograms into runnable PyTorch or JAX Python programs - A semantic validator that ensures references, datasets, and models are correct before execution
- An experiment orchestrator supporting hyperparameter grids, version comparison, multiple backends, and metric reporting
- A research platform for bridging compiler theory and ML systems
The .syntra language is expressive yet minimal, allowing users to describe ML workflows concisely while the compiler generates full execution logic.
Traditional ML workflows rely on handwritten Python scripts:
| Standard ML Workflow | SyntraLine++ Workflow |
|---|---|
| Imperative, verbose training loops | Declarative experiment definitions |
| Hidden logic in notebooks/scripts | Explicit, statically validated pipeline |
| Hard-coded model variants | Named model definitions with arch normalization |
| Boilerplate for dataloaders | Auto-generated dataset loading logic |
| Error-prone version comparison | Compiler-generated multi-version execution |
| Backend-specific code | Unified DSL → multiple execution backends |
By shifting ML pipeline specification into a compiler framework, SyntraLine++ provides:
- Static guarantees (datasets, models, experiment semantics)
- Reproducibility through structured programs
- Portability across execution backends
- Reduced boilerplate via automated code generation
- Higher-level reasoning about experiments
This approach mirrors how SQL abstracts away query execution—SyntraLine++ abstracts away ML boilerplate.
SyntraLine++ is built upon five foundational ideas and implementations, as shown below:
Instead of writing wrappers around PyTorch training loops, users write concise DSL programs:
experiment cnn_mnist(mnist) -> Metrics {
let train_run = train(simple_cnn, mnist.train)
let test_run = evaluate(simple_cnn, mnist.test) with {
metrics = [accuracy, loss]
}
return {
accuracy = test_run.accuracy,
loss = test_run.loss
}
}
The program describes intent, while the compiler determines the implementation.
Every .syntra file is parsed into an IR describing:
- Dataset declarations
- Model architectures and hyperparameters
- Train/Evaluate operations
- Experiment result structures
- Symbolic references across the pipeline
In which, the IR enables:
- Static validation
- Normalization of architectures (
cnn_small→cnn) - Backend-agnostic transformations
- Custom experiment handling (hypergrid, versioning)
Before any backend script is generated, the compiler ensures:
- Datasets referenced in experiments exist
- Models used in
train()orevaluate()exist - Experiments return valid metrics
- No undefined or ambiguous symbols are used
- Pipelines follow correct sequencing
Errors become compile-time failures, not runtime crashes.
The same .syntra code can primarily produce:
- PyTorch execution files using
--emit-pytorch - JAX execution files using
--emit-jax
These generated scripts simultaneously includes:
- Dataset loaders
- Model constructors
- Training loops
- Evaluation metrics
- Real CSV-based dataset integration
- Automatic device handling (CPU/GPU/JAX backends)
In which, backend differences are handled by the compiler and not the user.
SyntraLine++ outputs self-contained Python scripts such as:
build/run_cnn.py
build/run_mlp.py
build/run_compare.py
build/run_hypergrid.py
build/run_eval.py Each script contains:
- Torch/JAX dataset classes
- Model definitions (CNN/MLP)
- Training & evaluation loops
- Experiment logic
- Final metric printing
This turns every .syntra file into a reproducible artifact.
SyntraLine++ introduces several contributions to machine learning (ML) based tooling, such as:
A concise language to express datasets, models, training, evaluating, metrics, experiment results, and pipeline logic.
The compiler recognizes architecture families:
cnn_small,cnn_deep,cnn_grid,cnn_eval,cnn_v1→ cnnmlp_flat,mlp_deep,mlp_mnist→ mlp
while preserving variant-specific hyperparameters.
Generated Python includes:
- Real CSV MNIST loaders
- Random-data fallback
- Train/test source detection (
*_train.csv→*_test.csv) - Shuffle, batch, seed handling
No dataset boilerplate is needed.
Experiments likewise shown below:
experiment compare_versions(mnist_v1) -> Metrics { ... }
cause the compiler to generate:
- Multiple dataset loads
- Independent training loops
- Independent evaluation loops
- Result mapping (
acc_v1,acc_v2,loss_v1,loss_v2)
Multiple model definitions in a .syntra file define a search grid:
- Different learning rates
- Different batch sizes
- Different architectures
The compiler emits independent experiment runners per grid point.
Every experiment can run on:
- PyTorch
- JAX
with identical semantics.
The IR enables:
- Symbol checking
- Model/dataset consistency
- Experiment structure validation
- More predictable pipelines than Python scripts
SyntraLine++ is built to support future additions:
- Distributed execution (DDP, TPU strategies)
- Mixed precision training
- Additional model families
- Custom dataset types
- Graph optimizations
- Hardware-accelerated backend emitters
SyntraLine++ elevates ML experimentation from scattered Python scripts into a declarative, compiler-driven paradigm that improves reproducibility, clarity, consistency, and backend portability. Its contributions parimarily span language design, compiler construction, ML systems engineering, and experiment automation, making it both an academic tool and an engineering-ready foundation for advanced ML workflows.
SyntraLine++ is organized as a full compiler toolchain consisting of a front-end (AST + parser), a semantic analyzer, an Intermediate Representation (IR) layer, and backend code generators for PyTorch and JAX. The repository is structured to separate concerns cleanly and to mirror the architecture of modern compilers such as Clang/LLVM—while remaining lightweight and focused on ML pipeline construction. Below is the full directory structure, followed by an in-depth explanation of each component.
Syntralinepp-Compiler/
│
├── include/
│ ├── syntra/ast.hpp
│ ├── syntra/ir.hpp
│ ├── syntra/compiler.hpp
│ ├── syntra/backend_pytorch.hpp
│ ├── syntra/backend_jax.hpp
│ └── syntra/semantic.hpp
│
├── src/
│ ├── ast.cpp
│ ├── parser.cpp
│ ├── semantic.cpp
│ ├── ir.cpp
│ ├── codegen_pytorch.cpp
│ ├── codegen_jax.cpp
│ ├── main.cpp ← CLI entrypoint
│
├── examples/
│ ├── mnist_basic.syntra
│ ├── cnn_pipeline.syntra
│ ├── hypergrid_search.syntra
│ ├── versioning.syntra
│ └── evalsuite.syntra
│
├── build/
│ ├── run_mlp_jax.py
│ ├── run_cnn_deep.py
│ ├── run_compare.py
│ └── ...
│
├── data/
│ ├── mnist_train.csv
│ ├── mnist_test.csv
│ └── ...
│
└── README.md (this file)This section describes the role and purpose of each directory and each core file inside it.
The include/syntra/ directory contains the full public-facing compiler interfaces and all major constructs of the SyntraLine++ frontend and backend.
Defines the core AST nodes produced by the parser, representing:
- Dataset declarations
- Model declarations
- Experiment pipelines
- Train/Evaluate operations
- Named fields and literal expressions
- Higher-level constructs like result mappings
The AST forms the first structured representation of any .syntra program.
Defines the normalized, semantically validated IR including:
IRDatasetIRModelIRExperimentPipeline- Pipeline operations (
Train,Evaluate,Let, etc.) - Result mapping structures
The IR is backend-neutral and serves as the contract between the front-end and code generators.
Declares:
- The top-level
compile()function - Interfaces for invoking parser → semantic analyzer → IR → backend
- Support for
--emit-pytorchand--emit-jaxmodes - Command-line integration hooks
This file contains the high-level orchestration logic of the compiler.
Declares:
- Python generation routines for datasets
- Model factory & architecture normalization
- Training loop emission
- Evaluation routines
- Experiment-level generation
- Versioning/hypergrid special logic
The concrete implementation resides in codegen_pytorch.cpp.
Declares the JAX backend generator including:
- Random or real CSV-based dataset loaders
- MLP construction logic
- JIT-compiled training/evaluation functions
- Experiment mappings for JAX pipelines
The JAX backend is intentionally parallel to PyTorch’s architecture to ensure feature consistency.
Declares:
- Symbol table structures
- Dataset/model resolution
- Type and reference checking
- Architecture normalization hooks
- Error reporting utilities
This ensures that invalid .syntra programs fail at compile time, not runtime.
Contains the C++ source for each stage of the compiler pipeline and functional architecture.
Implements utility operations for AST node creation, parenting, field extraction, and diagnostic printing.
Implements a full recursive-descent parser for .syntra files:
- Lexical scanning
- Tokenization
- Parsing declarations
- Parsing experiment blocks
- Literal interpretation
The parser converts plain text → AST.
Implements:
- Duplicate symbol checks
- Ensuring datasets/models referenced in experiments exist
- Ensuring train/evaluate operations are well-formed
- Normalizing architecture names (cnn_small → cnn, cnn_v2 → cnn, mlp_mnist → mlp)
- Ensuring return mappings match evaluation metrics
This is the compiler’s “middle-end” responsible for correctness.
Implements transformation from raw AST into IR:
- Flattening constructs
- Resolving symbolic references
- Producing canonical IR structures
- Inferencing defaults (batch size, metrics, etc.)
This IR is what backends consume.
Generates full runnable Python scripts:
SyntraImageDatasetimplementation- Real CSV loader and fallback generator
SimpleCNNandSimpleMLPdefinitions- Architecture normalization logic
- Full training/evaluation loops
- Experiment pipeline emission
- Special handling for
compare_versions - Hypergrid search logic
- CLI entrypoint script assembly
This backend matches the semantics of the DSL with PyTorch code faithfully.
Contains the JAX backend parallel to PyTorch:
- Dataset loading via JAX + CSV
- PRNGKey handling
- JIT-compiled training loops
- Lightweight MLP architecture
- Experiment mapping generation
- Backend-consistent metric reporting
All JAX scripts are self-contained and executable out of the box.
Provides the compiler executable:
./build/src/syntra <file.syntra> –emit-pytorch –experiment./build/src/syntra <file.syntra> –emit-jax –experiment
Responsibilities:
- Argument parsing
- Reading and loading
.syntrafile - Invoking parser → semantic → IR → codegen
- Writing generated Python scripts to stdout
This is effectively the front door of the SyntraLine++ compiler.
Includes multiple .syntra files showcasing DSL features.
Introduces:
- Dataset definition
- MLP/CNN model definition
- Simple experiment wrapping train/evaluate
Used to verify the correctness of minimal end-to-end compilation.
Demonstrates:
- Multiple CNN architectures (
cnn_small,cnn_deep) - Independent experiments
- Dataset reuse
- Metrics extraction
Large-scale test for PyTorch/JAX parity.
Implements a simple hyperparameter grid via multiple model declarations:
- Learning rate variations
- Batch size alternatives
Compiler generates one script per experiment point.
Demonstrates advanced compiler features:
- Multiple dataset versions
- Multiple model versions
compare_versionsexperiment- Backend auto-generation of two training loops
- Naming conventions (
acc_v1,loss_v1, etc.)
This file tests complex IR handling.
Tests extended evaluation semantics:
- Additional metrics (precision, recall, f1)
- Compiler’s mapping logic
- Graceful handling of unsupported metrics (placeholder values)
Contains the Python scripts produced by SyntraLine++:
Examples:
run_mlp_jax.pyrun_cnn_deep.pyrun_compare.pyrun_grid_1e3.pyrun_evalsuite.pyrun_cnn_small.py
Each file is fully runnable with the following syntax and sample shown below:
SYNTRA_PREFER_REAL_DATASETS=1 python3 build/run_cnn_deep.py
In which, the scripts include:
- Dataset loader class
- Model definitions
- Training loop
- Evaluation loop
- Experiment logic
- Final result printing
This directory is regenerable (safe to delete and recompile).
Holds CSV datasets used by SyntraLine++:
mnist_train.csvmnist_test.csvmnist_v1.csvmnist_v2.csvmnist_eval.csv
All backends load real CSVs when:
SYNTRA_PREFER_REAL_DATASETS=1
Otherwise, fallback synthetic data is used.
The root documentation file (the one being authored right now).
It contains:
- Abstract
- Motivation
- Introduction
- Architecture
- Examples
- Usage instructions
- Developer notes
- Roadmap
- License
SyntraLine++ is built with a clean, compiler-inspired architecture:
include/— Public compiler interfacessrc/— Implementation of all compiler stagesexamples/— DSL showcase programsbuild/— Auto-generated backend codedata/— Real datasetsREADME.md— Documentation
This structure supports extensibility, backend independence, academic clarity, and real-world usability.
This section describes how to set up, build, and run the SyntraLine++ compiler from source. The build process follows standard modern C++ practices and is intentionally lightweight, reproducible, and backend-agnostic. SyntraLine++ is designed to behave like a real compiler toolchain: you build it once, then use the resulting syntra executable to compile .syntra programs into runnable ML backend scripts.
The SyntraLine++ compiler is built within a specific set of C++ and Python versions as shown below:
To build and run SyntraLine++, the following are required:
- C++17 compatible compiler
- GCC ≥ 9
- Clang ≥ 10
- Apple Clang (Xcode ≥ 13)
- CMake ≥ 3.14
- Python ≥ 3.10
These are required regardless of which backend (PyTorch or JAX) you plan to use.
SyntraLine++ emits plain Python scripts. The compiler itself does not depend on PyTorch or JAX, but the generated scripts do. Depending on the backend you use, install the corresponding runtime libraries as the following:
pip install torch
# Optional (Recommended)
pip install torchvision
# JAX Backend
pip install jax jaxlibOn macOS and Linux (CPU), the following specification of
pip install jax jaxlibis sufficient. For GPU acceleration, consult the official JAX documentation for CUDA-enabled wheels.
While not required, the following tools are recommended for development and research workflows:
- Python virtual environments (
venv,conda) blackorrufffor formatting generated scriptsmatplotlibfor plotting experiment outputsnumpyandpandasfor extended dataset manipulation
Clone the following repository:
git clone https://github.com/rizkysaputradev/Syntralinepp-Compiler.git
cd Syntralinepp-CompilerCreate a Python virtual environment (Optional but recommended):
python3 -m venv .syntra-venv
source .syntra-venv/bin/activateInstall backend dependencies inside the environment:
pip install torch jax jaxlibSyntraLine++ uses a standard out-of-source CMake build. Below shows these step-by-step build guide.
Firstly, a new directory called build is created with the specifications of a C++ program and enviornment.
mkdir build
cd build
cmake ..
make -j8After a successful build, the compiler executable will be located at:
build/src/syntraThis can be verified by checking the location of the build and its specficiations as such:
./build/src/syntra --helpMake sure Xcode Command Line Tools are installed:
xcode-select --installThe compiler builds natively. Generated PyTorch/JAX scripts will run on CPU unless GPU-enabled wheels are installed. However, make sure to setup the system requirements and specifications accordingly to avoid any mismatches.
Ensure gcc or clang supports C++17:
g++ --versionOnce built, the syntra executable can be used to compile .syntra DSL programs into runnable Python scripts.
./build/src/syntra <input.syntra> --emit-pytorchOr
./build/src/syntra <input.syntra> --emit-jaxBy default, the generated Python code is written to stdout. Redirect it to a file:
./build/src/syntra examples/mnist_basic.syntra \
--emit-pytorch \
--experiment mlp_mnist \
> build/run_mlp.pyIf a .syntra file defines multiple experiments, select one explicitly:
./build/src/syntra examples/cnn_pipeline.syntra \
--emit-pytorch \
--experiment cnn_deep_mnist \
> build/run_cnn_deep.pyIf no experiment is specified, the compiler defaults to the first experiment in the file.
Generated scripts are fully self-contained Python programs.
To enable real CSV dataset loading, set the environment variable:
SYNTRA_PREFER_REAL_DATASETS=1 python3 build/run_cnn_deep.pyIf this variable is not set, the script automatically falls back to synthetic random data, which is useful for debugging and compiler testing.
A typical run prints:
- Dataset loading information
- Training loss per epoch
- Evaluation metrics
- Final structured experiment result
Example:
[epoch 1/10] train loss = 0.72
[epoch 2/10] train loss = 0.19
...
eval stats: {'loss': 0.07, 'accuracy': 0.97}
Final experiment result:
{'accuracy': 0.97, 'loss': 0.07}At a high level, running the compiler follows this pipeline:
.syntra file
↓
Parser → AST
↓
Semantic Validation
↓
Intermediate Representation (IR)
↓
Backend Code Generation (PyTorch / JAX)
↓
Runnable Python ScriptThis mirrors the structure of a traditional compiler while targeting machine learning workflows.
SyntraLine++ is designed for reproducible ML experimentation:
- The DSL captures experiment intent explicitly
- Generated scripts contain all hyperparameters inline
- Dataset sources are explicit
- Backend code is deterministic by construction (unless randomness is explicitly introduced)
This makes the SyntraLine++ compiler suitable for the following purposes:
- Simplify training pipelines
- Advanced ML experimentation
- Expanding ML systems
- Benchmarking architectures
- Controlled ablation studies
To clean the build:
rm -rf buildThen rebuild from scratch following Section 5.3.
SyntraLine++ is intentionally not installed system-wide. Instead, it is treated as a project-local compiler tool, similar to research compilers and DSL toolchains. However, future developments will allow the compiler to be compatible within various range of systems after performing a complete set of benchmarks and testing procedures with acceptability on various high-level and advanced ML training pipelines. The current design choice is outline as such:
- Avoids dependency conflicts
- Encourages reproducibility
- Keeps the compiler tightly coupled to its examples and datasets
This section formally specifies the SyntraLine++ Domain-Specific Language (DSL) from an academic and compiler-oriented perspective.
The DSL is intentionally minimal, declarative, and statically analyzable, designed to describe machine learning pipelines rather than low-level tensor operations.
SyntraLine++ programs are compiled—not interpreted—into backend-specific execution code (PyTorch / JAX), following a traditional compiler pipeline: syntax → semantics → IR → code generation.
A dataset declaration defines a logical dataset entity used by experiments. It specifies data sources and loading behavior, but does not execute loading itself. Execution semantics are delegated to the backend code generator.
dataset <name>: <DatasetType> {
field1 = value1
field2 = value2
...
}
Currently supported dataset types include:
ImageDataset(MNIST-style CSVs)
The MNIST dataset is chosen due to its standardization and reproducibility in computation and benchmarking. As a result, this creates a global unit that can be referenced through various low-level experiments, such as compilers.
| Field Name | Type | Description |
|---|---|---|
source |
string | Path to the training CSV file (e.g. MNIST-style label,pixels...) |
test_source |
string | Path to the test CSV file (optional; inferred if omitted) |
batch |
int | Batch size used by the backend DataLoader |
shuffle |
bool | Whether to shuffle the training dataset |
seed |
int | Optional random seed for dataset initialization |
shape |
tuple | Logical input shape, e.g. (28, 28) |
channels |
int | Number of input channels (e.g. 1 for grayscale images) |
If
test_sourceis not provided, the compiler applies a heuristics where*_train.csv→*_test.csv.
dataset mnist: ImageDataset {
source = "data/mnist_train.csv"
batch = 64
shuffle = true
}
- Dataset declarations are pure metadata
- No I/O occurs during compilation
- Backend decides whether to load real data or generate fallback synthetic data
- Dataset objects are immutable after semantic validation
A model declaration defines a trainable computation unit together with its optimization parameters. Hereby, the models are declared and structured with these following functionalities and cosniderations:
- Backend-agnostic at the DSL level
- Normalized during semantic analysis
- Lowered to concrete implementations during code generation
model <name>: <ModelType> {
arch = "cnn"
lr = 1e-3
epochs = 5
optimizer = "adam"
...
}
The primary supported model types are listed as shown below:
- TorchModel
- JaxModel
| Field Name | Type | Description |
|---|---|---|
arch |
string | Architecture identifier (e.g. cnn, cnn_deep, mlp) |
lr |
float | Learning rate for the optimizer |
epochs |
int | Number of training epochs |
optimizer |
string | Optimizer type (adam, adamw, sgd) |
| Field Name | Type | Description |
|---|---|---|
in_channels |
int | Number of input channels (e.g. 1 for MNIST) |
num_classes |
int | Number of output classes |
model simple_cnn: TorchModel {
arch = "cnn_deep"
lr = 5e-4
epochs = 10
optimizer = "adam"
}
All CNN variants (
cnn_small,cnn_deep,cnn_grid,cnn_v1, etc.) are normalized to thecnnfamily during semantic analysis. Adjustments are to be made when various CNN features are developed to SyntraLine++.
| Field Name | Type | Description |
|---|---|---|
input_dim |
int | Flattened input dimension (e.g. 28×28 = 784) |
hidden_dim |
int | Size of hidden layers |
mlp_layers |
int | Total number of layers (including output layer) |
dropout |
float | Dropout probability (0.0 disables dropout) |
model mlp_mnist: TorchModel {
arch = "mlp"
input_dim = 784
hidden_dim = 256
mlp_layers = 2
lr = 1e-3
epochs = 10
}
- Architecture strings are normalized (
cnn_small,cnn_deep→cnn) - Unsupported architectures trigger compile-time fallback
- Models are statically validated against declared datasets
An experiment defines a pipeline of operations that describes:
- Which model is trained
- On which dataset
- Which metrics are evaluated
- What results are returned
Experiments are the primary executable unit of a SyntraLine++ program.
experiment <name>(<dataset_param>) -> <ReturnType> {
<pipeline_ops>
}train(<model_name>, <dataset>.train)
- Binds a model to a dataset split
- Establishes optimization context
- Emits training loops during codegen
evaluate(<model_name>, <dataset>.test) with {
metrics = [accuracy, loss]
}
- Runs inference on the test split
- Collects metrics
- Metrics must be known symbols
experiment cnn_mnist(mnist) -> Metrics {
train(simple_cnn, mnist.train)
evaluate(simple_cnn, mnist.test) with {
metrics = [accuracy, loss]
}
return {
accuracy = test_run.accuracy
loss = test_run.loss
}
}
- Experiments are sequentially ordered
- Variables are SSA-like (single assignment)
- Metrics are explicitly named and mapped
- The compiler enforces dataset–model compatibility
Machine learning research often requires controlled comparison between model versions or dataset revisions. SyntraLine++ introduces a domain-specific construct to express this pattern directly, rather than relying on external scripts.
experiment compare_versions(mnist) -> Metrics {
train(model_v1, mnist.train)
evaluate(model_v1, mnist.test) -> {
acc_v1 = "accuracy"
loss_v1 = "loss"
}
train(model_v2, mnist.train)
evaluate(model_v2, mnist.test) -> {
acc_v2 = "accuracy"
loss_v2 = "loss"
}
}
The compiler:
- Detects multiple train/evaluate pairs
- Emits separate training pipelines
- Prevents parameter sharing
- Returns a structured comparison dictionary
Generated Python code resembles:
result = {
"acc_v1": eval_stats_v1["accuracy"],
"loss_v1": eval_stats_v1["loss"],
"acc_v2": eval_stats_v2["accuracy"],
"loss_v2": eval_stats_v2["loss"],
}- Isolation between model versions
- Deterministic execution order
- Identical data loading semantics
- Explicit metric labeling
From a language-theoretic perspective, SyntraLine++ satisfies:
- Determinism: No implicit control flow
- Static analyzability: All symbols resolved at compile time
- Side-effect isolation: Effects only occur in generated code
- Backend separation: DSL semantics independent of PyTorch/JAX
The SyntraLine++ DSL:
- Abstracts ML pipelines at the compiler level
- Eliminates boilerplate experiment code
- Enables reproducible, structured ML research
- Bridges academic modeling and real execution systems
SyntraLine++ is implemented as a compiler-style DSL toolchain that translates a .syntra program into an executable Python training script for a selected backend (PyTorch or JAX). The compiler is structured into clearly separated phases:
- Lexing / Parsing → builds an AST
- Semantic Analysis → validates + normalizes the AST
- IR Construction → lowers AST into an execution-oriented IR
- Backend Codegen → emits runnable Python (PyTorch / JAX)
- Runtime Execution → Python script loads datasets, trains, evaluates, prints metrics
Input: .syntra
Output: .py runnable script (PyTorch or JAX)
PNG Placeholder:
docs/fig_arch_overview.png
Diagram contents to draw: “Source → Parser → AST → Semantic → IR → Backend Codegen → Python Script → Run”
The parser reads:
dataset <name>: <DatasetType> { ... }model <name>: <ModelType> { ... }experiment <name>(...) -> Metrics { ... }
It produces an AST that preserves:
- declaration names
- field assignments (
NamedField) - literal types (int/float/bool/string)
- experiment pipeline ops (
train,evaluate,return { ... })
PNG Placeholder:
docs/fig_ast_shape.png
Diagram contents to draw: “AST nodes: DatasetDecl, ModelDecl, ExperimentDecl, PipelineOp, Expr kinds (StringLiteral/FloatLiteral/etc.)”
Semantic analysis makes the language behave like a real DSL by enforcing rules and producing a canonical internal form. Typical responsibilities are listed as follows:
- Validate uniqueness of names (datasets/models/experiments)
- Verify required fields exist or apply defaults
- Normalize architecture families (e.g.
cnn_small,cnn_deep,cnn_v1→ canonical"cnn"family) - Resolve and verify references in pipeline ops (
train(model, dataset.train)) - Check metric validity (
accuracy,loss, later:precision/recall/f1) - Detect unsupported constructs early and fail with actionable compiler errors
PNG Placeholder:
docs/fig_semantic_passes.png
Diagram contents to draw: “Semantic passes: name resolution, type checking, defaults injection, normalization, reference validation”
The IR is designed to be:
- backend-independent
- easy to codegen
- pipeline-execution oriented
Instead of syntax, the IR represents:
- datasets: ready to bind to loader functions
- models: ready to bind to factory functions
- experiments: a list of ordered ops that the backend replays
IR elements include:
IRDataset(name + fields)IRModel(name + fields)IRExperimentPipelinedatasetParamops[](Train/Evaluate + structured info)results[](mapping output fields → metrics)
PNG Placeholder:
docs/fig_ir_layout.png
Diagram contents to draw: “IRDataset, IRModel, IRExperimentPipeline, PipelineOpKind(Train/Evaluate), ResultField mapping”
The backend decides how to translate the IR into a runnable script.
Backends currently supported:
--emit-pytorch→ generatestorchcode--emit-jax→ generatesjax + optaxcode
Common codegen has these following responsibilities:
- emit headers/imports
- emit dataset loaders (real CSV loader + fallback stub)
- emit model factories (arch-aware)
- emit training/evaluation loops
- emit experiment selection logic (
--experiment <name>)
PNG Placeholder:
docs/fig_codegen_strategy.png
Diagram contents to draw: “Shared IR → PyTorch backend emits torch DataLoader + nn.Module; JAX backend emits jax arrays + optax optimizer”
Several architectural computation based diagrams are constructed with very detailed layout in order to fully understand the functionalities and operationalization of the SyntraLine++ DSL compiler.
- Experiment selection
(--experiment <name>)is resolved in codegen time. - The generated script chooses the appropriate
run_experiment_*()function. - Real dataset integration is activated at runtime by setting:
SYNTRA_PREFER_REAL_DATASETS=1- Fallback behavior exists intentionally to make scripts runnable even when dataset files are missing.
- Special-case experiment lowering (e.g. version comparison) is implemented as a targeted codegen strategy to preserve DSL semantics while keeping the IR simple.
This section presents a formal mathematical description of the SyntraLine++ DSL, its compilation pipeline, and its execution semantics. The goal of this formalization is not to redefine machine learning, but to precisely specify how a SyntraLine++ program is interpreted, validated, compiled, and executed as a structured computational process.
A SyntraLine++ program is defined as a triple:
where:
-
$D = {d_1, d_2, \dots, d_k}$ is a finite set of dataset declarations -
$M = { m_1, m_2, \dots, m_\ell }$ is a finite set of model declarations -
$E = { e_1, e_2, \dots, e_n }$ is a finite set of experiment pipelines
Each component is declared independently in the DSL, but linked by name resolution during semantic analysis.
Each dataset declaration is modeled as a tuple:
where:
-
$name_d \in \Sigma^*$ is a unique identifier -
$\mathcal{F}_d = { (k, v) \mid k \in \text{FieldNames}, v \in \text{Expr} }$ is a finite map of named fields
After semantic normalization, each dataset induces a resolved dataset configuration:
with defaulting and derivation rules such as:
This normalized dataset is later interpreted as a data loader constructor in the backend.
Each model declaration is represented as:
where:
$name_m \in \Sigma^*$ $arch_m \in { \text{cnn}, \text{mlp}, \dots }$ -
$\mathcal{H}_m$ is a finite set of hyperparameters
After normalization, architecture families are collapsed:
Each normalized model declaration corresponds to a model factory function:
where:
-
$\phi$ denotes an empty and initialized declaration -
$f_\theta$ is a parameterized model -
$T \in \mathbb{N}$ is the number of training epochs
An experiment pipeline is defined as an ordered sequence of operations:
Each operation belongs to the set:
A training operation is defined as:
Semantically, this induces the iterative update:
for batches
An evaluation operation is defined as:
where:
Standard metrics include:
and:
Each experiment defines a result projection:
Example:
This allows multiple evaluations to coexist in a single experiment without collision.
The special compare_versions construct is modeled as parallel pipelines:
Each version pipeline is executed independently:
No parameter sharing or interference is permitted between versions.
Compilation proceeds by lowering the AST into an IR:
The IR is backend-agnostic and satisfies:
Each backend defines a mapping:
where
The overall execution semantics are therefore:
This establishes SyntraLine++ as a true compiler:
- Source language:
.syntra - Intermediate language: IR
- Target language: executable Python (PyTorch / JAX)
Given identical inputs:
the compilation pipeline satisfies:
and runtime behavior is reproducible up to backend-level nondeterminism (e.g., CUDA kernels).
This formalization shows that SyntraLine++ is:
- Declarative at the DSL level
- Deterministic at the compilation level
- Operationally grounded at runtime
- Extensible via IR-based backend specialization
In effect, SyntraLine++ defines a formal language for machine learning experimentation, bridging the gap between symbolic program specification and executable ML systems.
SyntraLine++ is designed as a multi-backend compiler:
The current system supports two production-grade backends:
- PyTorch Backend (
--emit-pytorch) - JAX Backend (
--emit-jax)
Both backends share the same front-end pipeline, ensuring:
- identical language semantics across runtimes
- the same
.syntraprogram can target multiple execution ecosystems - backend differences are isolated behind the IR interface
Key principle: Same DSL → Same IR → Different Backend Code Generation.
SyntraLine++ provides multiple CLI flags that expose internal stages of the compiler. These are essential for debugging, research, and validating correctness at each phase.
Crucial for verifying tokenization, keyword recognition, and formatting rules.
./src/syntra ../examples/mnist_basic.syntra --dump-tokensCrucial for verifying grammar coverage, AST node construction, and field parsing.
./src/syntra ../examples/mnist_basic.syntraDisplays the lowered, backend-agnostic IR representation.
./src/syntra ../examples/mnist_basic.syntra --dump-irRuns an interpreter-style simulation of experiment pipelines. This is a crucial middle layer tool to validate pipeline semantics without backend codegen.
./src/syntra ../examples/mnist_basic.syntra --simulateSupposed that the experiment exists. Thus, a training call becomes declarative.
./src/syntra ../examples/mnist_basic.syntra --simulate --experiment cnn_mnistHowever, if the experiment does not exist due to tests fallback behavior or error handling, then:
./src/syntra ../examples/mnist_basic.syntra --simulate --experiment doesnt_existSupposed the specified repository contains several unit-style tests (e.g., in ./tests/), likewise:
./tests/syntra_testsThen the experiment is validated if and only if the generated files are declarative and unique for each tests.
The PyTorch backend is a script-emitting compiler backend:
As the compiler backend emits a runnable .py script which includes:
- a dataset loader (real CSV with fallback)
- a model family factory (CNN / MLP)
- a generic training loop template
- an evaluation loop
- experiment resolution (select model/dataset from IR ops)
- optional specialized experiment codegen (e.g.,
compare_versions)
- If
SYNTRA_PREFER_REAL_DATASETS=1and files exist → load actual CSV MNIST - Otherwise → fall back to synthetic/random stub dataset (development safety)
- CNN family (normalized from
cnn_small,cnn_deep,cnn_eval,cnn_grid,cnn_v1,cnn_v2, etc.) - MLP family (mlp)
Model declaration fields are interpreted into a model construction function.
Experiment pipeline is compiled into Python code that replays ops in order.
For DSL programs like versioning.syntra, SyntraLine++ can emit a specialized experiment runner that executes two versions separately and returns a structured result mapping.
Conceptually, --emit-pytorch produces a script with these following layers:
- Header:
- imports
- device detection
- environment flags
- Dataset Runtime:
SyntraImageDatasetcreate_<dataset>_dataloaders()
- Model Runtime:
SimpleCNN,SimpleMLPcreate_<model>()
- Train/Eval Runtime:
train_one_epoch()evaluate_model()
- Per-experiment entrypoints:
run_experiment_<name>()
- Main selection:
- choose experiment and print results
./src/syntra ../examples/mnist_basic.syntra --emit-pytorch > run_mnist.py
python3 run_mnist.pyEnable real dataset loading:
export SYNTRA_PREFER_REAL_DATASETS=1Then run the generated script:
python3.11 build/run_mnist_real.pyInternally, this flips the runtime behavior of the generated dataset loader.
Rebuild the general compiler script first, where:
./scripts/build.sh./build/src/syntra examples/mnist_basic.syntra \
--emit-pytorch --experiment cnn_mnist > build/run_cnn.py
SYNTRA_PREFER_REAL_DATASETS=1 python3.11 build/run_cnn.py./build/src/syntra examples/mnist_basic.syntra \
--emit-pytorch --experiment mlp_mnist > build/run_mlp.py
SYNTRA_PREFER_REAL_DATASETS=1 python3.11 build/run_mlp.pyRebuild:
cmake --build build -j./build/src/syntra examples/cnn_pipeline.syntra \
--emit-pytorch --experiment cnn_small_mnist > build/run_cnn_small.py
SYNTRA_PREFER_REAL_DATASETS=1 python3.11 build/run_cnn_small.py
./build/src/syntra examples/cnn_pipeline.syntra \
--emit-pytorch --experiment cnn_deep_mnist > build/run_cnn_deep.py
SYNTRA_PREFER_REAL_DATASETS=1 python3.11 build/run_cnn_deep.py./build/src/syntra examples/hypergrid_search.syntra \
--emit-pytorch --experiment grid_lr_1e3 > build/run_grid_1e3.py
SYNTRA_PREFER_REAL_DATASETS=1 python3.11 build/run_grid_1e3.py./build/src/syntra examples/evalsuite.syntra \
--emit-pytorch --experiment evalsuite_mnist > build/run_evalsuite.py
SYNTRA_PREFER_REAL_DATASETS=1 python3.11 build/run_evalsuite.pyDenote that precision/recall/f1 in
evalsuite.syntramay still act as placeholders depending on current backend metric support. Accuracy/loss are expected to be wired fully.
Rebuild:
cmake --build build -jRun:
./build/src/syntra examples/versioning.syntra \
--emit-pytorch --experiment compare_versions > build/run_compare.py
SYNTRA_PREFER_REAL_DATASETS=1 python3.11 build/run_compare.pySemantic meaning revolves around two independent train/eval executed cycles, producing a structured output:
The JAX backend is designed as a fully functional execution backend with:
- JIT compilation for step functions
- Optax optimizers
- parameter PyTree updates
- consistent semantics with PyTorch backend (same IR)
- real dataset integration via the same environment flag
Formally:
The generated script defines:
init_*_params()*_apply()forward passmake_train_step()emitting@jax.jitattrain_stepmake_eval_fn()
The script supports:
Adam(default)AdamWSGD+momentum
Train step is typically:
Both architectures exist with:
- CNN uses
lax.conv_general_dilated(NHWC layout) - MLP uses dense layers and flattening
Dataset/model selection follows a similar IR interpretation logic.
Create a dedicated venv for JAX tooling (example uses Python 3.11):
python3.11 -m venv .syntra-venv
source .syntra-venv/bin/activate
pip install --upgrade pip
pip install "jax[jaxlib]"./src/syntra ../examples/mnist_basic.syntra --emit-jax > run_mnist_jax.py
python3.11 run_mnist_jax.pyActivate venv (if not already active):
source .syntra-venv/bin/activateEnable real dataset loading:
export SYNTRA_PREFER_REAL_DATASETS=1Build and run:
./scripts/build.sh
cd build
./src/syntra ../examples/mnist_basic.syntra --emit-jax > run_mnist_jax_real.py
cd ..
python3.11 build/run_mnist_jax_real.pyRebuild:
cmake --build build -jEmit scripts:
./build/src/syntra examples/mnist_basic.syntra \
--emit-jax --experiment cnn_mnist > build/run_cnn_jax.py
./build/src/syntra examples/mnist_basic.syntra \
--emit-jax --experiment mlp_mnist > build/run_mlp_jax.pyRun with the generated and compiled real data:
SYNTRA_PREFER_REAL_DATASETS=1 python3.11 build/run_cnn_jax.py
SYNTRA_PREFER_REAL_DATASETS=1 python3.11 build/run_mlp_jax.pySyntraLine++ maintains strong engineering invariants:
- Front-end equivalence: Both backends use the same parsing + semantic + IR pipeline.
- Experiment determinism: Experiment operation ordering in the DSL is preserved in the emitted script.
- Dataset resolution and selection with consistency:
- explicit dataset from train()/evaluate() ops if provided
- otherwise fallbacks (module front / experiment param)
- Common runtime contract
Both the specified backends target:
- PyTorch is often slower per-epoch if GPU is not used or if the environment is CPU-only.
- JAX can appear fast after first compilation because
@jitcompiles the step function once and runs optimized kernels afterwards. - The first JAX epoch may be slower due to compilation overhead (XLA compile).
The backend architecture of SyntraLine++ reflects a compiler-first design listed as such:
- DSL is compiled into IR
- IR is compiled into backend runtime scripts
- scripts are runnable and support real CSV datasets
- backends are modular and extensible (future: TensorFlow, ONNX, TPU, etc.)
dataset mnist_v1: ImageDataset {
source = "data/mnist_train.csv"
test_source = "data/mnist_test.csv"
shape = (28, 28)
channels = 1
batch = 64
shuffle = true
}
dataset mnist_v2: ImageDataset {
source = "data/mnist_train.csv"
test_source = "data/mnist_test.csv"
shape = (28, 28)
channels = 1
batch = 64
shuffle = true
}
model simple_cnn_v1: TorchModel {
arch = "cnn_v1"
framework = "pytorch"
lr = 1e-3
epochs = 5
optimizer = "adam"
}
model simple_cnn_v2: TorchModel {
arch = "cnn_v2"
framework = "pytorch"
lr = 8e-4
epochs = 8
optimizer = "adam"
}
experiment compare_versions(mnist_v1) -> Metrics {
let train_v1 = train(simple_cnn_v1, mnist_v1.train)
let test_v1 = evaluate(simple_cnn_v1, mnist_v1.test) with {
metrics = [accuracy, loss]
}
let train_v2 = train(simple_cnn_v2, mnist_v2.train)
let test_v2 = evaluate(simple_cnn_v2, mnist_v2.test) with {
metrics = [accuracy, loss]
}
return {
acc_v1 = test_v1.accuracy,
loss_v1 = test_v1.loss,
acc_v2 = test_v2.accuracy,
loss_v2 = test_v2.loss
}
}
The idea primarily revolves around the following considerations:
- The DSL contains two train/evaluate blocks inside one experiment.
- The compiler may detect this semantic pattern and emit a dedicated runner with train and eval for
v1, train and eval forv2, and aggregated results.
./build/src/syntra examples/versioning.syntra \
--emit-pytorch --experiment compare_versions > build/run_compare.py
SYNTRA_PREFER_REAL_DATASETS=1 python3.11 build/run_compare.pyThe standard output is displayed as shown below:
[Syntra-PyTorch] Using train source: data/mnist_train.csv
[Syntra-PyTorch] Using test source: data/mnist_test.csv
[version v1][epoch 1/5] train loss = 0.5624
...
[version v1] eval stats: {'loss': 0.0851, 'accuracy': 0.973}
[Syntra-PyTorch] Using train source: data/mnist_train.csv
[Syntra-PyTorch] Using test source: data/mnist_test.csv
[version v2][epoch 1/8] train loss = 0.6041
...
[version v2] eval stats: {'loss': 0.0742, 'accuracy': 0.971}
Final experiment result:
{'acc_v1': 0.973, 'loss_v1': 0.0851, 'acc_v2': 0.971, 'loss_v2': 0.0742}
Despite the generated script executing sequentially (v1 then v2), the DSL semantics represent parallel comparison, where various considerations are proposed as such:
- Both versions are executed under the same program, same compiler run.
- The result is a structured comparison artifact (Dict / Metrics record).
- True parallel execution (threads/processes)
- Multi-device execution
- CI regression testing (fail if acc drops > 1%)
- automatic report generation
If accuracy stays near ~0.10 and loss near ~2.30, then the training are generally executed on:
- random stub data, or
- a CSV that does not match MNIST format (label + 784 pixels)
Thus, ensure to always confirm the log includes as such:
Loaded real data from data/mnist_train.csv ...
Loaded real data from data/mnist_test.csv ...If the specified line does not appear, the loader likely fell back to random mode.
SyntraLine++ is not merely a syntactic convenience layer over existing machine learning frameworks. It is designed as a compiler-driven system, and as such, its design is guided by a set of explicit principles that influence the language syntax, compiler architecture, intermediate representation, and backend code generation. This section formalizes the core principles that govern the SyntraLine++ DSL compiler.
Reproducibility is treated as a first-class design constraint rather than an afterthought. Modern ML experimentation often suffers from:
- implicit state hidden inside scripts
- ad-hoc configuration via environment variables
- non-deterministic execution paths
- undocumented experimental changes
SyntraLine++ addresses these issues by enforcing that:
- All datasets, models, hyperparameters, and experiments are explicitly declared in a
.syntraprogram. - The compiler produces fully materialized execution scripts (PyTorch or JAX) that can be version-controlled.
- Experiments are named, structured, and reproducible by design.
Formally, a SyntraLine++ experiment is a pure function of its source program and runtime data:
There is no hidden control flow, no implicit global state, and no silent hyperparameter mutation. This makes the SyntraLine++ DSL compiler suitable for the following applications:
- real-time experimentation
- controlled ablation studies
- long-term experiment archival
- fair model comparisons
SyntraLine++ enforces strict separation of concerns through composable language constructs. The DSL is specifically built around three orthogonal entities as listed below:
- Datasets: data sources and loading semantics
- Models: architectural and optimization parameters
- Experiments: execution logic and evaluation pipelines
Each entity is:
- declared independently
- validated independently
- composed explicitly in experiments
This enables:
- Reuse of the same dataset across multiple models
- Reuse of the same model across multiple experiments
- Construction of higher-level workflows such as:
- hyperparameter grids
- version comparisons
- evaluation suites
Composability is preserved throughout the compiler pipeline:
$$ \text{DSL} \rightarrow \text{AST} \rightarrow \text{Semantic AST} \rightarrow \text{IR} \rightarrow \text{Backend Code} $$ At no stage are datasets, models, or experiments implicitly merged or mutated.
A key design decision in SyntraLine++ is transparent code generation. Unlike many ML orchestration tools that:
- generate opaque binaries
- hide execution logic behind runtime engines
- require proprietary runtimes
SyntraLine++ generates plain, readable Python code. This ensures that:
- Users can inspect exactly what is executed.
- Generated scripts can be modified, extended, or debugged manually.
- The compiler acts as a code generator, not a black-box executor.
Transparency applies to:
- dataset loading logic
- model definitions
- training loops
- evaluation routines
- experiment orchestration
This principle makes SyntraLine++ especially suitable for:
- education
- research prototyping
- systems experimentation
- bridging theory and practice
Despite its compiler-oriented architecture, SyntraLine++ prioritizes ergonomic language design. The DSL is intentionally designed to be:
- concise
- readable
- declarative
- minimally verbose
A complete experiment can often be expressed in shorter lines as shown below:
dataset mnist(source="data/mnist_train.csv")
model cnn(arch="cnn", lr=1e-3, epochs=5)
experiment cnn_mnist(mnist):
train(cnn, mnist.train)
evaluate(cnn, mnist.test) -> { acc="accuracy" }
Key ergonomic decisions include:
- Sensible defaults for most parameters
- Minimal required syntax
- Explicit but compact mappings between DSL and runtime behavior
- Familiar concepts for users of PyTorch and JAX
The goal is to make the language disappear, allowing users to focus on:
- experimental intent
- architectural comparison
- scientific reasoning
⸻
Finally, SyntraLine++ is designed with a compiler-first regulation, not solely as a runtime DSL. This means:
- Syntax is formally parsed, not dynamically interpreted
- Errors are caught early during compilation
- Semantic validation precedes execution
- Intermediate representations (IR) are explicit and inspectable
This philosophy enables future extensions such as:
- Static analysis of experiments
- Optimization passes over experiment graphs
- Backend-independent transformations
- Integration with distributed or embedded systems
The design principles of SyntraLine++ can be summarized as:
- Reproducible by construction
- Composable by design
- Transparent in execution
- Ergonomic in syntax
- Compiler-driven in architecture
These principles collectively distinguish SyntraLine++ from ad-hoc ML scripting approaches and position it as a research-grade DSL for machine learning pipelines.
This section summarizes the empirical evaluation of SyntraLine++ as a compiler-generated machine learning pipeline system, focusing on correctness, expressiveness, backend parity, and runtime characteristics. Rather than competing with hand-optimized ML code, SyntraLine++ is evaluated on its ability to:
- faithfully translate high-level DSL programs into runnable training pipelines
- preserve semantic intent across backends
- enable structured experimentation with minimal user effort
- maintain performance characteristics consistent with underlying frameworks
SyntraLine++ has been tested across the following experimental scenarios:
- MNIST CNN Training
- Single-model training using convolutional architectures
- Multiple CNN variants (
cnn_small,cnn_deep)
- MNIST MLP Training
- Fully-connected architectures
- Flattened image input pipelines
- Multi-Version Comparison
- Side-by-side evaluation of model and dataset versions
- Independent training loops with structured result aggregation
- Hyperparameter Grid Search
- Multiple experiments sharing architecture but differing in learning rate
- Explicit experiment-level isolation
All evaluations were conducted using real CSV-based MNIST datasets via the compiler’s dataset loader abstraction.
A core requirement of SyntraLine++ is that the same DSL program produces semantically equivalent pipelines across backends. Empirical testing confirms:
- Identical experiment definitions compile successfully to:
- PyTorch execution scripts
- JAX execution scripts
- Training curves exhibit similar convergence behavior
- Accuracy and loss values fall within expected variance ranges
This validates the compiler’s design:
with the IR acting as a stable, backend-agnostic contract.
Observed properties of the PyTorch backend include:
-
Strengths:
- Stable runtime behavior
- Familiar imperative execution model
- Extensive ecosystem compatibility
- Predictable debugging and error traces
-
Trade-offs:
- Slightly slower iteration speed compared to JAX
- Higher runtime memory usage
- No graph-level compilation optimizations
Where the specified PyTorch is well-suited for:
- rapid prototyping
- debugging
- educational use
- environments requiring maximum compatibility
Observed properties of the JAX backend include:
-
Strengths:
- Faster per-epoch execution after compilation
- Lower memory overhead in steady state
- JIT-compiled training loops
- Functional-style execution clarity
-
Trade-offs:
-
Initial compilation overhead on first execution
-
Stricter requirements on static shapes and types
-
Less forgiving debugging experience
Where the specified JAX is particularly suitable for:
- performance-sensitive experimentation
- large-scale iteration
- research into compiler-driven ML execution
Beyond raw performance metrics, SyntraLine++ demonstrates strengths in:
- Experiment clarity: experiment intent is explicit and reviewable
- Reproducibility: pipelines are deterministic and versionable
- Comparative analysis: versioning and grid search are first-class
- Educational value: compiler stages mirror formal language pipelines
The system has been validated not only as a runtime tool, but as a pedagogical and research platform.
SyntraLine++ is designed as an extensible compiler platform. Its roadmap is structured into clearly defined phases, reflecting increasing semantic richness and execution capability.
The foundational compiler and execution infrastructure is complete. Implemented features include:
- DSL grammar and parser
- Abstract Syntax Tree (AST)
- Semantic validation and normalization
- Intermediate Representation (IR)
- PyTorch backend code generation
- JAX backend code generation
- Real CSV-based dataset loading
- CNN and MLP model families
- Experiment selection via CLI
- Version comparison experiments
- Hyperparameter grid experiments
At this stage, SyntraLine++ already functions as a fully working DSL compiler for general ML pipelines.
The current focus is on semantic enrichment and static correctness guarantees. Planned and ongoing work includes:
- Stronger semantic type checking
- Dataset shape inference
- Model–dataset compatibility validation
- Early error detection at compile time
- More informative diagnostic messages
- Cross-experiment consistency checks
These enhancements aim to shift error discovery from runtime to compile time, further aligning SyntraLine++ with traditional compiler guarantees.
Longer-term extensions explore advanced compilation and deployment scenarios:
- Distributed training hints and annotations
- ONNX export backend
- WebAssembly (WASM) backend for edge execution
- Visual and graphical editor for the DSL
- Graph-level optimization passes over experiment pipelines
- Static experiment scheduling and optimization
- Integration with hardware-aware compilation targets
These directions position SyntraLine++ as a potential foundation for:
- ML systems research
- compiler–ML co-design
- reproducible large-scale experimentation
- cross-platform deployment pipelines
The long-term vision of SyntraLine++ is to treat machine learning workflows as first-class programs, subject to:
- formal semantics
- static analysis
- optimization
- backend portability
Rather than replacing existing ML frameworks, SyntraLine++ aims to orchestrate them through principled compilation, bridging the gap between:
- high-level experimental intent
- low-level execution detail
SyntraLine++ demonstrates that machine learning pipelines can be:
- expressive
- reproducible
- compiler-driven
- backend-agnostic
without sacrificing usability or performance.
This project is fully established and contributed by the following author:
- Name: Rizky Johan Saputra
- Institution: Independent
- Role: Project Developer, Manager and Author
- Affiliation: Undergraduate at Seoul National University (Enrolled at 2021, Graduating in 2026)
- Project Scope: Compiler Design, System Programming, Computer Architecture, Real-Time Systems, Machine Learning, Operating System.
This repository is distributed under an Independent Personal License tailored by the author. See LICENSE for the full terms. For further inquiries and requests, please contact via GitHub or Email only.
If you intend to reuse significant portions for research and academia purposes, please open and inquire an issue to discuss attribution and terms.






