LIFT — Language for Intelligent Frameworks and Technologies

Unified intermediate representation for AI and quantum computing.

License: MIT Rust Version crates.io Downloads Documentation CI GitHub Release GitHub Pages

LIFT is a modular compiler framework that provides a single SSA-based intermediate representation spanning tensor operations (AI/ML), quantum gates, and classical-quantum hybrid computation. It enables a unified pipeline: define → verify → optimise → analyse → predict → export.

Why LIFT?

The next decade of computing is both intelligent and quantum. AI models run on GPUs; quantum circuits run on QPUs; and hybrid classical-quantum systems (VQE, QAOA, quantum chemistry, quantum machine learning) need both — but today they live in separate worlds with separate IRs, separate toolchains, and no way to reason about them together.

LIFT's vision is a single unified foundation for AI + quantum computation:

  1. One IR, two worlds — AI tensors, quantum gates, and their hybrids are equal citizens in the same SSA graph. Joint optimisation across classical and quantum operations becomes possible.
  2. Noise in the type system — every quantum gate carries T1/T2, fidelity, and crosstalk metadata, so the compiler reasons about noise at every stage — not after the fact.
  3. Linear qubit types — the no-cloning theorem is enforced at compile time. Reusing a qubit is a type error, not a runtime crash.
  4. Simulation-first compilation — FLOPs, peak memory, circuit depth, expected fidelity, and energy cost are computed before any hardware runs. Budget violations halt compilation with actionable suggestions.
  5. One config language — a single .lith file replaces the 6–8 configuration files scattered across separate frameworks.

LIFT — because the future of computation is both intelligent and quantum, and it deserves a unified foundation.

Key Features

  • 110 tensor operations — arithmetic, attention (Flash, Paged, GQA), convolutions, normalisation, quantisation, MoE, GNN, diffusion, and more
  • 48 quantum gates — Pauli, Clifford, parametric, multi-qubit; noise models, Kraus channels, QEC codes
  • 21 hybrid operations — encoding strategies, gradient methods (parameter shift, adjoint), variational algorithms (VQC, VQE, QAOA)
  • 13 optimisation passes — canonicalise, constant folding, DCE, CSE, tensor fusion, FlashAttention replacement, quantisation annotation, gate cancellation, rotation merging, noise-aware scheduling, qubit layout mapping, gate decomposition, real qubit routing
  • 3 export backendsLLVM IR (GPU/CPU runtime), ONNX (opset 21, PyTorch/TensorFlow/TensorRT interop), OpenQASM 3.0 (IBM, Rigetti, IonQ, Quantinuum)
  • Optimisation levels O0O3 — preset pipelines, explicit-pass override, per-pass enable/disable
  • Semantic verificationverify checks operation arity against dialect signatures (core + tensor + quantum + hybrid)
  • Hardware-native gate decomposition — H/T/S/Y/RX lowering to provider gate sets (IBM, Rigetti, IonQ, Quantinuum)
  • Real qubit routing — SWAP insertion with BFS shortest paths over device topologies
  • Generic tensor fusion — matmul+bias+relu, linear+gelu/silu, conv+bn+relu
  • Non-adjacent gate cancellation & rotation merging — cancels/merges pairs across commuting gates
  • Programmatic model generationModelBuilder API for defining models from Rust code, lift-codegen binary for automatic .lif/.lith/.ll/.onnx/.qasm generation
  • Cost modelling — roofline analysis, GPU/QPU profiles (A100, H100, IBM, IonQ, etc.), energy/carbon estimation
  • Performance prediction — compute vs memory bottleneck identification

Architecture

Compilation pipeline

The pipeline reads left to right: Frontend → Core (with semantic verification) → Dialects → Optimise → Analyse → Export. The 13 optimisation passes are orchestrated by lift-config at the Optimise stage.

flowchart LR
    subgraph Frontend["Frontend"]
        LIF[".lif source"]
        LITH[".lith config"]
        CODGEN["lift-codegen / ModelBuilder"]
    end

    subgraph Core["Core + Verify"]
        AST["lift-ast (lexer / parser)"]
        IR["lift-core — SSA IR, verifier"]
    end

    subgraph Dialects["Dialects"]
        TEN["lift-tensor (AI ops)"]
        QUA["lift-quantum (gates, noise)"]
        HYB["lift-hybrid (fusion)"]
    end

    subgraph Optimise["Optimise"]
        CFG["lift-config (O0-O3)"]
        OPT["lift-opt (13 passes)"]
    end

    subgraph Analyse["Analyse"]
        SIM["lift-sim (FLOPs, memory)"]
        PRED["lift-predict (roofline)"]
    end

    subgraph Export["Export"]
        LLVM["LLVM IR"]
        ONNX["ONNX"]
        QASM["OpenQASM 3.0"]
    end

    LIF --> AST
    LITH --> CFG
    CODGEN --> AST
    AST --> IR
    IR --> TEN & QUA & HYB
    IR --> OPT
    CFG --> OPT
    OPT --> SIM
    SIM --> PRED
    IR --> SIM
    IR --> LLVM & ONNX & QASM
    OPT --> LLVM & ONNX & QASM

    classDef stage fill:#e8f0fe,stroke:#1a73e8,color:#174ea6;
    class Frontend,Core,Dialects,Optimise,Analyse,Export stage;

Crate dependency graph (by layer)

flowchart TB
    subgraph L4["Layer 4 — Tools"]
        CLI["lift-cli"]
        CGEN["lift-codegen"]
    end
    subgraph L3["Layer 3 — Prediction"]
        PRED["lift-predict"]
    end
    subgraph L2["Layer 2 — Analysis & I/O"]
        OPT["lift-opt"]
        SIM["lift-sim"]
        EXP["lift-export"]
        IMP["lift-import"]
        HYB["lift-hybrid"]
    end
    subgraph L1["Layer 1 — Dialects & Frontend"]
        AST["lift-ast"]
        TEN["lift-tensor"]
        QUA["lift-quantum"]
    end
    subgraph L0["Layer 0 — Foundation"]
        CORE["lift-core"]
        CFG["lift-config"]
    end

    CLI --> PRED & OPT & SIM & EXP & HYB & AST & TEN & QUA & CORE & CFG
    CGEN --> PRED & OPT & SIM & EXP & AST & CORE & CFG
    PRED --> SIM & CORE & TEN & QUA
    OPT --> CORE & TEN & QUA
    SIM --> CORE & TEN & QUA
    EXP --> CORE & TEN & QUA
    IMP --> CORE & TEN & QUA
    HYB --> CORE & TEN & QUA
    AST --> CORE
    TEN --> CORE
    QUA --> CORE

    classDef l0 fill:#f3e8ff,stroke:#7c3aed;
    classDef l1 fill:#e8f0fe,stroke:#1a73e8;
    classDef l2 fill:#e6f4ea,stroke:#188038;
    classDef l3 fill:#fef7e0,stroke:#f9ab00;
    classDef l4 fill:#fce8e6,stroke:#d93025;
    class CORE,CFG l0;
    class AST,TEN,QUA l1;
    class OPT,SIM,EXP,IMP,HYB l2;
    class PRED l3;
    class CLI,CGEN l4;

Chaque arête A → B signifie « la crate A dépend de B » (vérifié via cargo metadata). Les crates sont disposées par niveau de dépendance (de haut en bas, L4L0) : rien ne pointe vers le haut.

Crates

CrateDescription
lift-coreSSA IR, type system, verifier, printer, pass manager, dialect registry, ModelBuilder
lift-astLexer, parser, IR builder for .lif source files
lift-tensor110 tensor operations with shape inference and FLOP counting
lift-quantum48 quantum gates, hardware providers, device topology, noise models, Kraus channels, QEC
lift-hybrid21 hybrid ops — encoding, gradient methods, variational algorithms, co-execution
lift-opt13 optimisation passes (classical, quantum, and AI-specific)
lift-simClassical/quantum cost models, energy estimation, reactive budgets, module analysis
lift-predictRoofline-based performance prediction
lift-importONNX, PyTorch FX, OpenQASM 3.0 importers
lift-exportLLVM IR, ONNX (opset 21), OpenQASM 3.0 exporters
lift-config.lith configuration file parser
lift-cliCommand-line interface (verify, analyse, optimise, predict, export, print)
lift-codegenProgrammatic model generation binary — define models from Rust, emit all formats

Published Crates (v0.4.4)

All LIFT crates are published to crates.io:

Quick Start

Prerequisites

  • Rust 1.80+ — install via rustup

Install the CLI from crates.io

cargo install lift-cli

This installs the lift binary with the verify, analyse, optimise, predict, and export commands.

Build from source

git clone https://github.com/rustnew/Lift.git
cd Lift
cargo build --release

Run the CLI

# Verify a .lif file
cargo run --release -p lift-cli -- verify examples/phi3_mini.lif

# Analyse
cargo run --release -p lift-cli -- analyse examples/phi3_mini.lif

# Optimise
cargo run --release -p lift-cli -- optimise examples/phi3_mini.lif --config examples/phi3_optimize.lith

# Predict performance
cargo run --release -p lift-cli -- predict examples/phi3_mini.lif --device h100

# Export to LLVM IR
cargo run --release -p lift-cli -- export examples/phi3_mini.lif --backend llvm --output model.ll

# Export to ONNX
cargo run --release -p lift-cli -- export examples/phi3_mini.lif --backend onnx --output model.onnx

# Export to OpenQASM 3.0
cargo run --release -p lift-cli -- export examples/quantum_bell.lif --backend qasm --output circuit.qasm

Programmatic Model Generation

Define models directly from Rust code and generate all formats with a single command:

cargo run --bin lift-codegen

This generates into examples/:

  • 4 .lif models — Phi-3-mini, MLP, ResNet block, VQE circuit
  • 4 .ll files — LLVM IR exports
  • 4 .onnx files — ONNX exports
  • 1 .qasm file — OpenQASM export (for quantum models)
  • 1 .lith config — H100 optimization configuration

Each model is automatically verified, analysed, optimised, and exported.

Define Models from Rust

#![allow(unused)]
fn main() {
use lift_core::model_builder::{ModelBuilder, tensor, tensor_2d, DataType};

let model = ModelBuilder::new("my_model")
    .function("forward")
        .param("x", tensor(&[1, 784], DataType::FP32))
        .param("w", tensor_2d(784, 256, DataType::FP32))
        .op("tensor.matmul", &["x", "w"], "h", tensor(&[1, 256], DataType::FP32))
        .op("tensor.relu", &["h"], "out", tensor(&[1, 256], DataType::FP32))
        .returns("out")
        .done();

// Generate .lif source (parseable by lift-cli)
model.write_lif("my_model.lif").unwrap();

// Build IR context for verification/analysis/export
let ctx = model.build_context();
lift_core::verifier::verify(&ctx).unwrap();

// Export to all backends
let llvm_ir = lift_export::LlvmExporter::new().export(&ctx).unwrap();
let onnx_ir = lift_export::OnnxExporter::new().export(&ctx).unwrap();
std::fs::write("my_model.ll", &llvm_ir).unwrap();
std::fs::write("my_model.onnx", &onnx_ir).unwrap();
}

Use as a Library

[dependencies]
lift-core    = "0.4.4"
lift-ast     = "0.4.4"
lift-tensor  = "0.4.4"
lift-quantum = "0.4.4"
lift-hybrid  = "0.4.4"
lift-opt     = "0.4.4"
lift-sim     = "0.4.4"
lift-predict = "0.4.4"
lift-import  = "0.4.4"
lift-export  = "0.4.4"
lift-config  = "0.4.4"
#![allow(unused)]
fn main() {
use lift_ast::{Lexer, Parser, IrBuilder};
use lift_core::{Context, verifier, pass::PassManager};
use lift_quantum::{Provider, DeviceTopology};

// Parse a .lif file
let source = std::fs::read_to_string("model.lif").unwrap();
let tokens = Lexer::new(&source).tokenize().to_vec();
let program = Parser::new(tokens).parse().unwrap();

let mut ctx = Context::new();
IrBuilder::new().build_program(&mut ctx, &program).unwrap();

// Verify (structural + semantic against dialect signatures)
verifier::verify(&ctx).unwrap();

// Optimise (all 13 passes)
let mut pm = PassManager::new();
pm.add_pass(Box::new(lift_opt::Canonicalize));
pm.add_pass(Box::new(lift_opt::ConstantFolding));
pm.add_pass(Box::new(lift_opt::DeadCodeElimination));
pm.add_pass(Box::new(lift_opt::CommonSubexprElimination));
pm.add_pass(Box::new(lift_opt::TensorFusion));
pm.add_pass(Box::new(lift_opt::FlashAttentionPass::default()));
pm.add_pass(Box::new(lift_opt::QuantisationPass::default()));
pm.add_pass(Box::new(lift_opt::GateCancellation));
pm.add_pass(Box::new(lift_opt::RotationMerge));
pm.add_pass(Box::new(lift_opt::NoiseAwareSchedule));
pm.add_pass(Box::new(lift_opt::LayoutMapping));
pm.add_pass(Box::new(lift_opt::GateDecomposition::new(Provider::IbmKyoto)));
pm.add_pass(Box::new(lift_opt::RealRouting::new(DeviceTopology::linear(8))));
pm.run_all(&mut ctx);

// Export to all 3 backends
let llvm = lift_export::LlvmExporter::new().export(&ctx).unwrap();
let onnx = lift_export::OnnxExporter::new().export(&ctx).unwrap();
let qasm = lift_export::QasmExporter::new().export(&ctx).unwrap();
}

Export Backends

LLVM IR

Generates LLVM IR with runtime function calls for all 110 tensor operations (cuBLAS/cuDNN backend):

lift export model.lif --backend llvm --output model.ll

ONNX

Generates ONNX protobuf text format (opset 21) compatible with PyTorch, TensorFlow, TensorRT, and ONNX Runtime. Supports Microsoft extensions for attention and MoE operations:

lift export model.lif --backend onnx --output model.onnx

Supported ONNX op mappings:

LIFT OperationONNX OpDomain
tensor.matmulMatMulstandard
tensor.linearGemmstandard
tensor.reluRelustandard
tensor.geluGelustandard
tensor.softmaxSoftmaxstandard
tensor.layernormLayerNormalizationstandard
tensor.rmsnormSimplifiedLayerNormalizationcom.microsoft
tensor.conv2dConvstandard
tensor.attentionAttentioncom.microsoft
tensor.grouped_query_attentionGroupQueryAttentioncom.microsoft
tensor.flash_attentionMultiHeadAttentioncom.microsoft
tensor.quantizeQuantizeLinearstandard
tensor.dequantizeDequantizeLinearstandard
tensor.moe_dispatchMoEcom.microsoft
+ 60 more operations

OpenQASM 3.0

Generates OpenQASM 3.0 for quantum hardware execution. Supports all 48 gates including IBM, Rigetti, IonQ, and Quantinuum native gate sets:

lift export quantum.lif --backend qasm --output circuit.qasm

File Formats

ExtensionDescription
.lifLIFT IR source code
.lithCompilation configuration
.llLLVM IR export
.onnxONNX export (protobuf text)
.qasmOpenQASM 3.0 export

Examples

See the examples/ directory:

Hand-written models

  • phi3_mini.lif — Phi-3-mini transformer
  • llama2_7b.lif — LLaMA-2 7B
  • mistral_7b.lif — Mistral 7B (sliding window attention)
  • bert_base.lif — BERT-base
  • tensor_mlp.lif — Multi-layer perceptron
  • quantum_bell.lif — Bell state preparation

Generated models (via cargo run --bin lift-codegen)

  • phi3_generated.lif — Phi-3-mini (programmatic)
  • mlp_generated.lif — MLP classifier (programmatic)
  • resnet_generated.lif — ResNet block (programmatic)
  • vqe_generated.lif — VQE circuit (programmatic)

Validation

bash examples/validate_all.sh   # Full pipeline validation (105 checks)

Documentation

Contributing

Contributions are welcome! See CONTRIBUTING.md for the development workflow, project layout, code style, and how to open a pull request.

Roadmap

LIFT is built in phases. Each phase is released on crates.io and validated end-to-end (examples/validate_all.sh).

flowchart LR
    V3["v0.3 — IR, dialects, 11 passes, export"]
    V4["v0.4 — O0-O3 pipeline, semantic verify, 13 passes, crates.io"]
    V5["v0.5 — simulator, real backends, importers"]
    V6["v0.6 — autodiff, Python bindings, v1.0"]
    V3 --> V4 --> V5 --> V6

v0.4 (current) — done

  • Optimisation pipeline by level (O0O3) with explicit-pass override
  • Semantic verification (op arity vs dialect signatures)
  • 13 optimisation passes: generic tensor fusion, hardware-native gate decomposition, real qubit routing (SWAP + BFS), non-adjacent gate cancellation & rotation merging
  • All 13 crates published to crates.io

v0.5 — in progress

  • State-vector quantum simulator (CPU, up to ~25 qubits) — validate circuits before deploying to real QPUs
  • Tensor interpreter — execute tensor ops with real values (numpy-like)
  • Real LLVM IR lowering with cuBLAS/cuDNN runtime calls
  • Functional importers — ONNX, PyTorch FX, OpenQASM 3 (currently stubs)
  • SABRE-style dynamic qubit re-placement

v0.6 — planned

  • True automatic differentiation (backward graph construction)
  • PyO3 Python bindings — use LIFT from Python
  • Multi-file support (include / linking)
  • v1.0 release — full pipeline, benchmarks, arXiv paper

License

MIT

Complete LIFT Framework Guide — All Features

LIFTLanguage for Intelligent Frameworks and Technologies Unified intermediate representation for AI and quantum computing.

This document describes every feature of the LIFT framework, numbered and organised by crate. For each feature: what it does, how to use it, and which other features to combine it with.


Table of Contents

  1. General Architecture
  2. lift-core — IR Core
  3. lift-ast — Parsing the .lif Language
  4. lift-tensor — Tensor Operations (110 ops)
  5. lift-quantum — Quantum Gates and Noise (48 gates)
  6. lift-hybrid — Classical-Quantum Hybrid Computation
  7. lift-opt — Optimisation Passes (13 passes)
  8. lift-sim — Simulation and Cost Analysis
  9. lift-predict — Performance Prediction
  10. lift-import — Model Import
  11. lift-export — Backend Export (LLVM, ONNX, QASM)
  12. lift-config — Configuration (.lith)
  13. lift-cli — Command-Line Interface
  14. lift-codegen — Programmatic Model Generation
  15. Combinations and Complete Pipelines
  16. Concrete Examples

1. General Architecture

LIFT is a modular compiler composed of 14 crates organised in layers:

                    ┌──────────┐
                    │ lift-cli │  ← User interface
                    └────┬─────┘
           ┌─────────────┼─────────────┐
           │             │             │
    ┌──────┴──────┐ ┌────┴────┐ ┌──────┴──────┐
    │ lift-import │ │lift-opt │ │ lift-export │
    └──────┬──────┘ └────┬────┘ └──────┬──────┘
           │             │             │
    ┌──────┴──────┐ ┌────┴────┐ ┌──────┴──────┐
    │  lift-ast   │ │lift-sim │ │lift-predict │
    └──────┬──────┘ └────┬────┘ └──────┬──────┘
           │             │             │
    ┌──────┴─────────────┴─────────────┴──────┐
    │              lift-core                    │
    ├──────────┬──────────┬───────────────────┤
    │lift-tensor│lift-quantum│  lift-hybrid    │
    └──────────┴──────────┴───────────────────┘

1.1 Compilation Pipeline

The standard workflow is:

Source (.lif) → Lexer → Parser → IR (SSA) → Verification → Optimisation → Simulation → Export

1.2 File Formats

ExtensionDescription
.lifLIFT IR source code
.lithCompilation configuration
.llLLVM IR export
.onnxONNX export (protobuf text)
.qasmOpenQASM 3.0 export

1.3 Adding LIFT as a Dependency

[dependencies]
lift-core     = "0.4.3"
lift-ast      = "0.4.3"
lift-tensor   = "0.4.3"
lift-quantum  = "0.4.3"
lift-hybrid   = "0.4.3"
lift-opt      = "0.4.3"
lift-sim      = "0.4.3"
lift-predict  = "0.4.3"
lift-import   = "0.4.3"
lift-export   = "0.4.3"
lift-config   = "0.4.3"

2. lift-core — IR Core

The heart of the framework. Provides the SSA (Static Single Assignment) intermediate representation.

2.1 Context — The Central Container

#![allow(unused)]
fn main() {
use lift_core::Context;

let mut ctx = Context::new();
}

The Context stores all IR data: values, operations, blocks, regions, functions, modules, interned strings, and types.

FieldDescriptionUsage
ctx.valuesAll SSA valuesEach operation result is a unique value
ctx.opsAll operationsProgram instructions
ctx.blocksBasic blocksContain sequences of operations
ctx.regionsRegionsContain blocks (function bodies)
ctx.modulesModulesCompilation units
ctx.stringsString interningctx.strings.intern("name")
ctx.type_internerType interningType deduplication

Combine with: All other crates. The Context is the entry point for every pipeline.

2.2 Types — Type System

#![allow(unused)]
fn main() {
use lift_core::types::*;

// Data types
let fp32 = DataType::FP32;
let fp16 = DataType::FP16;
let bf16 = DataType::BF16;
let int8 = DataType::INT8;
let fp64 = DataType::FP64;

// Dimensions (static or symbolic)
let batch = Dimension::Constant(32);
let seq = Dimension::Symbolic("seq_len".to_string());

// Tensor type info
let tensor_info = TensorTypeInfo {
    shape: vec![Dimension::Constant(1), Dimension::Constant(784)],
    dtype: DataType::FP32,
    layout: MemoryLayout::Contiguous,
};

// Size in bytes
let bytes = tensor_info.size_bytes(); // Some(3136) = 1*784*4
}

Available data types:

TypeSizeUsage
FP648 bytesHigh-precision scientific computing
FP324 bytesStandard training
FP162 bytesFast inference
BF162 bytesMixed-precision training (Google Brain)
INT81 bytePost-training quantisation
INT324 bytesIndices, counters
BOOL1 byteMasks

Memory layouts: Contiguous, Strided.

2.3 Attributes — Operation Metadata

#![allow(unused)]
fn main() {
use lift_core::attributes::{Attribute, Attributes};

let mut attrs = Attributes::new();

// Different attribute types
attrs.set("num_heads", Attribute::Integer(8));
attrs.set("dropout", Attribute::Float(0.1));
attrs.set("causal", Attribute::Bool(true));

// Reading
let heads = attrs.get_integer("num_heads"); // Some(8)
let drop = attrs.get_float("dropout");       // Some(0.1)
let causal = attrs.get_bool("causal");       // Some(true)

// Checking
assert!(attrs.contains("num_heads"));
assert_eq!(attrs.len(), 3);

// Iteration
for (key, val) in attrs.iter() {
    println!("{}: {:?}", key, val);
}
}

Combine with: lift-opt (passes read/write attributes), lift-export (exporters read attributes).

2.4 Verifier — Invariant Checking

#![allow(unused)]
fn main() {
use lift_core::verifier;

let ctx = Context::new();
match verifier::verify(&ctx) {
    Ok(()) => println!("IR valid"),
    Err(errors) => {
        for e in &errors {
            eprintln!("Error: {}", e);
        }
    }
}
}

Checks:

  • SSA: every value is defined exactly once
  • Qubit linearity: every qubit is used exactly once
  • Typing: type consistency between operations
  • Structure: blocks, regions, terminators are correct

Combine with: Always use after import and after each optimisation pass.

2.5 Printer — IR Display

#![allow(unused)]
fn main() {
use lift_core::printer::print_ir;

let ctx = Context::new();
let output = print_ir(&ctx);
println!("{}", output);
}

Produces a human-readable textual representation of the IR, useful for debugging.

2.6 Pass Manager

#![allow(unused)]
fn main() {
use lift_core::pass::{PassManager, Pass, PassResult, AnalysisCache};

let mut pm = PassManager::new();
pm.add_pass(Box::new(lift_opt::Canonicalize));
pm.add_pass(Box::new(lift_opt::DeadCodeElimination));
pm.add_pass(Box::new(lift_opt::TensorFusion));

let results = pm.run_all(&mut ctx);
for (name, result) in &results {
    match result {
        PassResult::Changed => println!("{}: changed", name),
        PassResult::Unchanged => println!("{}: unchanged", name),
        PassResult::Error(e) => println!("{}: error: {}", name, e),
        PassResult::RolledBack => println!("{}: rolled back", name),
    }
}
}

Combine with: lift-opt (all 13 passes), lift-config (pass selection via configuration).

2.7 Dialect — Dialect System

#![allow(unused)]
fn main() {
use lift_core::dialect::{DialectRegistry, Dialect};

let registry = DialectRegistry::new();
// The tensor, quantum, hybrid dialects are registered automatically
}

The three LIFT dialects:

  • tensor: tensor operations (tensor.matmul, tensor.relu, etc.)
  • quantum: quantum gates (quantum.h, quantum.cx, etc.)
  • hybrid: hybrid operations (hybrid.encode, hybrid.vqc_layer, etc.)

3. lift-ast — Parsing the .lif Language

3.1 Lexer — Tokenisation

#![allow(unused)]
fn main() {
use lift_ast::Lexer;

let source = r#"
dialect tensor
module @mlp {
    func @forward(%x: tensor<1x784xf32>) -> tensor<1x10xf32> {
        %out = "tensor.relu"(%x) : (tensor<1x784xf32>) -> tensor<1x784xf32>
        return %out
    }
}
"#;

let mut lexer = Lexer::new(source);
let tokens = lexer.tokenize().to_vec();
assert!(lexer.errors().is_empty(), "Lexing errors: {:?}", lexer.errors());
}

3.2 Parser — Syntactic Analysis

#![allow(unused)]
fn main() {
use lift_ast::Parser;

let mut parser = Parser::new(tokens);
let program = parser.parse().expect("Parsing errors");
}

3.3 IrBuilder — IR Construction

#![allow(unused)]
fn main() {
use lift_ast::IrBuilder;
use lift_core::Context;

let mut ctx = Context::new();
let mut builder = IrBuilder::new();
builder.build_program(&mut ctx, &program).expect("IR construction errors");
}

3.4 Complete Parsing Pipeline

#![allow(unused)]
fn main() {
fn load_lif_file(path: &str) -> Result<Context, String> {
    let source = std::fs::read_to_string(path)
        .map_err(|e| format!("Read failed: {}", e))?;

    let mut lexer = Lexer::new(&source);
    let tokens = lexer.tokenize().to_vec();
    if !lexer.errors().is_empty() {
        return Err(format!("Lexer errors: {:?}", lexer.errors()));
    }

    let mut parser = Parser::new(tokens);
    let program = parser.parse().map_err(|e| format!("Parser errors: {:?}", e))?;

    let mut ctx = Context::new();
    let mut builder = IrBuilder::new();
    builder.build_program(&mut ctx, &program)?;
    Ok(ctx)
}
}

Combine with: lift-core (Context), then lift-opt (optimisation), lift-sim (analysis), lift-export (compilation).


4. lift-tensor — Tensor Operations (110 ops)

4.1 Complete Operation List by Category

4.1.1 Basic Arithmetic (5 ops)

#OpIR NameInputsDescription
1Addtensor.add2Element-wise addition
2Subtensor.sub2Subtraction
3Multensor.mul2Element-wise multiplication
4Divtensor.div2Division
5Negtensor.neg1Negation
#![allow(unused)]
fn main() {
use lift_tensor::ops::TensorOp;

let op = TensorOp::MatMul;
println!("Nom: {}", op.name());           // "tensor.matmul"
println!("Inputs: {:?}", op.num_inputs()); // (2, 2)
println!("FLOPs: {}", op.flops_formula()); // "2*M*N*K"
}

4.1.2 Linear Algebra (4 ops)

#OpInputsDescription
6MatMul2Matrix multiplication
7Linear3Linear layer (matmul + bias)
8Embedding2Embedding lookup table
9SparseMatMul2Sparse MatMul

4.1.3 Activations (11 ops)

#OpDescriptionFLOPs Formula
10ReLUmax(0, x)N
11GeLUGaussian Error Linear Unit~8N
12SiLUx * sigmoid(x) (Swish)~8N
13Sigmoid1/(1+exp(-x))N
14TanhHyperbolic tangentN
15Softmaxexp(x)/sum(exp(x))5N
16LeakyReLUmax(αx, x)N
17ELUExponential Linear UnitN
18Mishx * tanh(softplus(x))~8N
19HardSwishSwish approximation~8N
20HardSigmoidSigmoid approximationN
#![allow(unused)]
fn main() {
assert!(TensorOp::ReLU.is_activation());
assert!(!TensorOp::MatMul.is_activation());
}

4.1.4 Normalisation (5 ops)

#OpInputsDescription
21LayerNorm2-3Layer normalisation
22RMSNorm2-3Root Mean Square Norm (LLaMA)
23BatchNorm3-5Batch normalisation
24GroupNorm2-3Group normalisation
25InstanceNorm2-3Instance normalisation
#![allow(unused)]
fn main() {
assert!(TensorOp::LayerNorm.is_normalisation());
}

4.1.5 Attention (8 ops)

#OpInputsDescription
26Attention3-4Standard attention (Q, K, V, [mask])
27MultiHeadAttention3-4Multi-head
28MultiQueryAttention3-4Multi-query (Llama)
29GroupedQueryAttention3-4Grouped query (GQA)
30FlashAttention3-4FlashAttention V2 (O(N) memory)
31SlidingWindowAttention3-4Sliding window (Mistral)
32CrossAttention3-4Cross-attention (encoder-decoder)
33PagedAttention3-5Paged attention (vLLM)
#![allow(unused)]
fn main() {
assert!(TensorOp::FlashAttention.is_attention());
}

4.1.6 Convolutions (6 ops)

#OpDescription
34Conv2DConvolution 2D standard
35Conv1D1D convolution (audio, sequences)
36Conv3D3D convolution (video, volumetric)
37ConvTranspose2DTransposed convolution (upsampling)
38DepthwiseConv2DDepthwise convolution (MobileNet)
39DilatedConv2DDilated convolution (large receptive field)

4.1.7 Pooling (4 ops)

#OpDescription
40MaxPool2DMax pooling 2D
41AvgPool2DAverage pooling 2D
42AdaptiveAvgPool2DAdaptive average pooling
43GlobalAvgPoolGlobal average pooling

4.1.8 Shape Operations (13 ops)

#OpDescriptionFLOPs
44ReshapeChange shape0
45TransposeTranspose0
46ConcatConcatenate0
47SplitSplit0
48GatherAdvanced indexing0
49ScatterIndexed write0
50SqueezeRemove dim=10
51UnsqueezeAdd dim=10
52PermutePermute dimensions0
53ExpandBroadcast expansion0
54SliceSlice0
55PadPadding0
56TileRepeat0
#![allow(unused)]
fn main() {
assert!(TensorOp::Reshape.is_zero_flop());
}

4.1.9 Constants (5 ops)

#OpDescription
57ConstantConstant tensor
58ZerosZero tensor
59OnesOnes tensor
60ArangeSequence [0, 1, ..., n-1]
61FullTensor filled with a value

4.1.10 Recurrent (3 ops)

#OpDescription
62LSTMCellLSTM cell
63GRUCellGRU cell
64RNNCellSimple RNN cell

4.1.11 Advanced Mathematics (9 ops)

#OpDescription
65EinsumEinstein notation
66FFTFast Fourier Transform
67IFFTInverse FFT
68SVDSingular Value Decomposition
69EigEigendecomposition
70SolveLinear system solver
71TopKTop-K values
72SortSort
73CumsumCumulative sum

4.1.12 Quantisation (6 ops)

#OpDescription
74QuantizeFP → INT8
75DequantizeINT8 → FP
76QuantizeInt4FP → INT4
77DequantizeInt4INT4 → FP
78QuantizeFp8FP → FP8
79DequantizeFp8FP8 → FP

4.1.13 Diffusion / Generative (3 ops)

#OpDescription
80UNetDownBlockU-Net down block
81UNetUpBlockU-Net up block
82TimestepEmbeddingTimestep embedding (Stable Diffusion)

4.1.14 GNN — Graph Neural Networks (2 ops)

#OpDescription
83GNNMessagePassingGNN message passing
84GNNGlobalPoolingGNN global pooling

4.1.15 MoE — Mixture of Experts (2 ops)

#OpDescription
85MoEDispatchRoute to experts
86MoECombineCombine expert outputs

4.1.16 Memory and Gradient (11 ops)

#OpDescription
87CheckpointGradient checkpointing (memory saving)
88OffloadCPU offload (for large models)
89GradAccumulateGradient accumulation
90GradMatMulMatMul gradient
91GradReLUReLU gradient
92GradSoftmaxSoftmax gradient
93GradLayerNormLayerNorm gradient
94GradAttentionAttention gradient
95GradConv2DConv2D gradient
96GradLinearLinear gradient
97GradGeLUGeLU gradient

4.1.17 Parallelism (4 ops)

#OpDescription
98ParallelSplitData parallel split
99ParallelAllReduceAll-reduce across GPUs
100PipelineSendPipeline parallel send
101PipelineReceivePipeline parallel receive

4.1.18 Fused Operations (6 ops)

#OpDescriptionGain
102FusedMatMulBiasReLUMatMul + Bias + ReLU1 kernel instead of 3
103FusedMatMulBiasMatMul + Bias1 kernel instead of 2
104FusedLinearGeLULinear + GeLUBandwidth gain
105FusedAttentionLayerNormAttention + LayerNormMemory reduction
106FusedLinearSiLULinear + SiLUBandwidth gain
110FusedConvBatchNormReLUConv + BN + ReLUFast inference

4.2 Shape Inference

#![allow(unused)]
fn main() {
use lift_core::types::*;
use lift_tensor::ops::TensorOp;
use lift_tensor::shape::ShapeInference;

fn mk(shape: Vec<usize>, dtype: DataType) -> TensorTypeInfo {
    TensorTypeInfo {
        shape: shape.into_iter().map(Dimension::Constant).collect(),
        dtype,
        layout: MemoryLayout::Contiguous,
    }
}

// Shape inference
let a = mk(vec![2, 3, 64], DataType::FP32);
let b = mk(vec![2, 64, 128], DataType::FP32);
let result = ShapeInference::infer_output_shape(&TensorOp::MatMul, &[&a, &b]).unwrap();
// result[0].shape = [2, 3, 128]

// FLOP computation
let flops = ShapeInference::compute_flops(&TensorOp::MatMul, &[&a, &b]);
println!("FLOPs: {:?}", flops); // Some(49152)

// Memory computation
let mem = ShapeInference::compute_memory_bytes(&TensorOp::MatMul, &[&a, &b]);
println!("Memory: {:?} bytes", mem);
}

Combine with: lift-sim (cost model uses FLOPs), lift-predict (roofline prediction).

4.3 Useful Predicates

#![allow(unused)]
fn main() {
let op = TensorOp::FlashAttention;

op.is_attention();      // true — attention variant?
op.is_convolution();    // false — convolution?
op.is_normalisation();  // false — normalisation?
op.is_activation();     // false — activation?
op.is_fused();          // false — fused operation?
op.is_gradient();       // false — gradient operation?
op.is_zero_flop();      // false — zero FLOPs (reshape, etc.)?
op.num_inputs();        // (3, 4) — min/max number of inputs
op.flops_formula();     // "2*B*H*(S^2*D + S*D^2)"
}

5. lift-quantum — Quantum Gates and Noise (48 gates)

5.1 Quantum Gates

5.1.1 Standard 1-Qubit Gates (9 gates)

#GateIR NameTypeDescription
1Hquantum.hCliffordHadamard
2Xquantum.xPauliQuantum NOT (bit-flip)
3Yquantum.yPauliY rotation by π
4Zquantum.zPauliPhase-flip
5Squantum.sCliffordPhase π/2
6Sdgquantum.sdgCliffordS inverse
7Tquantum.tNon-CliffordPhase π/4 (expensive for QEC)
8Tdgquantum.tdgNon-CliffordT inverse
9SXquantum.sxCliffordSquare root of X

5.1.2 Parametric 1-Qubit Gates (9 gates)

#GateParametersDescription
10RXθRotation around X
11RYθRotation around Y
12RZθRotation around Z
13PφPhase gate
14U1λU1 unitary gate
15U2φ, λU2 unitary gate
16U3θ, φ, λGeneral unitary gate
17Rx90Fixed RX(π/2)
18Rx180Fixed RX(π)

5.1.3 2-Qubit Gates (14 gates)

#GateDescriptionNative for
19CXCNOTIBM
20CZControlled-ZIBM, Rigetti
21CYControlled-Y
22SWAPQubit swap
23ISWAPiSWAPRigetti
24ECREchoed Cross-ResonanceIBM Eagle
25RZXZX rotationIBM
26XXIsing XXIonQ
27YYIsing YYIonQ
28ZZIsing ZZIonQ
29CPhaseControlled PhaseRigetti
30XYXY interactionRigetti
31CPControlled Phase
32MSMølmer–SørensenIonQ

5.1.4 3-Qubit and Multi-Control Gates (4 gates)

#GateDescription
33CCXToffoli (CCNOT)
34CSWAPFredkin
35MCXMulti-controlled X
36MCZMulti-controlled Z

5.1.5 Special and Control Gates (10 gates)

#GateDescription
37GlobalPhaseGlobal phase
38DelayDelay (decoherence)
39VirtualRZVirtual RZ (no physical cost)
40IfElseClassical conditional control
41MeasureMeasure 1 qubit
42MeasureAllMeasure all qubits
43ResetReset
44BarrierBarrier (prevents optimisation)
45InitInitialisation
46ParamGateGeneric parametric gate
#![allow(unused)]
fn main() {
use lift_quantum::gates::QuantumGate;

let gate = QuantumGate::H;
println!("Name: {}", gate.op_name());       // "quantum.h"
println!("Qubits: {}", gate.num_qubits());  // 1
println!("Clifford: {}", gate.is_clifford()); // true
println!("Parametric: {}", gate.is_parametric()); // false
println!("Self-inverse: {}", gate.is_self_inverse()); // true

// Look up a gate by its IR name
let gate = QuantumGate::from_name("quantum.cx"); // Some(CX)
}

5.2 Hardware Providers — Native Gate Sets

#![allow(unused)]
fn main() {
use lift_quantum::gates::{QuantumGate, Provider};

// Native gates per provider
let ibm_basis = QuantumGate::native_basis(Provider::IbmEagle);
let rigetti_basis = QuantumGate::native_basis(Provider::Rigetti);
let ionq_basis = QuantumGate::native_basis(Provider::IonQ);
let quant_basis = QuantumGate::native_basis(Provider::Quantinuum);
}
ProviderNative Gates
IbmEagleCX, RZ, SX, X
IbmKyotoECR, RZ, SX, X
RigettiCZ, RX, RZ
IonQGPI, GPI2, MS
QuantinuumRZ, RX, ZZ
SimulatorAll gates

Combine with: lift-opt::LayoutMapping (transpilation to target hardware).

5.3 Device Topology — Hardware Topology

#![allow(unused)]
fn main() {
use lift_quantum::topology::DeviceTopology;

// Predefined topologies
let linear = DeviceTopology::linear(10);         // Linear chain
let grid = DeviceTopology::grid(3, 3);           // 3x3 grid
let hex = DeviceTopology::heavy_hex(27);         // Heavy-hex IBM
let ion = DeviceTopology::all_to_all(32);        // All-to-all (trapped ions)
let tree = DeviceTopology::tree(15);             // Binary tree

// Custom topology
let custom = DeviceTopology::custom("my_chip",
    &[(0,1), (1,2), (2,3), (0,3)], 0.99);

// Querying
linear.are_connected(0, 1);           // true
linear.shortest_path(0, 4);           // Some([0, 1, 2, 3, 4])
linear.swap_distance(0, 4);           // Some(3)
linear.avg_connectivity();             // average connectivity
linear.diameter();                     // graph diameter
grid.neighbors(4);                     // neighbours of qubit 4
}

Combine with: lift-opt::LayoutMapping, lift-opt::NoiseAwareSchedule.

5.4 Noise Models

#![allow(unused)]
fn main() {
use lift_quantum::noise::{NoiseModel, GateNoise, CircuitNoise};

// Noise models
let ideal = NoiseModel::Ideal;
let depol = NoiseModel::Depolarizing { p: 0.01 };
let bitflip = NoiseModel::BitFlip { p: 0.001 };
let phaseflip = NoiseModel::PhaseFlip { p: 0.001 };

// Model fidelity
let fidelity = depol.fidelity(); // 0.99

// Per-gate noise
let gate_noise = GateNoise::with_depolarizing(0.999, 0.02);

// Full circuit analysis
let mut cn = CircuitNoise::new();
// ... noise accumulation
println!("Total fidelity: {}", cn.total_fidelity);
println!("2-qubit gates: {}", cn.two_qubit_count);
}

5.5 Kraus Channels — Quantum Noise Channels

#![allow(unused)]
fn main() {
use lift_quantum::kraus::{ComplexMatrix, KrausChannel};

// Predefined noise channels
let depol = KrausChannel::depolarizing(0.01, 1);     // 1-qubit depolarising
let amp = KrausChannel::amplitude_damping(0.02);      // Amplitude damping
let phase = KrausChannel::phase_damping(0.01);         // Phase damping

// Channel fidelity
let fidelity = depol.average_gate_fidelity();
println!("Fidelity: {:.6}", fidelity);

// Complex matrices
let mut m = ComplexMatrix::identity(2);
let dagger = m.dagger();    // Conjugate transpose
let product = m.mul(&dagger).unwrap();
let trace = m.trace().unwrap();
}

Combine with: lift-sim::QuantumCostModel (circuit fidelity estimation), lift-opt::NoiseAwareSchedule.

5.6 QEC — Quantum Error Correction

#![allow(unused)]
fn main() {
use lift_quantum::qec::{QecCode, QecAnalysis};

// Available QEC codes
let surface = QecCode::SurfaceCode { distance: 5 };   // 25 physical qubits/logical
let steane = QecCode::SteaneCode;                       // 7 physical qubits/logical
let shor = QecCode::ShorCode;                            // 9 physical qubits/logical
let rep = QecCode::RepetitionCode { distance: 7 };     // 7 physical qubits
let ldpc = QecCode::LdpcCode { n: 100, k: 10 };       // LDPC code

// Code properties
println!("Physical/logical: {}", surface.physical_per_logical()); // 25
println!("Distance: {}", surface.code_distance());                 // 5
println!("Syndrome depth: {}", surface.syndrome_circuit_depth()); // 5

// Full QEC analysis
let analysis = QecAnalysis::analyse(
    10,     // logical qubits
    100,    // circuit depth
    QecCode::SurfaceCode { distance: 5 },
    0.001,  // physical error rate
);
println!("Physical qubits: {}", analysis.physical_qubits);
println!("Logical error rate: {:.2e}", analysis.logical_error_rate);
println!("Overhead: {}", analysis.overhead_qubits);
}

Combine with: lift-sim::QuantumCostModel, lift-predict (fidelity budget).


6. lift-hybrid — Classical-Quantum Hybrid Computation

6.1 Hybrid Operations (21 ops)

6.1.1 Encoding/Decoding (2 ops)

#OpIR NameDescription
1Encodehybrid.encodeEncode classical data → qubits
2Decodehybrid.decodeDecode quantum measurements → classical

6.1.2 Gradient Methods (6 ops)

#OpIR NameEvaluationsExact?
3ParameterShifthybrid.parameter_shift2NYes
4FiniteDifferencehybrid.finite_differenceN+1No
5SPSAhybrid.spsa2No
6AdjointDifferentiationhybrid.adjoint_diff1Yes
7StochasticParameterShifthybrid.stochastic_param_shift2No
8JointGradienthybrid.joint_gradientCombined
#![allow(unused)]
fn main() {
use lift_hybrid::gradient::GradientMethod;

let method = GradientMethod::ParameterShift;
let evals = method.circuit_evaluations(100); // 200 evaluations for 100 params
assert!(method.is_exact()); // true
}

6.1.3 Processing (4 ops)

#OpDescription
9ClassicalPreprocessClassical preprocessing
10QuantumPostprocessQuantum postprocessing
11HybridForwardHybrid forward pass
12HybridBackwardHybrid backward pass

6.1.4 Variational Algorithms (4 ops)

#OpDescriptionUsage
13VqcLayerVariational circuit layerQuantum classification
14VqeAnsatzVQE ansatzQuantum chemistry
15QaoaLayerQAOA layerCombinatorial optimisation
16QuantumKernelQuantum kernelQuantum machine learning

6.1.5 Data Transfer (2 ops)

#OpDescription
17GpuToQpuGPU → QPU transfer
18QpuToGpuQPU → GPU transfer

6.1.6 Co-Execution and Measurement (3 ops)

#OpDescription
19CoExecuteSimultaneous classical+quantum execution
20MeasureExpectationObservable expectation value
21MeasureSamplesMeasurement sampling
#![allow(unused)]
fn main() {
use lift_hybrid::ops::HybridOp;

let op = HybridOp::VqcLayer;
assert!(op.is_variational());
assert!(!op.is_gradient());
}

6.2 Encoding Strategies

#![allow(unused)]
fn main() {
use lift_hybrid::encoding::{EncodingStrategy, EncodingConfig};

let strategies = [
    EncodingStrategy::AngleEncoding,       // 1 qubit/feature, depth 1
    EncodingStrategy::AmplitudeEncoding,    // log2(n) qubits, depth n
    EncodingStrategy::BasisEncoding,        // 1 qubit/feature, depth 1
    EncodingStrategy::IQPEncoding,          // 1 qubit/feature, depth 2n
    EncodingStrategy::HamiltonianEncoding,  // 1 qubit/feature, depth n
    EncodingStrategy::KernelEncoding,       // 1 qubit/feature, depth 3n
];

// Encoding configuration
let config = EncodingConfig::new(EncodingStrategy::AmplitudeEncoding, 256);
println!("Qubits required: {}", config.num_qubits); // 8 = log2(256)
println!("Classical dimension: {}", config.classical_dim); // 256
}
StrategyQubitsDepthBest for
Anglen1Few features
Amplitudelog₂(n)nMany features
Basisn1Binary data
IQPn2nQuantum advantage
HamiltoniannnPhysical simulation
Kerneln3nQuantum ML

6.3 Gradient Configuration — Joint Gradient Setup

#![allow(unused)]
fn main() {
use lift_hybrid::gradient::{GradientMethod, JointGradientConfig};

let config = JointGradientConfig {
    classical_method: GradientMethod::Backprop,
    quantum_method: GradientMethod::ParameterShift,
    num_classical_params: 1000,
    num_quantum_params: 50,
};
println!("Total evaluations: {}", config.total_evaluations());
// 1 (backprop) + 100 (2*50 parameter shift) = 101
}

6.4 Auxiliary Types

#![allow(unused)]
fn main() {
use lift_hybrid::ops::{AnsatzType, SyncPolicy, FeatureMap};

// Ansatz types for VQC
let ansatz = AnsatzType::HardwareEfficient; // HardwareEfficient, StronglyEntangling, TwoLocal, UCCSD, Custom

// Synchronisation policy
let sync = SyncPolicy::Blocking; // Blocking, Asynchronous, Pipeline

// Feature maps for quantum kernels
let fm = FeatureMap::ZZFeatureMap; // ZZFeatureMap, PauliFeatureMap, AngleEncoding, AmplitudeEncoding
}

7. lift-opt — Optimisation Passes (13 passes)

7.1 Classical Passes (5 passes)

7.1.1 Canonicalize — Canonical Form

#![allow(unused)]
fn main() {
use lift_opt::Canonicalize;
use lift_core::pass::Pass;

let pass = Canonicalize;
// Reorders operations into canonical form
// Normalises IR patterns to facilitate subsequent optimisations
}

Usage: Always run first in the pipeline.

7.1.2 ConstantFolding — Constant Folding

#![allow(unused)]
fn main() {
use lift_opt::ConstantFolding;

let pass = ConstantFolding;
// Evaluates operations whose operands are all compile-time constants
// Example: add(const(2), const(3)) → const(5)
}

7.1.3 DeadCodeElimination — Dead Code Elimination

#![allow(unused)]
fn main() {
use lift_opt::DeadCodeElimination;

let pass = DeadCodeElimination;
// Removes operations whose results are never used
// Respects operations with side effects (measurements, etc.)
}

7.1.4 TensorFusion — Tensor Fusion

#![allow(unused)]
fn main() {
use lift_opt::TensorFusion;

let pass = TensorFusion;
// Fuses consecutive operations into fused operations
// Example: MatMul + Bias + ReLU → FusedMatMulBiasReLU
// Reduces memory accesses and kernel launches
}

Combine with: Run after Canonicalize and ConstantFolding.

7.1.5 CommonSubexprElimination — Common Subexpression Elimination

#![allow(unused)]
fn main() {
use lift_opt::CommonSubexprElimination;

let pass = CommonSubexprElimination;
// Detects identical operations (same op, same operands)
// Replaces duplicates with references to the first occurrence
// Excludes operations with side effects
}

7.2 Quantum Passes (3 passes)

7.2.1 GateCancellation — Gate Cancellation

#![allow(unused)]
fn main() {
use lift_opt::GateCancellation;

let pass = GateCancellation;
// Removes gate pairs that cancel out
// Example: H H → identity, X X → identity
// Respects qubit linearity invariants
}

7.2.2 RotationMerge — Rotation Merging

#![allow(unused)]
fn main() {
use lift_opt::RotationMerge;

let pass = RotationMerge;
// Merges consecutive rotations on the same axis
// Example: RZ(0.3) RZ(0.5) → RZ(0.8)
// Removes identity rotations (angle ≈ 0)
}

7.2.3 NoiseAwareSchedule — Noise-Aware Scheduling

#![allow(unused)]
fn main() {
use lift_opt::NoiseAwareSchedule;

let pass = NoiseAwareSchedule;
// Reorders quantum gates to minimise decoherence
// Prioritises fast gates (1-qubit) before slow ones (2-qubit)
// Respects SSA dependencies
}

Combine with: lift-quantum::topology::DeviceTopology for the target topology.

7.3 Advanced AI Passes (3 passes)

7.3.1 FlashAttentionPass — FlashAttention Replacement

#![allow(unused)]
fn main() {
use lift_opt::FlashAttentionPass;

let pass = FlashAttentionPass::default(); // threshold = 512
let pass_custom = FlashAttentionPass { seq_len_threshold: 1024 };
// Replaces tensor.attention with tensor.flash_attention
// when sequence length exceeds the threshold
// Reduces memory complexity from O(N²) to O(N)
}

7.3.2 QuantisationPass — Quantisation Annotation

#![allow(unused)]
fn main() {
use lift_opt::QuantisationPass;
use lift_opt::quantisation_pass::{QuantTarget, QuantMode};

let pass = QuantisationPass::default(); // INT8, Dynamic
let pass_custom = QuantisationPass {
    target_dtype: QuantTarget::Fp8E4M3,
    mode: QuantMode::Static,
};
// Annotates heavy operations (MatMul, Conv, Linear, Attention)
// with quantisation metadata
// Inserts Quantize/Dequantize pairs around annotated ops
}
TargetSizeUsage
Int81 byteStandard inference
Int40.5 byteCompressed LLMs (GPTQ, AWQ)
Fp8E4M31 byteH100 training
Fp8E5M21 byteH100 inference

7.3.3 LayoutMapping — Qubit Mapping

#![allow(unused)]
fn main() {
use lift_opt::LayoutMapping;

let pass = LayoutMapping;
// Inserts SWAP gates to map logical qubits to physical qubits
// Based on the target device topology
// Marks operations requiring swaps via attributes
}

Combine with: lift-quantum::topology::DeviceTopology.

7.3.4 GateDecomposition — Hardware-Native Gate Sets

#![allow(unused)]
fn main() {
use lift_opt::gate_decompose::GateDecomposition;
use lift_quantum::dialect::Provider;

let pass = GateDecomposition::new(Some(Provider::Ibm));
// Lowers high-level gates to hardware-native gate sets:
//   H     → RZ(π/2) SX RZ(π/2)
//   T/Tdg → RZ(±π/4)
//   S/Sdg → RZ(±π/2)
//   Y     → RZ(π/2) X RZ(-π/2)
//   RX(θ) → RZ(-π/2) SX RZ(π+θ) SX RZ(π/2)
// Provider is read from QuantumConfig (provider = ibm|rigetti|ionq|quantinuum|simulator)
// Uses Context::insert_op_before to preserve SSA dominance
}

Combine with: lift-config [quantum] provider key.

7.3.5 RealRouting — SWAP-Based Qubit Routing

#![allow(unused)]
fn main() {
use lift_opt::real_routing::RealRouting;
use lift_quantum::topology::DeviceTopology;

let pass = RealRouting::new(DeviceTopology::linear(8));
// Inserts actual quantum.swap operations so every 2-qubit gate
// only acts on physically connected qubits.
// Strategy: identity initial placement, BFS shortest-path routing,
// logical↔physical placement maps updated after every swap.
}

Combine with: lift-config [quantum] topology / num_qubits keys.

7.4 Optimisation Levels (O0-O3)

lift-config provides preset pipelines so you don't have to enumerate passes by hand:

LevelPasses
O0none
O1canonicalize, constant-folding, dce
O2O1 + cse, tensor-fusion
O3all 13 passes (incl. gate-decomposition, real-routing)
[optimisation]
level = "O3"                  # preset pipeline
passes = []                   # (optional) explicit overrides the level
disabled_passes = ["cse"]     # (optional) remove specific passes
max_iterations = 5

Explicit passes take priority over level; unknown pass names are reported by OptimisationConfig::validate().

#![allow(unused)]
fn main() {
use lift_core::PassManager;

let mut pm = PassManager::new();

// Phase 1: Cleanup
pm.add_pass(Box::new(lift_opt::Canonicalize));
pm.add_pass(Box::new(lift_opt::ConstantFolding));
pm.add_pass(Box::new(lift_opt::DeadCodeElimination));
pm.add_pass(Box::new(lift_opt::CommonSubexprElimination));

// Phase 2: Fusion (AI)
pm.add_pass(Box::new(lift_opt::TensorFusion));
pm.add_pass(Box::new(lift_opt::FlashAttentionPass::default()));
pm.add_pass(Box::new(lift_opt::QuantisationPass::default()));

// Phase 3: Quantum
pm.add_pass(Box::new(lift_opt::GateCancellation));
pm.add_pass(Box::new(lift_opt::RotationMerge));
pm.add_pass(Box::new(lift_opt::NoiseAwareSchedule));
pm.add_pass(Box::new(lift_opt::LayoutMapping));

// Phase 3b: Hardware targeting
pm.add_pass(Box::new(lift_opt::gate_decompose::GateDecomposition::new(Some(Provider::Ibm))));
pm.add_pass(Box::new(lift_opt::real_routing::RealRouting::new(DeviceTopology::linear(8))));

// Phase 4: Final cleanup
pm.add_pass(Box::new(lift_opt::DeadCodeElimination));

let results = pm.run_all(&mut ctx);
}

8. lift-sim — Simulation and Cost Analysis

8.1 CostModel — Classical Cost Model

#![allow(unused)]
fn main() {
use lift_sim::cost::CostModel;

// Predefined GPU profiles
let a100 = CostModel::a100();  // 312 TFLOPS, 2039 GB/s
let h100 = CostModel::h100();  // 989 TFLOPS, 3350 GB/s

// Time estimation
let flops = 2 * 1024 * 1024 * 1024_u64;
let bytes = 4 * 1024 * 1024_u64;

let compute_ms = a100.compute_time_ms(flops);      // Compute time
let memory_ms = a100.memory_time_ms(bytes);         // Memory time
let roofline_ms = a100.roofline_time_ms(flops, bytes); // Roofline model

// Analysis
let ai = a100.arithmetic_intensity(flops, bytes);   // FLOPs/byte
let bound = a100.is_compute_bound(flops, bytes);    // true = compute-bound
let fits = a100.fits_in_memory(bytes);               // Fits in memory?
let gpus = a100.num_gpus_needed(bytes);              // GPUs needed
}

8.2 QuantumCostModel — Quantum Cost Model

#![allow(unused)]
fn main() {
use lift_sim::cost::QuantumCostModel;

// Quantum processor profiles
let sc = QuantumCostModel::superconducting_default(); // IBM-like: 127 qubits
let ion = QuantumCostModel::trapped_ion_default();     // IonQ-like: 32 qubits
let atom = QuantumCostModel::neutral_atom_default();   // Atom-like: 256 qubits

// Circuit fidelity estimation
let fidelity = sc.circuit_fidelity(50, 20); // 50 1Q gates, 20 2Q gates
println!("Fidelity: {:.6}", fidelity);

// Circuit time
let time_us = sc.circuit_time_us(50, 20, 5, 10); // 50 1Q, 20 2Q, 5 measurements, 10 depth
println!("Time: {:.2} µs", time_us);

// Decoherence fidelity
let decoherence = sc.decoherence_fidelity(time_us);
println!("Decoherence fidelity: {:.6}", decoherence);
}
ParameterSuperconductingTrapped IonsNeutral Atoms
1Q time0.02 µs10 µs0.5 µs
2Q time0.3 µs200 µs1.0 µs
1Q fidelity99.9%99.99%99.9%
2Q fidelity99%99.9%99.5%
T1100 µs1 s5 ms
Qubits12732256

8.3 Budget — Resource Constraints

#![allow(unused)]
fn main() {
use lift_sim::cost::Budget;

let budget = Budget {
    max_flops: Some(1_000_000_000_000), // 1 TFLOP max
    max_memory_bytes: Some(80_000_000_000), // 80 GB
    max_time_ms: Some(100.0),           // 100 ms
    min_fidelity: Some(0.99),           // 99% min fidelity
    max_circuit_depth: Some(1000),      // 1000 layers max
};

budget.check_flops(500_000_000_000).unwrap();   // OK
budget.check_memory(40_000_000_000).unwrap();   // OK
budget.check_fidelity(0.995).unwrap();           // OK
}

8.4 EnergyModel — Energy and Carbon Estimation

#![allow(unused)]
fn main() {
use lift_sim::cost::EnergyModel;

let model = EnergyModel::a100();

// Energy for 1 second of computation on 4 GPUs
let joules = model.energy_joules(1000.0, 4);     // Joules
let kwh = model.energy_kwh(1000.0, 4);           // kWh
let carbon = model.carbon_grams(1000.0, 4);       // grams CO₂

println!("Energy: {:.2} J", joules);
println!("Carbon: {:.4} g CO₂", carbon);

// Quantum energy (cryogenic refrigeration)
let q_joules = model.quantum_energy_joules(100.0, 127); // 100 µs, 127 qubits
}

8.5 ReactiveBudget — Dynamic Budget

#![allow(unused)]
fn main() {
use lift_sim::cost::{Budget, ReactiveBudget};

let budget = Budget {
    max_flops: Some(1_000_000),
    max_memory_bytes: Some(1_000_000),
    max_time_ms: Some(50.0),
    min_fidelity: Some(0.9),
    max_circuit_depth: None,
};
let mut rb = ReactiveBudget::new(budget);

// Consume resources incrementally
rb.consume(100_000, 50_000, 5.0, 0.99); // flops, mem, time, fidelity
rb.consume(200_000, 80_000, 10.0, 0.98);

// Check remaining budget
rb.check_remaining().unwrap(); // OK if within limits

// Utilisation report
let util = rb.utilisation();
println!("FLOPs used: {:.1}%", util.flop_ratio.unwrap() * 100.0);
println!("Time used: {:.1}%", util.time_ratio.unwrap() * 100.0);

// Remaining budget
println!("Remaining FLOPs: {:?}", rb.remaining_flops());
println!("Remaining time: {:?} ms", rb.remaining_time_ms());
}

Combine with: lift-opt (stop optimisation if budget exhausted), lift-predict (verify prediction respects budget).

8.6 Module Analysis

#![allow(unused)]
fn main() {
use lift_sim::{analyze_module, analyze_quantum_ops};

let ctx = load_and_parse("model.lif").unwrap();

// Classical analysis
let report = analyze_module(&ctx);
println!("Total ops: {}", report.num_ops);
println!("Tensor ops: {}", report.num_tensor_ops);
println!("Quantum ops: {}", report.num_quantum_ops);
println!("Hybrid ops: {}", report.num_hybrid_ops);
println!("Total FLOPs: {}", report.total_flops);
println!("Total memory: {} bytes", report.total_memory_bytes);
println!("Peak memory: {} bytes", report.peak_memory_bytes);

// Quantum analysis
let quantum = analyze_quantum_ops(&ctx);
println!("Qubits: {}", quantum.num_qubits_used);
println!("Gates: {}", quantum.gate_count);
println!("1Q gates: {}", quantum.one_qubit_gates);
println!("2Q gates: {}", quantum.two_qubit_gates);
println!("Measurements: {}", quantum.measurements);
println!("Estimated fidelity: {:.6}", quantum.estimated_fidelity);
}

9. lift-predict — Performance Prediction

#![allow(unused)]
fn main() {
use lift_predict::predict_performance;
use lift_sim::{analyze_module, cost::CostModel};

let report = analyze_module(&ctx);
let cost_model = CostModel::h100();
let prediction = predict_performance(&report, &cost_model);

println!("Compute time: {:.4} ms", prediction.compute_time_ms);
println!("Memory time: {:.4} ms", prediction.memory_time_ms);
println!("Predicted time: {:.4} ms", prediction.predicted_time_ms);
println!("Arithmetic intensity: {:.2} FLOP/byte", prediction.arithmetic_intensity);
println!("Bottleneck: {}", prediction.bottleneck); // "compute" or "memory"
}

Combine with: lift-sim (provides the analysis report and cost model).


10. lift-import — Model Import

10.1 ONNX Import

#![allow(unused)]
fn main() {
use lift_import::OnnxImporter;

let importer = OnnxImporter::new();
let ctx = importer.import("model.onnx").expect("ONNX import failed");
}

10.2 PyTorch FX Import

#![allow(unused)]
fn main() {
use lift_import::PyTorchFxImporter;

let importer = PyTorchFxImporter::new();
let ctx = importer.import("model_fx.json").expect("FX import failed");
}

10.3 OpenQASM 3.0 Import

#![allow(unused)]
fn main() {
use lift_import::OpenQasm3Importer;

let importer = OpenQasm3Importer::new();
let ctx = importer.import("circuit.qasm").expect("QASM import failed");
}

Combine with: lift-core::verifier (verify imported IR), then lift-opt (optimise).


11. lift-export — Backend Export (LLVM, ONNX, QASM)

11.1 Export LLVM IR

#![allow(unused)]
fn main() {
use lift_export::LlvmExporter;

let exporter = LlvmExporter::new();
let llvm_ir = exporter.export(&ctx).expect("LLVM export failed");
std::fs::write("output.ll", &llvm_ir).unwrap();
}

Produces LLVM IR with runtime function calls for tensor operations (cuBLAS/cuDNN backend).

11.2 Export ONNX

#![allow(unused)]
fn main() {
use lift_export::OnnxExporter;

let exporter = OnnxExporter::new();
let onnx_text = exporter.export(&ctx).expect("ONNX export failed");
std::fs::write("output.onnx", &onnx_text).unwrap();

// Also available: JSON format
let onnx_json = exporter.export_json(&ctx).expect("ONNX JSON export failed");
std::fs::write("output_onnx.json", &onnx_json).unwrap();
}

Produces ONNX protobuf text format at opset version 21, IR version 9. Compatible with:

  • PyTorch, TensorFlow, TensorRT, ONNX Runtime
  • Microsoft extension ops for attention and MoE

ONNX op mapping (70+ operations):

LIFT OperationONNX OpDomain
tensor.matmulMatMulstandard
tensor.linearGemmstandard
tensor.add / sub / mul / divAdd / Sub / Mul / Divstandard
tensor.reluRelustandard
tensor.geluGelustandard
tensor.siluSigmoid + Mulstandard
tensor.softmaxSoftmaxstandard
tensor.layernormLayerNormalizationstandard
tensor.rmsnormSimplifiedLayerNormalizationcom.microsoft
tensor.batchnormBatchNormalizationstandard
tensor.conv2dConvstandard
tensor.maxpool2dMaxPoolstandard
tensor.avgpool2dAveragePoolstandard
tensor.attentionAttentioncom.microsoft
tensor.grouped_query_attentionGroupQueryAttentioncom.microsoft
tensor.flash_attentionMultiHeadAttentioncom.microsoft
tensor.quantizeQuantizeLinearstandard
tensor.dequantizeDequantizeLinearstandard
tensor.moe_dispatchMoEcom.microsoft
tensor.reshapeReshapestandard
tensor.transposeTransposestandard
tensor.concatConcatstandard
tensor.gatherGatherstandard
tensor.squeeze / unsqueezeSqueeze / Unsqueezestandard
tensor.clip / clampClipstandard
tensor.topkTopKstandard
tensor.whereWherestandard
tensor.cumsumCumSumstandard
tensor.constantConstantstandard
tensor.zeros / onesConstantOfShapestandard
tensor.einsumEinsumstandard
tensor.fft / ifftDFT / IDFTstandard
tensor.sparse_matmulMatMul (sparse)standard
tensor.fused_matmul_bias_reluFusedMatMulBiasRelucom.microsoft
tensor.fused_matmul_biasFusedMatMulBiascom.microsoft
tensor.fused_linear_geluFusedGemmcom.microsoft
tensor.fused_linear_siluFusedGemmcom.microsoft
tensor.fused_conv_batchnorm_reluFusedConvBatchNormRelucom.microsoft
tensor.fused_attention_layernormFusedAttentioncom.microsoft

Data type mapping:

LIFT DataTypeONNX ElemType
FP321 (FLOAT)
FP6411 (DOUBLE)
FP1610 (FLOAT16)
BF1616 (BFLOAT16)
INT83 (INT8)
INT326 (INT32)
INT647 (INT64)
BOOL9 (BOOL)

11.3 Export OpenQASM 3.0

#![allow(unused)]
fn main() {
use lift_export::QasmExporter;

let exporter = QasmExporter::new();
let qasm = exporter.export(&ctx).expect("QASM export failed");
std::fs::write("output.qasm", &qasm).unwrap();
}

Produces OpenQASM 3.0 executable on IBM Quantum, Rigetti, IonQ, Quantinuum.

Combine with: lift-opt (optimise before export), lift-quantum::Provider (transpile to native gate set).


12. lift-config — Configuration (.lith)

12.1 .lith File Format

[target]
backend = "cuda"
device = "A100"
precision = "fp16"

[budget]
max_flops = 1000000000000
max_memory_bytes = 80000000000
max_time_ms = 100.0
min_fidelity = 0.99

[optimisation]
level = O2
max_iterations = 10

[simulation]
shape_propagation = true
flop_counting = true
memory_analysis = true
noise_simulation = true

[quantum]
topology = "heavy_hex"
num_qubits = 127
shots = 4096

12.2 Programmatic Loading

#![allow(unused)]
fn main() {
use lift_config::{ConfigParser, LithConfig};

// From a file
let source = std::fs::read_to_string("config.lith").unwrap();
let config = ConfigParser::new().parse(&source).unwrap();

// Default configuration
let default = LithConfig::default();
// Backend: llvm, Level: O2, Passes: canonicalize, constant-folding, dce, tensor-fusion

// With quantum
let hybrid = LithConfig::default().with_quantum("heavy_hex", 127);
}

12.3 Optimisation Levels

LevelPassesUsage
O0NoneDebug, verification
O1Canonicalize, DCEFast compilation
O2+ ConstantFolding, TensorFusionDefault — good trade-off
O3+ FlashAttention, Quantisation, CSEMaximum performance

13. lift-cli — Command-Line Interface

13.1 Available Commands

13.1.1 lift verify — Verify a .lif file

lift verify model.lif
lift verify --verbose model.lif

Checks SSA invariants, qubit linearity, and typing.

13.1.2 lift analyse — Analyse a program

lift analyse model.lif
lift analyse model.lif --format json

Produces a report: op count, FLOPs, memory, quantum analysis.

13.1.3 lift print — Display the IR

lift print model.lif

Displays the IR in human-readable format.

13.1.4 lift optimise — Optimise

lift optimise model.lif
lift optimise model.lif --config config.lith --output optimised.lif

Applies the configured optimisation passes.

13.1.5 lift predict — Predict performance

lift predict model.lif --device a100
lift predict model.lif --device h100

Predicts execution time using the roofline model.

13.1.6 lift export — Export

lift export model.lif --backend llvm --output model.ll
lift export model.lif --backend onnx --output model.onnx
lift export quantum.lif --backend qasm --output circuit.qasm

Exports to LLVM IR, ONNX (opset 21), or OpenQASM 3.0.


14. lift-codegen — Programmatic Model Generation

The lift-codegen binary lets you define models directly from Rust code and automatically generate all export formats.

14.1 Running the Code Generator

cargo run --bin lift-codegen

This generates into examples/:

  • 4 .lif models — Phi-3-mini, MLP, ResNet block, VQE circuit
  • 4 .ll files — LLVM IR exports
  • 4 .onnx files — ONNX exports
  • 1 .qasm file — OpenQASM export (for quantum models only)
  • 1 .lith config — H100 optimization configuration

Each model is automatically verified, analysed, optimised, and exported.

14.2 ModelBuilder API

#![allow(unused)]
fn main() {
use lift_core::model_builder::{ModelBuilder, tensor, tensor_2d, DataType};

let model = ModelBuilder::new("my_model")
    .function("forward")
        .param("x", tensor(&[1, 784], DataType::FP32))
        .param("w", tensor_2d(784, 256, DataType::FP32))
        .op("tensor.matmul", &["x", "w"], "h", tensor(&[1, 256], DataType::FP32))
        .op("tensor.relu", &["h"], "out", tensor(&[1, 256], DataType::FP32))
        .returns("out")
        .done();

// Write .lif source file
model.write_lif("my_model.lif").unwrap();

// Build IR context for verification/analysis/export
let ctx = model.build_context();
lift_core::verifier::verify(&ctx).unwrap();
}

14.3 Multi-Target Export from Code

#![allow(unused)]
fn main() {
let ctx = model.build_context();

// Optimise first
let mut pm = PassManager::new();
pm.add_pass(Box::new(lift_opt::Canonicalize));
pm.add_pass(Box::new(lift_opt::ConstantFolding));
pm.add_pass(Box::new(lift_opt::DeadCodeElimination));
pm.add_pass(Box::new(lift_opt::TensorFusion));
pm.run_all(&mut ctx);

// Export to all 3 backends
let llvm_ir = lift_export::LlvmExporter::new().export(&ctx).unwrap();
let onnx_ir = lift_export::OnnxExporter::new().export(&ctx).unwrap();
std::fs::write("my_model.ll", &llvm_ir).unwrap();
std::fs::write("my_model.onnx", &onnx_ir).unwrap();

// Export QASM only if quantum ops present
if ctx.ops.iter().any(|(_, op)| ctx.strings.resolve(op.name).starts_with("quantum.")) {
    let qasm_ir = lift_export::QasmExporter::new().export(&ctx).unwrap();
    std::fs::write("my_model.qasm", &qasm_ir).unwrap();
}
}

Combine with: All other crates. ModelBuilder is the programmatic entry point for defining models without .lif files.


15. Combinations and Complete Pipelines

15.1 Complete AI Pipeline (Transformer)

#![allow(unused)]
fn main() {
// 1. Import an ONNX model
let ctx = OnnxImporter::new().import("bert.onnx")?;

// 2. Verify
verifier::verify(&ctx)?;

// 3. Analyse
let report = analyze_module(&ctx);

// 4. Optimise
let mut pm = PassManager::new();
pm.add_pass(Box::new(Canonicalize));
pm.add_pass(Box::new(ConstantFolding));
pm.add_pass(Box::new(DeadCodeElimination));
pm.add_pass(Box::new(CommonSubexprElimination));
pm.add_pass(Box::new(TensorFusion));
pm.add_pass(Box::new(FlashAttentionPass { seq_len_threshold: 512 }));
pm.add_pass(Box::new(QuantisationPass {
    target_dtype: QuantTarget::Int8,
    mode: QuantMode::Dynamic,
}));
pm.add_pass(Box::new(DeadCodeElimination));
pm.run_all(&mut ctx);

// 5. Predict performance
let h100 = CostModel::h100();
let pred = predict_performance(&analyze_module(&ctx), &h100);

// 6. Export to LLVM and ONNX
let llvm = LlvmExporter::new().export(&ctx)?;
let onnx = OnnxExporter::new().export(&ctx)?;
std::fs::write("bert_optimised.ll", llvm)?;
std::fs::write("bert_optimised.onnx", onnx)?;
}

15.2 Complete Quantum Pipeline (Bell State)

#![allow(unused)]
fn main() {
// 1. Parse the circuit
let ctx = load_lif_file("quantum_bell.lif")?;

// 2. Analyse noise
let quantum = analyze_quantum_ops(&ctx);
let sc = QuantumCostModel::superconducting_default();
let fidelity = sc.circuit_fidelity(
    quantum.one_qubit_gates, quantum.two_qubit_gates
);

// 3. QEC if needed
if fidelity < 0.99 {
    let analysis = QecAnalysis::analyse(2, 5,
        QecCode::SurfaceCode { distance: 3 }, 0.001);
    println!("Physical qubits needed: {}", analysis.physical_qubits);
}

// 4. Optimise
let mut pm = PassManager::new();
pm.add_pass(Box::new(GateCancellation));
pm.add_pass(Box::new(RotationMerge));
pm.add_pass(Box::new(NoiseAwareSchedule));
pm.add_pass(Box::new(LayoutMapping));
pm.run_all(&mut ctx);

// 5. Export to QASM
let qasm = QasmExporter::new().export(&ctx)?;
std::fs::write("bell_optimised.qasm", qasm)?;
}

15.3 Complete Hybrid Pipeline (VQE)

#![allow(unused)]
fn main() {
// 1. Configure encoding
let encoding = EncodingConfig::new(EncodingStrategy::AngleEncoding, 4);

// 2. Configure gradient
let grad_config = JointGradientConfig {
    classical_method: GradientMethod::Backprop,
    quantum_method: GradientMethod::ParameterShift,
    num_classical_params: 100,
    num_quantum_params: 20,
};

// 3. Reactive budget to control resources
let budget = Budget {
    max_flops: Some(1_000_000_000),
    max_memory_bytes: Some(8_000_000_000),
    max_time_ms: Some(60_000.0),
    min_fidelity: Some(0.95),
    max_circuit_depth: Some(500),
};
let mut rb = ReactiveBudget::new(budget);

// 4. VQE optimisation loop
for iteration in 0..100 {
    // Execute the quantum circuit
    rb.consume(10_000, 1_000, 0.5, 0.999);
    
    if rb.check_remaining().is_err() {
        println!("Budget exhausted at iteration {}", iteration);
        break;
    }
    
    let util = rb.utilisation();
    println!("Iteration {}: FLOP {:.1}%, Time {:.1}%",
        iteration,
        util.flop_ratio.unwrap() * 100.0,
        util.time_ratio.unwrap() * 100.0
    );
}

// 5. Estimate carbon footprint
let energy = EnergyModel::a100();
let carbon = energy.carbon_grams(rb.elapsed_ms, 1);
println!("Carbon footprint: {:.4} g CO₂", carbon);
}

15.4 Complete CLI Pipeline

# Verify, analyse, optimise, predict and export in one sequence
lift verify model.lif
lift analyse model.lif --format json > analysis.json
lift optimise model.lif --config production.lith --output optimised.lif
lift predict optimised.lif --device h100
lift export optimised.lif --backend llvm --output model.ll
lift export optimised.lif --backend onnx --output model.onnx

16. Concrete Examples

16.1 MLP (Multi-Layer Perceptron)

File tensor_mlp.lif:

#dialect tensor

module @mlp {
    func @forward(%x: tensor<1x784xf32>, %w1: tensor<784x256xf32>,
                  %b1: tensor<256xf32>, %w2: tensor<256x10xf32>,
                  %b2: tensor<10xf32>) -> tensor<1x10xf32> {
        %h1 = "tensor.matmul"(%x, %w1) : (tensor<1x784xf32>, tensor<784x256xf32>) -> tensor<1x256xf32>
        %h2 = "tensor.add"(%h1, %b1) : (tensor<1x256xf32>, tensor<256xf32>) -> tensor<1x256xf32>
        %h3 = "tensor.relu"(%h2) : (tensor<1x256xf32>) -> tensor<1x256xf32>
        %h4 = "tensor.matmul"(%h3, %w2) : (tensor<1x256xf32>, tensor<256x10xf32>) -> tensor<1x10xf32>
        %h5 = "tensor.add"(%h4, %b2) : (tensor<1x10xf32>, tensor<10xf32>) -> tensor<1x10xf32>
        %out = "tensor.softmax"(%h5) : (tensor<1x10xf32>) -> tensor<1x10xf32>
        return %out
    }
}

16.2 Self-Attention (Transformer)

File attention.lif:

#dialect tensor

module @transformer {
    func @self_attention(%q: tensor<1x128x64xf32>, %k: tensor<1x128x64xf32>,
                         %v: tensor<1x128x64xf32>, %norm_w: tensor<64xf32>)
                         -> tensor<1x128x64xf32> {
        %attn = "tensor.attention"(%q, %k, %v) : (...) -> tensor<1x128x64xf32>
        %normed = "tensor.layernorm"(%attn, %norm_w) : (...) -> tensor<1x128x64xf32>
        return %normed
    }
}

16.3 Bell State (Quantum)

File quantum_bell.lif:

#dialect quantum

module @bell_state {
    func @bell(%q0: qubit, %q1: qubit) -> (qubit, qubit) {
        %q2 = "quantum.h"(%q0) : (qubit) -> qubit
        %q3, %q4 = "quantum.cx"(%q2, %q1) : (qubit, qubit) -> (qubit, qubit)
        return %q3, %q4
    }
}

16.4 Production Configuration

File production.lith:

[target]
backend = "cuda"
device = "H100"
precision = "fp16"

[budget]
max_flops = 1000000000000
max_memory_bytes = 80000000000
max_time_ms = 100.0

[optimisation]
level = O3
max_iterations = 20

[simulation]
shape_propagation = true
flop_counting = true
memory_analysis = true
noise_simulation = true

[quantum]
topology = "heavy_hex"
num_qubits = 127
shots = 4096

Summary of Combinations by Task

TaskCrates to combine
Train an LLMlift-tensor + lift-opt (TensorFusion, FlashAttention) + lift-sim (CostModel) + lift-export (LLVM, ONNX)
Quantised inferencelift-tensor + lift-opt (QuantisationPass) + lift-predict + lift-export (LLVM, ONNX)
Quantum circuitlift-quantum + lift-opt (GateCancellation, RotationMerge, LayoutMapping) + lift-export (QASM)
VQE / QAOAlift-hybrid + lift-quantum + lift-opt (NoiseAwareSchedule) + lift-sim (QuantumCostModel)
Quantum MLlift-hybrid (QuantumKernel, encoding) + lift-tensor + lift-quantum
Cost analysislift-sim (CostModel, EnergyModel) + lift-predict
QEC planninglift-quantum (qec, topology) + lift-sim (QuantumCostModel)
Import/Optimise/Exportlift-import + lift-opt + lift-export (LLVM, ONNX, QASM)
Programmatic generationlift-codegen + lift-core (ModelBuilder) + lift-export
Stable Diffusionlift-tensor (UNet ops) + lift-opt (TensorFusion) + lift-export
GNNlift-tensor (GNNMessagePassing, GNNGlobalPooling) + lift-opt + lift-export

LIFT User Manual — Complete Usage Guide

LIFTLanguage for Intelligent Frameworks and Technologies Version 0.4.3

This manual is the definitive reference for every use case of the LIFT compiler framework. It presents real-world problems, explains how LIFT solves them, and provides working code examples for each scenario.


Table of Contents

  1. What is LIFT and Why Does It Exist?
  2. Installation and Setup
  3. Core Concepts
  4. The .lif Source Language
  5. Use Case 1 — Neural Network Optimisation
  6. Use Case 2 — Transformer Attention and FlashAttention
  7. Use Case 3 — Quantum Circuit Design and Noise Analysis
  8. Use Case 4 — Hybrid Classical-Quantum (VQE)
  9. Use Case 5 — Model Import
  10. Use Case 6 — Performance Prediction
  11. Use Case 7 — Quantised Inference
  12. Use Case 8 — Backend Export (LLVM, ONNX, QASM)
  13. Use Case 9 — Energy and Carbon Estimation
  14. Use Case 10 — Device Topology and Routing
  15. Use Case 11 — Diffusion and GNN Models
  16. Use Case 12 — Budget-Constrained Compilation
  17. Use Case 13 — End-to-End Pipelines
  18. Configuration with .lith Files
  19. CLI Reference
  20. Programmatic Model Generation
  21. Complete API Reference
  22. Troubleshooting

1. What is LIFT and Why Does It Exist?

1.1 The Problem

Modern computing faces a fragmentation crisis:

  • AI/ML frameworks (PyTorch, TensorFlow, ONNX) produce models in incompatible formats with no unified optimisation pipeline.
  • Quantum computing (Qiskit, Cirq, OpenQASM) uses entirely separate toolchains with no connection to classical compilation.
  • Hybrid algorithms (VQE, QAOA, Quantum ML) require ad-hoc glue code between classical and quantum systems.
  • Performance analysis is fragmented — different tools for GPU profiling, quantum fidelity, and cost modelling.

1.2 How LIFT Solves It

LIFT provides a single SSA-based intermediate representation spanning three dialects:

DialectDomainOperations
tensorAI/ML110 ops: arithmetic, attention, convolution, normalisation, quantisation, GNN, diffusion
quantumQuantum computing48 gates: Pauli, Clifford, parametric, multi-qubit; noise models, QEC, topology
hybridClassical-quantum21 ops: encoding, gradient methods, variational algorithms, GPU↔QPU transfer

The unified pipeline: import → verify → analyse → optimise → predict → export.

1.3 Architecture

                    ┌──────────┐
                    │ lift-cli │  ← User interface
                    └────┬─────┘
           ┌─────────────┼─────────────┐
    ┌──────┴──────┐ ┌────┴────┐ ┌──────┴──────┐
    │ lift-import │ │lift-opt │ │ lift-export │
    └──────┬──────┘ └────┬────┘ └──────┬──────┘
    ┌──────┴──────┐ ┌────┴────┐ ┌──────┴──────┐
    │  lift-ast   │ │lift-sim │ │lift-predict │
    └──────┬──────┘ └────┬────┘ └──────┬──────┘
    ┌──────┴─────────────┴─────────────┴──────┐
    │              lift-core                    │
    ├──────────┬──────────┬───────────────────┤
    │lift-tensor│lift-quantum│  lift-hybrid    │
    └──────────┴──────────┴───────────────────┘

2. Installation and Setup

2.1 Prerequisites

  • Rust 1.80+ — install via rustup

2.2 Build

git clone https://github.com/rustnew/Lift.git
cd Lift
cargo build --release
cargo test --workspace   # 535 tests, all pass

2.3 Use as a Library

[dependencies]
lift-core    = { path = "crates/lift-core" }
lift-ast     = { path = "crates/lift-ast" }
lift-tensor  = { path = "crates/lift-tensor" }
lift-quantum = { path = "crates/lift-quantum" }
lift-hybrid  = { path = "crates/lift-hybrid" }
lift-opt     = { path = "crates/lift-opt" }
lift-sim     = { path = "crates/lift-sim" }
lift-predict = { path = "crates/lift-predict" }
lift-import  = { path = "crates/lift-import" }
lift-export  = { path = "crates/lift-export" }
lift-config  = { path = "crates/lift-config" }

3. Core Concepts

3.1 SSA IR

LIFT uses Static Single Assignment — every value is defined exactly once:

%h1 = "tensor.matmul"(%x, %w) : (tensor<1x784xf32>, tensor<784x256xf32>) -> tensor<1x256xf32>
%h2 = "tensor.relu"(%h1) : (tensor<1x256xf32>) -> tensor<1x256xf32>

3.2 The Context

The Context is the central data structure holding all IR elements:

#![allow(unused)]
fn main() {
use lift_core::{Context, Attributes, Location};
use lift_core::types::{Dimension, DataType, MemoryLayout};

let mut ctx = Context::new();

// Create types
let tensor_ty = ctx.make_tensor_type(
    vec![Dimension::Constant(1), Dimension::Constant(784)],
    DataType::FP32, MemoryLayout::Contiguous,
);
let qubit_ty = ctx.make_qubit_type();

// Create block, add arguments
let block = ctx.create_block();
let x = ctx.create_block_arg(block, tensor_ty);

// Create operation
let (op, results) = ctx.create_op(
    "tensor.relu", "tensor",
    vec![x], vec![tensor_ty],
    Attributes::new(), Location::unknown(),
);
ctx.add_op_to_block(block, op);
}

3.3 Linear Qubit Types

Problem: Qubits cannot be copied (no-cloning theorem). Classical IRs allow reuse, violating physics.

Solution: LIFT enforces linear types for qubits — each consumed exactly once:

#![allow(unused)]
fn main() {
let mut ctx = Context::new();
let qubit_ty = ctx.make_qubit_type();
let block = ctx.create_block();
let q0 = ctx.create_block_arg(block, qubit_ty);

// First use — OK
let (op1, _) = ctx.create_op("quantum.x", "quantum",
    vec![q0], vec![qubit_ty], Attributes::new(), Location::unknown());
ctx.add_op_to_block(block, op1);

// Second use of same q0 — LINEARITY VIOLATION
let (op2, _) = ctx.create_op("quantum.h", "quantum",
    vec![q0], vec![qubit_ty], Attributes::new(), Location::unknown());
ctx.add_op_to_block(block, op2);

let result = lift_core::verifier::verify(&ctx);
assert!(result.is_err());  // VerifyError::LinearityViolation
}

3.4 Verification

The verifier checks SSA, dominance, and linearity:

#![allow(unused)]
fn main() {
use lift_core::verifier;

match verifier::verify(&ctx) {
    Ok(()) => println!("IR is valid"),
    Err(errors) => {
        for err in &errors {
            eprintln!("Error: {}", err);
        }
    }
}
}

3.5 Printing the IR

#![allow(unused)]
fn main() {
use lift_core::printer::print_ir;
let output = print_ir(&ctx);
println!("{}", output);
}

4. The .lif Source Language

4.1 Syntax

#dialect tensor

module @name {
    func @function(%arg0: type0, %arg1: type1) -> return_type {
        %result = "dialect.op"(%arg0, %arg1) {attr = value}
            : (type0, type1) -> return_type
        return %result
    }
}

4.2 Types

TypeSyntaxExample
Tensortensor<shape x dtype>tensor<1x784xf32>
Qubitqubitqubit
Classical bitbitbit
Scalarf32, f64, i32, i64f32

4.3 Parsing Programmatically

#![allow(unused)]
fn main() {
use lift_ast::{Lexer, Parser, IrBuilder};
use lift_core::Context;

let source = std::fs::read_to_string("examples/tensor_mlp.lif").unwrap();
let tokens = Lexer::new(&source).tokenize().to_vec();
let program = Parser::new(tokens).parse().unwrap();

let mut ctx = Context::new();
IrBuilder::new().build_program(&mut ctx, &program).unwrap();
lift_core::verifier::verify(&ctx).unwrap();
}

5. Use Case 1 — Neural Network Optimisation

5.1 Problem

You have a Multi-Layer Perceptron (MLP) and want to:

  1. Represent it as LIFT IR
  2. Verify correctness
  3. Fuse MatMul + Bias + ReLU into a single kernel
  4. Measure FLOPs and memory

5.2 The MLP in .lif

File: examples/tensor_mlp.lif

#dialect tensor

module @mlp {
    func @forward(%x: tensor<1x784xf32>, %w1: tensor<784x256xf32>, %b1: tensor<256xf32>,
                  %w2: tensor<256x10xf32>, %b2: tensor<10xf32>) -> tensor<1x10xf32> {
        %h1 = "tensor.matmul"(%x, %w1) : (tensor<1x784xf32>, tensor<784x256xf32>) -> tensor<1x256xf32>
        %h2 = "tensor.add"(%h1, %b1) : (tensor<1x256xf32>, tensor<256xf32>) -> tensor<1x256xf32>
        %h3 = "tensor.relu"(%h2) : (tensor<1x256xf32>) -> tensor<1x256xf32>
        %h4 = "tensor.matmul"(%h3, %w2) : (tensor<1x256xf32>, tensor<256x10xf32>) -> tensor<1x10xf32>
        %h5 = "tensor.add"(%h4, %b2) : (tensor<1x10xf32>, tensor<10xf32>) -> tensor<1x10xf32>
        %out = "tensor.softmax"(%h5) : (tensor<1x10xf32>) -> tensor<1x10xf32>
        return %out
    }
}

5.3 Build the IR Programmatically

#![allow(unused)]
fn main() {
use lift_core::{Context, Attributes, Location};
use lift_core::types::{Dimension, DataType, MemoryLayout};

let mut ctx = Context::new();

let input_ty = ctx.make_tensor_type(
    vec![Dimension::Constant(1), Dimension::Constant(784)],
    DataType::FP32, MemoryLayout::Contiguous,
);
let w1_ty = ctx.make_tensor_type(
    vec![Dimension::Constant(784), Dimension::Constant(256)],
    DataType::FP32, MemoryLayout::Contiguous,
);
let b1_ty = ctx.make_tensor_type(
    vec![Dimension::Constant(256)],
    DataType::FP32, MemoryLayout::Contiguous,
);
let h1_ty = ctx.make_tensor_type(
    vec![Dimension::Constant(1), Dimension::Constant(256)],
    DataType::FP32, MemoryLayout::Contiguous,
);

let block = ctx.create_block();
let x  = ctx.create_block_arg(block, input_ty);
let w1 = ctx.create_block_arg(block, w1_ty);
let b1 = ctx.create_block_arg(block, b1_ty);

// MatMul
let (mm_op, mm_res) = ctx.create_op(
    "tensor.matmul", "tensor", vec![x, w1], vec![h1_ty],
    Attributes::new(), Location::unknown(),
);
ctx.add_op_to_block(block, mm_op);

// Add bias
let (add_op, add_res) = ctx.create_op(
    "tensor.add", "tensor", vec![mm_res[0], b1], vec![h1_ty],
    Attributes::new(), Location::unknown(),
);
ctx.add_op_to_block(block, add_op);

// ReLU
let (relu_op, _relu_res) = ctx.create_op(
    "tensor.relu", "tensor", vec![add_res[0]], vec![h1_ty],
    Attributes::new(), Location::unknown(),
);
ctx.add_op_to_block(block, relu_op);

lift_core::verifier::verify(&ctx).expect("Verification failed");
}

5.4 Tensor Fusion: Fuse MatMul + Bias + ReLU

Problem: Three separate GPU kernels waste memory bandwidth on intermediate results.

Solution: The TensorFusion pass detects matmul → add → relu and fuses them:

#![allow(unused)]
fn main() {
use lift_core::pass::PassManager;
use lift_opt::{Canonicalize, ConstantFolding, TensorFusion, DeadCodeElimination};

let mut pm = PassManager::new();
pm.add_pass(Box::new(Canonicalize));        // x + 0 → x, x * 1 → x
pm.add_pass(Box::new(ConstantFolding));     // fold constants at compile time
pm.add_pass(Box::new(TensorFusion));        // matmul + bias + relu → fused
pm.add_pass(Box::new(DeadCodeElimination)); // remove dead ops

let results = pm.run_all(&mut ctx);
for (name, result) in &results {
    println!("  {}: {:?}", name, result);
}
}

Before fusion:

%h1 = "tensor.matmul"(%x, %w1)  : (...) -> tensor<1x256xf32>
%h2 = "tensor.add"(%h1, %b1)    : (...) -> tensor<1x256xf32>
%h3 = "tensor.relu"(%h2)        : (...) -> tensor<1x256xf32>

After fusion:

%h3 = "tensor.fused_matmul_bias_relu"(%x, %w1, %b1) : (...) -> tensor<1x256xf32>

5.5 Analyse Resource Usage

#![allow(unused)]
fn main() {
use lift_sim::analysis::analyze_module;

let report = analyze_module(&ctx);
println!("Total ops: {}", report.num_ops);
println!("Tensor ops: {}", report.num_tensor_ops);
println!("Total FLOPs: {}", report.total_flops);
println!("Total memory: {} bytes", report.total_memory_bytes);
println!("Peak memory: {} bytes", report.peak_memory_bytes);

for (op_name, count) in &report.op_breakdown {
    println!("  {}: {}", op_name, count);
}
}

5.6 Shape Inference and FLOPs Counting

LIFT computes shapes and FLOPs for every tensor operation:

#![allow(unused)]
fn main() {
use lift_tensor::{TensorOp, ShapeInference};
use lift_core::types::{TensorTypeInfo, Dimension, DataType, MemoryLayout};

let a = TensorTypeInfo {
    shape: vec![Dimension::Constant(2), Dimension::Constant(3)],
    dtype: DataType::FP32, layout: MemoryLayout::Contiguous,
};
let b = TensorTypeInfo {
    shape: vec![Dimension::Constant(3), Dimension::Constant(4)],
    dtype: DataType::FP32, layout: MemoryLayout::Contiguous,
};

// Shape inference
let output = ShapeInference::infer_output_shape(&TensorOp::MatMul, &[&a, &b]).unwrap();
// output[0].shape = [2, 4]

// FLOPs: 2*M*N*K = 2*2*4*3 = 48
let flops = ShapeInference::compute_flops(&TensorOp::MatMul, &[&a, &b]);
assert_eq!(flops, Some(48));

// Memory bytes: input A + input B + output
let mem = ShapeInference::compute_memory_bytes(&TensorOp::MatMul, &[&a, &b]);
println!("Memory: {:?} bytes", mem);
}

5.7 All 110 Tensor Operations

CategoryOperations
Arithmeticadd, sub, mul, div, neg, matmul, linear, conv2d, embedding
Activationsrelu, gelu, silu, sigmoid, softmax, tanh, leaky_relu, elu, mish, hard_swish, hard_sigmoid
Normalisationlayernorm, rmsnorm, batchnorm, groupnorm, instancenorm
Shapereshape, transpose, concat, split, gather, scatter, squeeze, unsqueeze, permute, expand, slice, pad, tile
Constantsconstant, zeros, ones, arange, full
Attentionattention, multi_head_attention, multi_query_attention, grouped_query_attention, flash_attention, sliding_window_attention, cross_attention, paged_attention
MoEmoe_dispatch, moe_combine
Convolutionconv1d, conv3d, conv_transpose2d, depthwise_conv2d, dilated_conv2d
Poolingmaxpool2d, avgpool2d, adaptive_avgpool2d, global_avgpool
Recurrentlstm_cell, gru_cell, rnn_cell
Advanced Matheinsum, fft, ifft, svd, eig, solve, topk, sort, cumsum, where, clamp
Sparsesparse_matmul, sparse_embedding
Quantisationquantize, dequantize, quantize_int4, dequantize_int4, quantize_fp8, dequantize_fp8
Diffusionunet_down_block, unet_up_block, timestep_embedding
GNNgnn_message_passing, gnn_global_pooling
Memorycheckpoint, offload, grad_accumulate
Gradientgrad_matmul, grad_relu, grad_softmax, grad_layernorm, grad_attention, grad_conv2d, grad_linear, grad_gelu
Parallelismparallel_split, parallel_allreduce, pipeline_send, pipeline_receive
Fusedfused_matmul_bias_relu, fused_matmul_bias, fused_linear_gelu, fused_attention_layernorm, fused_linear_silu, fused_conv_batchnorm_relu

6. Use Case 2 — Transformer Attention and FlashAttention

6.1 Problem

Transformers use self-attention which scales O(n²) in memory. For long sequences (>512 tokens), this becomes the bottleneck.

6.2 Attention in .lif

File: examples/attention.lif

#dialect tensor

module @transformer {
    func @self_attention(%q: tensor<1x128x64xf32>, %k: tensor<1x128x64xf32>,
                         %v: tensor<1x128x64xf32>, %norm_w: tensor<64xf32>)
                         -> tensor<1x128x64xf32> {
        %attn = "tensor.attention"(%q, %k, %v)
            : (tensor<1x128x64xf32>, tensor<1x128x64xf32>, tensor<1x128x64xf32>)
            -> tensor<1x128x64xf32>
        %normed = "tensor.layernorm"(%attn, %norm_w)
            : (tensor<1x128x64xf32>, tensor<64xf32>) -> tensor<1x128x64xf32>
        return %normed
    }
}

6.3 FlashAttention Pass

The FlashAttentionPass replaces tensor.attention with tensor.flash_attention when sequence length exceeds a threshold:

#![allow(unused)]
fn main() {
use lift_opt::FlashAttentionPass;
use lift_core::pass::PassManager;

let mut pm = PassManager::new();
pm.add_pass(Box::new(FlashAttentionPass { seq_len_threshold: 512 }));
pm.run_all(&mut ctx);
// tensor.attention → tensor.flash_attention
// Same FLOPs, O(n) memory instead of O(n²)
}

6.4 Attention Variants

OperationArchitectureMemory
tensor.attentionStandard QKVO(n²)
tensor.multi_head_attentionGPT, BERTO(n²)
tensor.multi_query_attentionPaLMO(n²) reduced
tensor.grouped_query_attentionLlama 2O(n²) reduced
tensor.flash_attentionFlashAttentionO(n)
tensor.sliding_window_attentionMistralO(n×w)
tensor.cross_attentionEncoder-decoderO(n×m)
tensor.paged_attentionvLLM KV cacheO(n) paged

6.5 FLOPs Calculation

For attention: FLOPs = 4 × B × H × S² × D

#![allow(unused)]
fn main() {
use lift_tensor::{TensorOp, ShapeInference};
use lift_core::types::{TensorTypeInfo, Dimension, DataType, MemoryLayout};

let q = TensorTypeInfo {
    shape: vec![
        Dimension::Constant(1),    // batch
        Dimension::Constant(8),    // heads
        Dimension::Constant(2048), // seq_len
        Dimension::Constant(64),   // head_dim
    ],
    dtype: DataType::FP32, layout: MemoryLayout::Contiguous,
};

let flops = ShapeInference::compute_flops(&TensorOp::Attention, &[&q, &q, &q]);
println!("Attention FLOPs: {:?}", flops);
// 4 × 1 × 8 × 2048 × 2048 × 64 ≈ 8.6 billion
}

7. Use Case 3 — Quantum Circuit Design and Noise Analysis

7.1 Problem

Design a quantum circuit, understand which gates your hardware supports, model noise, and estimate fidelity before executing on real devices.

7.2 Bell State in .lif

File: examples/quantum_bell.lif

#dialect quantum

module @bell_state {
    func @bell(%q0: qubit, %q1: qubit) -> (qubit, qubit) {
        %q2 = "quantum.h"(%q0) : (qubit) -> qubit
        %q3, %q4 = "quantum.cx"(%q2, %q1) : (qubit, qubit) -> (qubit, qubit)
        return %q3, %q4
    }
}

7.3 Build a Circuit Programmatically

#![allow(unused)]
fn main() {
use lift_core::{Context, Attributes, Location};

let mut ctx = Context::new();
let qubit_ty = ctx.make_qubit_type();

let block = ctx.create_block();
let q0 = ctx.create_block_arg(block, qubit_ty);
let q1 = ctx.create_block_arg(block, qubit_ty);

// Hadamard on q0
let (h_op, h_res) = ctx.create_op(
    "quantum.h", "quantum",
    vec![q0], vec![qubit_ty],
    Attributes::new(), Location::unknown(),
);
ctx.add_op_to_block(block, h_op);

// CNOT on (q0', q1)
let (cx_op, cx_res) = ctx.create_op(
    "quantum.cx", "quantum",
    vec![h_res[0], q1], vec![qubit_ty, qubit_ty],
    Attributes::new(), Location::unknown(),
);
ctx.add_op_to_block(block, cx_op);

lift_core::verifier::verify(&ctx).expect("Valid circuit");
}

7.4 All 48 Quantum Gates

CategoryGates
1Q standardH, X, Y, Z, S, Sdg, T, Tdg, SX
1Q parametricRX, RY, RZ, P, U1, U2, U3
1Q fixedRx90, Rx180
2Q standardCX, CZ, CY, SWAP, ISWAP, ECR
2Q parametricRZX, XX, YY, ZZ, CPhase, XY, CP
IonQ nativeGPI, GPI2, MS
3QCCX (Toffoli), CSWAP (Fredkin)
Multi-controlledMCX, MCZ
MeasurementMeasure, MeasureAll, Reset, Barrier, Init
SpecialGlobalPhase, Delay, VirtualRZ, IfElse, ParamGate

7.5 Hardware-Native Gate Sets

#![allow(unused)]
fn main() {
use lift_quantum::QuantumGate;
use lift_quantum::gates::Provider;

// IBM Eagle/Kyoto native: {RZ, SX, X, CX, ECR}
let ibm = QuantumGate::native_basis(Provider::IbmEagle);

// Rigetti native: {RZ, RX, CZ, CPhase, XY}
let rigetti = QuantumGate::native_basis(Provider::Rigetti);

// IonQ native: {GPI, GPI2, MS}
let ionq = QuantumGate::native_basis(Provider::IonQ);

// Quantinuum native: {RZ, RX, RY, ZZ}
let quantinuum = QuantumGate::native_basis(Provider::Quantinuum);

for gate in ibm {
    println!("{} ({} qubit, parametric: {}, clifford: {})",
        gate.op_name(), gate.num_qubits(),
        gate.is_parametric(), gate.is_clifford());
}
}

7.6 Noise Models

Problem: Real quantum hardware introduces errors. You need to model them before execution.

#![allow(unused)]
fn main() {
use lift_quantum::{NoiseModel, GateNoise, CircuitNoise};

// Depolarizing noise (1Q gate error p = 0.001)
let noise_1q = NoiseModel::Depolarizing { p: 0.001 };
println!("1Q fidelity: {:.6}", noise_1q.fidelity()); // 0.999000

// Thermal relaxation
let thermal = NoiseModel::ThermalRelaxation {
    t1_us: 100.0, t2_us: 80.0, gate_time_us: 0.3,
};
println!("Thermal fidelity: {:.6}", thermal.fidelity());

// Composed noise
let combined = noise_1q.compose(&thermal);
println!("Combined fidelity: {:.6}", combined.fidelity());

// Track noise across a full circuit
let mut circuit = CircuitNoise::new();
let g1q = GateNoise::with_depolarizing(0.999, 0.02);
let g2q = GateNoise::with_depolarizing(0.99, 0.3);

circuit.add_gate(&g1q, false);  // H  (1Q)
circuit.add_gate(&g2q, true);   // CX (2Q)

println!("Circuit fidelity: {:.6}", circuit.total_fidelity);
println!("Gate count: {}, 2Q gates: {}", circuit.gate_count, circuit.two_qubit_count);
println!("Meets 99% threshold: {}", circuit.meets_threshold(0.99));
}

All noise models:

ModelParameterUse Case
IdealSimulation baseline
Depolarizing { p }Error probabilityGeneral gate errors
AmplitudeDamping { gamma }Decay rateT1 relaxation
PhaseDamping { gamma }Dephasing rateT2 dephasing
BitFlip { p }Flip probabilityClassical-like errors
PhaseFlip { p }Phase flip probZ errors
ThermalRelaxation { t1, t2, t }Coherence timesRealistic hardware
Kraus { operators }Kraus matricesCustom channels
Composed(vec)Multiple modelsLayered noise

7.7 Quantum Cost Model

#![allow(unused)]
fn main() {
use lift_sim::cost::QuantumCostModel;

// Superconducting (IBM-like): fast but lower fidelity
let sc = QuantumCostModel::superconducting_default();
// gate_time_1q: 0.02μs, gate_time_2q: 0.3μs, fidelity_1q: 0.999, fidelity_2q: 0.99

// Trapped-ion (IonQ-like): slow but very high fidelity
let ti = QuantumCostModel::trapped_ion_default();
// gate_time_1q: 10μs, gate_time_2q: 200μs, fidelity_1q: 0.9999, fidelity_2q: 0.999

// Neutral-atom: fast with moderate fidelity, many qubits
let na = QuantumCostModel::neutral_atom_default();
// gate_time_1q: 0.5μs, gate_time_2q: 1.0μs, fidelity_1q: 0.999, fidelity_2q: 0.995

// Compare fidelity for a 100-gate circuit (80×1Q + 20×2Q)
println!("Superconducting: {:.6}", sc.circuit_fidelity(80, 20));
println!("Trapped-ion:     {:.6}", ti.circuit_fidelity(80, 20));
println!("Neutral-atom:    {:.6}", na.circuit_fidelity(80, 20));
}

7.8 Gate Optimisation Passes

#![allow(unused)]
fn main() {
use lift_opt::{GateCancellation, RotationMerge, NoiseAwareSchedule, LayoutMapping};
use lift_core::pass::PassManager;

let mut pm = PassManager::new();
pm.add_pass(Box::new(GateCancellation));     // H·H → I, X·X → I
pm.add_pass(Box::new(RotationMerge));        // Rz(a)·Rz(b) → Rz(a+b)
pm.add_pass(Box::new(NoiseAwareSchedule));   // schedule to minimise noise
pm.add_pass(Box::new(LayoutMapping));        // map to device topology

let results = pm.run_all(&mut ctx);
for (name, result) in &results {
    println!("  {}: {:?}", name, result);
}
}
PassWhat It Does
GateCancellationCancels adjacent inverse gates (H·H, X·X, etc.)
RotationMergeMerges consecutive rotations: Rz(a)·Rz(b) → Rz(a+b)
NoiseAwareScheduleReorders gates to place noisy 2Q gates on high-fidelity edges
LayoutMappingMaps logical qubits to physical qubits with SWAP insertion

8. Use Case 4 — Hybrid Classical-Quantum (VQE)

8.1 Problem

VQE (Variational Quantum Eigensolver) is a hybrid algorithm requiring:

  1. Encoding classical data into quantum states
  2. Running a parametrised circuit (ansatz)
  3. Computing gradients of quantum parameters
  4. Iterating with a classical optimiser

8.2 Encoding Strategies

#![allow(unused)]
fn main() {
use lift_hybrid::encoding::{EncodingStrategy, EncodingConfig};

// Angle encoding: 1 qubit per feature, circuit depth 1
let angle = EncodingConfig::new(EncodingStrategy::AngleEncoding, 4);
println!("Qubits: {}, depth: {}", angle.num_qubits,
    angle.strategy.circuit_depth(4));
// 4 qubits, depth 1

// Amplitude encoding: log2(N) qubits, depth N
let amp = EncodingConfig::new(EncodingStrategy::AmplitudeEncoding, 16);
println!("Qubits: {}, depth: {}", amp.num_qubits,
    amp.strategy.circuit_depth(16));
// 4 qubits, depth 16

// IQP encoding: N qubits, depth 2N
let iqp = EncodingConfig::new(EncodingStrategy::IQPEncoding, 8);
println!("Qubits: {}, depth: {}", iqp.num_qubits,
    iqp.strategy.circuit_depth(8));
// 8 qubits, depth 16
}
StrategyQubitsDepthBest For
AngleEncodingN1Small feature spaces
AmplitudeEncodinglog₂(N)NLarge feature spaces
BasisEncodingN1Binary data
IQPEncodingN2NQuantum advantage proofs
HamiltonianEncodingNNPhysics simulations
KernelEncodingN3NQuantum kernel methods

8.3 Gradient Methods

#![allow(unused)]
fn main() {
use lift_hybrid::gradient::GradientMethod;

let num_params = 20;

// Parameter shift: exact, 2 evaluations per parameter
let ps = GradientMethod::ParameterShift;
println!("Evals: {}, exact: {}", ps.circuit_evaluations(num_params), ps.is_exact());
// 40, true

// SPSA: stochastic, only 2 evaluations total
let spsa = GradientMethod::SPSA;
println!("Evals: {}, exact: {}", spsa.circuit_evaluations(num_params), spsa.is_exact());
// 2, false

// Adjoint: exact, 1 evaluation (best for simulators)
let adj = GradientMethod::Adjoint;
println!("Evals: {}, exact: {}", adj.circuit_evaluations(num_params), adj.is_exact());
// 1, true
}
MethodEvaluationsExactBest For
ParameterShift2NYesHardware
FiniteDifferenceN+1NoQuick approximation
SPSA2NoMany parameters
Adjoint1YesSimulators
Backprop1YesClassical parts

8.4 Joint Gradient (Classical + Quantum)

#![allow(unused)]
fn main() {
use lift_hybrid::gradient::{GradientMethod, JointGradientConfig};

let config = JointGradientConfig {
    classical_method: GradientMethod::Backprop,
    quantum_method: GradientMethod::ParameterShift,
    num_classical_params: 1000,
    num_quantum_params: 20,
};

println!("Total evaluations: {}", config.total_evaluations());
// 1 (backprop) + 40 (param shift) = 41
}

8.5 VQE Pipeline in .lif

#dialect tensor
#dialect quantum
#dialect hybrid

module @vqe {
    func @step(%data: tensor<1x4xf32>, %q0: qubit, %q1: qubit) -> f32 {
        // 1. Encode classical data
        %encoded = "hybrid.encode"(%data) : (tensor<1x4xf32>) -> tensor<1x4xf32>

        // 2. Variational ansatz
        %q2 = "quantum.ry"(%q0) {angle = 0.5} : (qubit) -> qubit
        %q3, %q4 = "quantum.cx"(%q2, %q1) : (qubit, qubit) -> (qubit, qubit)
        %q5 = "quantum.rz"(%q3) {angle = 1.2} : (qubit) -> qubit

        // 3. Measure expectation value
        %energy = "hybrid.measure_expectation"(%q5) : (qubit) -> f32

        // 4. Compute gradient
        %grad = "hybrid.parameter_shift"(%energy) : (f32) -> f32

        return %energy
    }
}

8.6 All 21 Hybrid Operations

OperationDescription
hybrid.encodeEncode classical data into quantum state
hybrid.decodeDecode quantum measurement to classical
hybrid.parameter_shiftGradient via parameter shift rule
hybrid.finite_differenceGradient via finite differences
hybrid.spsaStochastic parameter shift approximation
hybrid.adjoint_diffGradient via adjoint differentiation
hybrid.stochastic_param_shiftStochastic parameter shift
hybrid.joint_gradientJoint classical+quantum gradient
hybrid.classical_preprocessClassical preprocessing step
hybrid.quantum_postprocessQuantum postprocessing step
hybrid.forwardHybrid forward pass
hybrid.backwardHybrid backward pass
hybrid.vqc_layerVariational quantum circuit layer
hybrid.vqe_ansatzVQE ansatz circuit
hybrid.qaoa_layerQAOA mixer + cost layer
hybrid.quantum_kernelQuantum kernel evaluation
hybrid.gpu_to_qpuTransfer data GPU → QPU
hybrid.qpu_to_gpuTransfer data QPU → GPU
hybrid.co_executeCo-execute classical and quantum
hybrid.measure_expectationMeasure observable expectation
hybrid.measure_samplesMeasure and return bit-strings

9. Use Case 5 — Model Import

9.1 Problem

You have existing models in ONNX, PyTorch FX, or OpenQASM format and want to bring them into LIFT for unified optimisation and analysis.

9.2 ONNX Import

#![allow(unused)]
fn main() {
use lift_import::OnnxImporter;
use lift_core::pass::PassManager;

let importer = OnnxImporter::new();
let mut ctx = importer.import("model.onnx")
    .expect("ONNX import failed");

// Optimise with LIFT
let mut pm = PassManager::new();
pm.add_pass(Box::new(lift_opt::Canonicalize));
pm.add_pass(Box::new(lift_opt::TensorFusion));
pm.add_pass(Box::new(lift_opt::DeadCodeElimination));
pm.run_all(&mut ctx);
}

Supported ONNX operators are mapped to LIFT tensor ops (MatMul, Conv, ReLU, Softmax, Attention, etc.).

9.3 PyTorch FX Import

#![allow(unused)]
fn main() {
use lift_import::PyTorchFxImporter;

let importer = PyTorchFxImporter::new();
let ctx = importer.import("model_fx.json")
    .expect("FX import failed");
}

Import from torch.fx graph JSON exports. All standard PyTorch operations are mapped to their LIFT equivalents.

9.4 OpenQASM 3.0 Import

#![allow(unused)]
fn main() {
use lift_import::OpenQasm3Importer;
use lift_core::pass::PassManager;

let importer = OpenQasm3Importer::new();
let mut ctx = importer.import("circuit.qasm")
    .expect("QASM import failed");

// Optimise the quantum circuit
let mut pm = PassManager::new();
pm.add_pass(Box::new(lift_opt::GateCancellation));
pm.add_pass(Box::new(lift_opt::RotationMerge));
pm.run_all(&mut ctx);
}

9.5 Import → Analyse → Compare

A common workflow: import a model, analyse it, optimise, then compare before/after:

#![allow(unused)]
fn main() {
use lift_sim::analysis::analyze_module;

// Before optimisation
let report_before = analyze_module(&ctx);
println!("Before: {} ops, {} FLOPs", report_before.num_ops, report_before.total_flops);

// Run passes...
pm.run_all(&mut ctx);

// After optimisation
let report_after = analyze_module(&ctx);
println!("After:  {} ops, {} FLOPs", report_after.num_ops, report_after.total_flops);
println!("Ops reduced: {:.1}%",
    (1.0 - report_after.num_ops as f64 / report_before.num_ops as f64) * 100.0);
}

10. Use Case 6 — Performance Prediction

10.1 Problem

Before running a model on expensive hardware, you need to know:

  • How long will it take?
  • Is it compute-bound or memory-bound?
  • Will it fit in GPU memory?
  • How many GPUs are needed?

10.2 Roofline Model (Classical)

#![allow(unused)]
fn main() {
use lift_sim::analysis::analyze_module;
use lift_sim::cost::CostModel;
use lift_predict::roofline::predict_performance;

let report = analyze_module(&ctx);

// NVIDIA A100
let a100 = CostModel::a100();
let pred_a100 = predict_performance(&report, &a100);

println!("=== A100 Prediction ===");
println!("Compute time: {:.4} ms", pred_a100.compute_time_ms);
println!("Memory time:  {:.4} ms", pred_a100.memory_time_ms);
println!("Predicted:    {:.4} ms", pred_a100.predicted_time_ms);
println!("Arithmetic intensity: {:.2} FLOP/byte", pred_a100.arithmetic_intensity);
println!("Bottleneck: {}", pred_a100.bottleneck); // "compute" or "memory"

// NVIDIA H100
let h100 = CostModel::h100();
let pred_h100 = predict_performance(&report, &h100);

println!("\n=== H100 Prediction ===");
println!("Predicted: {:.4} ms", pred_h100.predicted_time_ms);
println!("Speedup vs A100: {:.2}x",
    pred_a100.predicted_time_ms / pred_h100.predicted_time_ms);
}

10.3 GPU Profiles

ProfileTFLOPS (FP16)Memory BW (GB/s)VRAMTDP
CostModel::a100()3122,03980 GB400W
CostModel::h100()9893,35080 GB700W

10.4 Memory Fit and Multi-GPU Planning

#![allow(unused)]
fn main() {
let model = CostModel::a100();
let bytes = report.total_memory_bytes;

println!("Model size: {:.2} GB", bytes as f64 / 1e9);
println!("Fits in 1 GPU: {}", model.fits_in_memory(bytes));
println!("GPUs needed: {}", model.num_gpus_needed(bytes));

// Arithmetic intensity analysis
let ai = model.arithmetic_intensity(report.total_flops, bytes);
let ridge = model.flops_per_second / (model.memory_bandwidth_gb_s * 1e9);
println!("Arithmetic intensity: {:.2} FLOP/byte", ai);
println!("Ridge point: {:.2} FLOP/byte", ridge);
println!("Regime: {}", if ai >= ridge { "compute-bound" } else { "memory-bound" });
}

10.5 Quantum Performance Prediction

#![allow(unused)]
fn main() {
use lift_predict::roofline::predict_quantum;
use lift_sim::quantum_sim::QuantumAnalysis;
use lift_sim::cost::QuantumCostModel;

let analysis = QuantumAnalysis {
    num_qubits_used: 10,
    gate_count: 200,
    one_qubit_gates: 150,
    two_qubit_gates: 50,
    measurements: 10,
    circuit_depth: 30,
    estimated_fidelity: 0.92,
};

let sc = QuantumCostModel::superconducting_default();
let prediction = predict_quantum(&analysis, &sc, 0.01); // 1% precision

println!("Estimated fidelity: {:.6}", prediction.estimated_fidelity);
println!("Circuit time: {:.2} μs", prediction.circuit_time_us);
println!("Shots for 1%% precision: {}", prediction.num_shots_for_precision);
println!("Total execution: {:.2} ms", prediction.total_execution_time_ms);

// Compare technologies
let ti = QuantumCostModel::trapped_ion_default();
let pred_ti = predict_quantum(&analysis, &ti, 0.01);
println!("\nTrapped-ion fidelity: {:.6} (vs {:.6} superconducting)",
    pred_ti.estimated_fidelity, prediction.estimated_fidelity);
println!("Trapped-ion time: {:.2} ms (vs {:.2} ms)",
    pred_ti.total_execution_time_ms, prediction.total_execution_time_ms);
}

11. Use Case 7 — Quantised Inference

11.1 Problem

FP32 models are too large and slow for deployment. You want INT8, INT4, or FP8 for faster inference.

11.2 Quantisation Operations

OperationConversion
tensor.quantizeFP32 → INT8
tensor.dequantizeINT8 → FP32
tensor.quantize_int4FP32 → INT4
tensor.dequantize_int4INT4 → FP32
tensor.quantize_fp8FP32 → FP8
tensor.dequantize_fp8FP8 → FP32

11.3 Quantised Inference in .lif

#dialect tensor

module @quantised_inference {
    func @forward(%x: tensor<1x784xf32>,
                  %w1_q: tensor<784x256xi8>,
                  %b1: tensor<256xf32>) -> tensor<1x256xf32> {
        // Dequantize INT8 weights to FP32
        %w1 = "tensor.dequantize"(%w1_q) : (tensor<784x256xi8>) -> tensor<784x256xf32>

        // Compute in FP32
        %h1 = "tensor.matmul"(%x, %w1) : (tensor<1x784xf32>, tensor<784x256xf32>) -> tensor<1x256xf32>
        %h2 = "tensor.add"(%h1, %b1) : (tensor<1x256xf32>, tensor<256xf32>) -> tensor<1x256xf32>
        %out = "tensor.relu"(%h2) : (tensor<1x256xf32>) -> tensor<1x256xf32>
        return %out
    }
}

11.4 Automatic Quantisation Pass

The QuantisationPass annotates ops that are safe to quantise:

#![allow(unused)]
fn main() {
use lift_opt::QuantisationPass;
use lift_core::pass::PassManager;

let mut pm = PassManager::new();
pm.add_pass(Box::new(QuantisationPass));
pm.run_all(&mut ctx);
}

11.5 Memory Savings

Data TypeBitsSize vs FP32Use Case
FP32321× baselineTraining
FP16 / BF16160.5×Mixed-precision training
FP8 (E4M3)80.25×H100 inference
INT880.25×Server inference
INT440.125×Edge/mobile inference
INT220.0625×Extreme compression

11.6 FP8 Formats

LIFT supports both FP8 variants:

#![allow(unused)]
fn main() {
use lift_tensor::ops::Fp8Format;

// E4M3: 4 exponent, 3 mantissa — higher precision, smaller range
// Best for: weights and activations in forward pass
let e4m3 = Fp8Format::E4M3;

// E5M2: 5 exponent, 2 mantissa — lower precision, larger range
// Best for: gradients in backward pass
let e5m2 = Fp8Format::E5M2;
}

12. Use Case 8 — Backend Export (LLVM, ONNX, QASM)

12.1 Problem

After optimisation, you need to compile the IR to executable code for GPU/CPU or quantum hardware.

12.2 Export to LLVM IR

#![allow(unused)]
fn main() {
use lift_export::LlvmExporter;

let exporter = LlvmExporter::new();
let llvm_ir = exporter.export(&ctx).expect("LLVM export failed");

std::fs::write("output.ll", &llvm_ir).unwrap();
println!("Written {} bytes of LLVM IR", llvm_ir.len());
}

Compile the output:

# Compile to binary
clang -O3 output.ll -o model

# Or to object file
llc -O3 output.ll -filetype=obj -o model.o

12.3 Export to ONNX

#![allow(unused)]
fn main() {
use lift_export::OnnxExporter;

let exporter = OnnxExporter::new();
let onnx = exporter.export(&ctx).expect("ONNX export failed");

std::fs::write("model.onnx", &onnx).unwrap();

// JSON format also available
let onnx_json = exporter.export_json(&ctx).expect("ONNX JSON export failed");
std::fs::write("model_onnx.json", &onnx_json).unwrap();
}

The output is ONNX protobuf text format at opset version 21, compatible with:

  • PyTorch (via torch.onnx.export round-trip)
  • TensorFlow (via tf2onnx)
  • TensorRT (NVIDIA inference)
  • ONNX Runtime (cross-platform inference)
  • Microsoft extensions for attention, MoE, and fused operations

Key ONNX op mappings:

LIFT OperationONNX OperatorDomain
tensor.matmulMatMulstandard
tensor.linearGemmstandard
tensor.reluRelustandard
tensor.geluGelustandard
tensor.softmaxSoftmaxstandard
tensor.layernormLayerNormalizationstandard
tensor.rmsnormSimplifiedLayerNormalizationcom.microsoft
tensor.conv2dConvstandard
tensor.attentionAttentioncom.microsoft
tensor.flash_attentionMultiHeadAttentioncom.microsoft
tensor.grouped_query_attentionGroupQueryAttentioncom.microsoft
tensor.quantizeQuantizeLinearstandard
tensor.dequantizeDequantizeLinearstandard
tensor.moe_dispatchMoEcom.microsoft
tensor.fused_matmul_bias_reluFusedMatMulBiasRelucom.microsoft
+ 55 more operations

12.4 Export to OpenQASM 3.0

#![allow(unused)]
fn main() {
use lift_export::QasmExporter;

let exporter = QasmExporter::new();
let qasm = exporter.export(&ctx).expect("QASM export failed");

std::fs::write("circuit.qasm", &qasm).unwrap();
}

The output is standard OpenQASM 3.0 executable on:

  • IBM Quantum (via Qiskit)
  • Rigetti (via pyQuil)
  • IonQ (via native API)
  • Quantinuum (via TKET)
  • Any OpenQASM 3.0 compatible platform

12.5 Full Export Pipeline

#![allow(unused)]
fn main() {
use lift_core::printer::print_ir;

// Print human-readable IR (for debugging)
let ir_text = print_ir(&ctx);
std::fs::write("debug.lif", &ir_text).unwrap();

// Export to LLVM (for tensor/classical ops)
let llvm = LlvmExporter::new().export(&ctx).expect("LLVM failed");
std::fs::write("model.ll", &llvm).unwrap();

// Export to ONNX (for PyTorch/TensorFlow/TensorRT interop)
let onnx = OnnxExporter::new().export(&ctx).expect("ONNX failed");
std::fs::write("model.onnx", &onnx).unwrap();

// Export to QASM (for quantum ops)
let qasm = QasmExporter::new().export(&ctx).expect("QASM failed");
std::fs::write("circuit.qasm", &qasm).unwrap();
}

13. Use Case 9 — Energy and Carbon Estimation

13.1 Problem

AI training and inference consume significant energy. You want to estimate the environmental impact before committing resources.

13.2 Classical Energy Model

#![allow(unused)]
fn main() {
use lift_sim::cost::{CostModel, EnergyModel};
use lift_sim::analysis::analyze_module;
use lift_predict::roofline::predict_performance;

let report = analyze_module(&ctx);
let cost = CostModel::h100();
let prediction = predict_performance(&report, &cost);

let energy = EnergyModel::h100();

// Single inference
let joules = energy.energy_joules(prediction.predicted_time_ms, 1);
let kwh = energy.energy_kwh(prediction.predicted_time_ms, 1);
let co2 = energy.carbon_grams(prediction.predicted_time_ms, 1);

println!("Single inference:");
println!("  Energy: {:.4} J ({:.8} kWh)", joules, kwh);
println!("  CO₂: {:.6} g", co2);

// Training: 8 GPUs for 72 hours
let train_ms = 72.0 * 3600.0 * 1000.0;
let train_kwh = energy.energy_kwh(train_ms, 8);
let train_co2_kg = energy.carbon_grams(train_ms, 8) / 1000.0;

println!("\nTraining (8× H100, 72h):");
println!("  Energy: {:.2} kWh", train_kwh);
println!("  CO₂: {:.2} kg", train_co2_kg);
println!("  Equivalent to: {:.0} km driven", train_co2_kg / 0.21);
}

13.3 Energy Profiles

ProfileGPU TDPCPU TDPCooling PUECO₂ (g/kWh)
EnergyModel::a100()400W250W1.1400 (world avg)
EnergyModel::h100()700W350W1.1400 (world avg)

13.4 Quantum Energy Estimation

#![allow(unused)]
fn main() {
let energy = EnergyModel::h100();

// Quantum circuit: dominated by cryogenic cooling
let circuit_time_us = 100.0;
let num_qubits = 127;
let quantum_joules = energy.quantum_energy_joules(circuit_time_us, num_qubits);

println!("Quantum energy: {:.4} J", quantum_joules);
println!("  Cryogenics: ~25 kW (dilution refrigerator)");
println!("  Control electronics: ~{:.0} W ({} qubits × 10W)", num_qubits as f64 * 10.0, num_qubits);
}

13.5 Compare Classical vs Quantum Energy

#![allow(unused)]
fn main() {
// Classical: matmul 1000×1000 on H100
let classical_time_ms = cost.compute_time_ms(2 * 1000 * 1000 * 1000);
let classical_j = energy.energy_joules(classical_time_ms, 1);

// Quantum: 100-gate circuit
let quantum_j = energy.quantum_energy_joules(100.0, 50);

println!("Classical (1000×1000 matmul): {:.4} J", classical_j);
println!("Quantum (100-gate circuit):   {:.4} J", quantum_j);
println!("Note: Quantum energy is dominated by cryogenic overhead,");
println!("not by the computation itself.");
}

14. Use Case 10 — Device Topology and Routing

14.1 Problem

Quantum hardware has limited connectivity — not all qubits can directly interact. Two-qubit gates between non-adjacent qubits require SWAP operations, increasing circuit depth and noise.

14.2 Built-in Topologies

#![allow(unused)]
fn main() {
use lift_quantum::DeviceTopology;

// Linear chain (nearest-neighbour)
let linear = DeviceTopology::linear(10);
println!("Linear: {} qubits, {} edges, diameter {}",
    linear.num_qubits, linear.edges.len(), linear.diameter());

// 2D Grid (superconducting chips)
let grid = DeviceTopology::grid(4, 4);
println!("Grid 4×4: {} qubits, avg connectivity {:.2}",
    grid.num_qubits, grid.avg_connectivity());

// IBM Heavy-hex (Eagle/Heron processors)
let heavy_hex = DeviceTopology::heavy_hex(127);
println!("Heavy-hex: {} qubits, {} edges",
    heavy_hex.num_qubits, heavy_hex.edges.len());

// All-to-all (trapped-ion systems)
let ion = DeviceTopology::all_to_all(32);
println!("All-to-all: {} qubits, {} edges, diameter {}",
    ion.num_qubits, ion.edges.len(), ion.diameter());

// Binary tree
let tree = DeviceTopology::tree(15);

// Custom topology
let custom = DeviceTopology::custom("my_chip",
    &[(0,1), (1,2), (2,3), (0,3), (1,3)], 0.995);
}
TopologyConstructorTypical Hardware
Linearlinear(n)Simple chains
Gridgrid(rows, cols)Google Sycamore
Heavy-hexheavy_hex(n)IBM Eagle/Heron
All-to-allall_to_all(n)IonQ, Quantinuum
Treetree(n)Hierarchical architectures
Customcustom(name, edges, fidelity)Any device

14.3 Routing and SWAP Cost

#![allow(unused)]
fn main() {
let topo = DeviceTopology::grid(5, 5);

// Are two qubits directly connected?
println!("0↔1 connected: {}", topo.are_connected(0, 1));  // true
println!("0↔6 connected: {}", topo.are_connected(0, 6));  // false

// Find shortest path between qubits
if let Some(path) = topo.shortest_path(0, 24) {
    println!("Path 0→24: {:?}", path);
    println!("SWAPs needed: {}", path.len() - 2);
}

// Number of SWAPs between any two qubits
let swaps = topo.swap_distance(0, 24);
println!("SWAP distance 0→24: {:?}", swaps);

// Neighbours of a qubit
println!("Neighbours of qubit 12: {:?}", topo.neighbors(12));

// Graph metrics
println!("Diameter: {}", topo.diameter());
println!("Avg connectivity: {:.2}", topo.avg_connectivity());
}

14.4 Layout Mapping Pass

The LayoutMapping pass automatically inserts SWAPs to match your device:

#![allow(unused)]
fn main() {
use lift_opt::LayoutMapping;
use lift_core::pass::PassManager;

let mut pm = PassManager::new();
pm.add_pass(Box::new(LayoutMapping));
pm.run_all(&mut ctx);
}

15. Use Case 11 — Diffusion and GNN Models

15.1 Diffusion Models (Stable Diffusion)

Problem: Diffusion models use UNet architectures with timestep conditioning and cross-attention. Standard tensor frameworks lack first-class support.

#dialect tensor

module @unet_step {
    func @denoise(%x: tensor<1x4x64x64xf32>, %t: tensor<1xf32>,
                  %context: tensor<1x77x768xf32>) -> tensor<1x4x64x64xf32> {
        // Timestep embedding
        %t_emb = "tensor.timestep_embedding"(%t)
            : (tensor<1xf32>) -> tensor<1x320xf32>

        // UNet down block (conv + attention)
        %d1 = "tensor.unet_down_block"(%x, %t_emb)
            : (tensor<1x4x64x64xf32>, tensor<1x320xf32>) -> tensor<1x320x32x32xf32>

        // Cross-attention with text context
        %attn = "tensor.cross_attention"(%d1, %context, %context)
            : (tensor<1x320x32x32xf32>, tensor<1x77x768xf32>, tensor<1x77x768xf32>)
            -> tensor<1x320x32x32xf32>

        // UNet up block (transpose conv + skip connections)
        %u1 = "tensor.unet_up_block"(%attn, %t_emb)
            : (tensor<1x320x32x32xf32>, tensor<1x320xf32>) -> tensor<1x4x64x64xf32>

        return %u1
    }
}

Diffusion-specific ops:

OperationDescription
tensor.timestep_embeddingSinusoidal timestep encoding
tensor.unet_down_blockDownsample with residual + attention
tensor.unet_up_blockUpsample with skip connections

15.2 Graph Neural Networks (GNN)

Problem: GNNs operate on irregular graph structures. Message passing between nodes requires specialised aggregation operations.

#dialect tensor

module @gcn {
    func @forward(%nodes: tensor<100x64xf32>,
                  %edges: tensor<2x500xi64>,
                  %w: tensor<64x32xf32>) -> tensor<100x32xf32> {
        // Message passing: aggregate neighbour features
        %msg = "tensor.gnn_message_passing"(%nodes, %edges)
            {aggregation = "mean"}
            : (tensor<100x64xf32>, tensor<2x500xi64>) -> tensor<100x64xf32>

        // Linear transform
        %h = "tensor.matmul"(%msg, %w)
            : (tensor<100x64xf32>, tensor<64x32xf32>) -> tensor<100x32xf32>
        %out = "tensor.relu"(%h)
            : (tensor<100x32xf32>) -> tensor<100x32xf32>
        return %out
    }

    func @graph_classify(%nodes: tensor<100x32xf32>) -> tensor<1x32xf32> {
        // Global pooling: graph-level representation
        %graph = "tensor.gnn_global_pooling"(%nodes)
            {aggregation = "mean"}
            : (tensor<100x32xf32>) -> tensor<1x32xf32>
        return %graph
    }
}

GNN operations:

OperationDescriptionAggregation
tensor.gnn_message_passingNeighbour feature aggregationsum, mean, max, min
tensor.gnn_global_poolingGraph-level readoutsum, mean, max

16. Use Case 12 — Budget-Constrained Compilation

16.1 Problem

You have hard resource constraints: maximum FLOPs, memory, time, or minimum quantum fidelity. You want to enforce these during compilation.

16.2 Static Budget

#![allow(unused)]
fn main() {
use lift_sim::cost::Budget;
use lift_sim::analysis::analyze_module;

let budget = Budget {
    max_flops: Some(1_000_000_000),          // 1 GFLOP
    max_memory_bytes: Some(1_073_741_824),   // 1 GB
    max_time_ms: Some(100.0),                // 100 ms
    min_fidelity: Some(0.99),                // 99% fidelity
    max_circuit_depth: Some(100),
};

let report = analyze_module(&ctx);

match budget.check_flops(report.total_flops) {
    Ok(()) => println!("FLOP budget OK"),
    Err(e) => println!("WARNING: {}", e),
}

match budget.check_memory(report.total_memory_bytes) {
    Ok(()) => println!("Memory budget OK"),
    Err(e) => println!("WARNING: {}", e),
}
}

16.3 Reactive Budget (Dynamic Tracking)

For iterative algorithms (VQE, QAOA) where resources are consumed over time:

#![allow(unused)]
fn main() {
use lift_sim::cost::{Budget, ReactiveBudget};

let budget = Budget {
    max_flops: Some(10_000_000_000),       // 10 GFLOP
    max_memory_bytes: Some(4_294_967_296), // 4 GB
    max_time_ms: Some(5000.0),             // 5 seconds
    min_fidelity: Some(0.90),              // 90% fidelity
    max_circuit_depth: None,
};

let mut tracker = ReactiveBudget::new(budget);

for iteration in 0..100 {
    // Simulate consuming resources each iteration
    tracker.consume(
        100_000_000,  // 100M FLOPs
        500_000_000,  // 500MB memory
        50.0,         // 50ms
        0.999,        // fidelity factor
    );

    match tracker.check_remaining() {
        Ok(()) => {
            let util = tracker.utilisation();
            if iteration % 10 == 0 {
                println!("Iter {}: FLOP {:.0}%, time {:.0}%",
                    iteration,
                    util.flop_ratio.unwrap_or(0.0) * 100.0,
                    util.time_ratio.unwrap_or(0.0) * 100.0,
                );
            }
        }
        Err(e) => {
            println!("Budget exceeded at iteration {}: {}", iteration, e);
            break;
        }
    }
}

// Query remaining budget
if let Some(remaining) = tracker.remaining_flops() {
    println!("Remaining FLOPs: {}", remaining);
}
if let Some(remaining) = tracker.remaining_time_ms() {
    println!("Remaining time: {:.2} ms", remaining);
}
}

17. Use Case 13 — End-to-End Pipelines

17.1 AI Pipeline: Import → Verify → Optimise → Predict → Export

#![allow(unused)]
fn main() {
use lift_import::OnnxImporter;
use lift_core::{verifier, pass::PassManager};
use lift_sim::analysis::analyze_module;
use lift_sim::cost::CostModel;
use lift_predict::roofline::predict_performance;
use lift_export::LlvmExporter;

// ── 1. Import ──
let mut ctx = OnnxImporter::new()
    .import("model.onnx").expect("Import failed");

// ── 2. Verify ──
verifier::verify(&ctx).expect("Verification failed");

// ── 3. Analyse (before) ──
let before = analyze_module(&ctx);

// ── 4. Optimise ──
let mut pm = PassManager::new();
pm.add_pass(Box::new(lift_opt::Canonicalize));
pm.add_pass(Box::new(lift_opt::ConstantFolding));
pm.add_pass(Box::new(lift_opt::TensorFusion));
pm.add_pass(Box::new(lift_opt::FlashAttentionPass::default()));
pm.add_pass(Box::new(lift_opt::CommonSubexprElimination));
pm.add_pass(Box::new(lift_opt::DeadCodeElimination));

for (name, result) in pm.run_all(&mut ctx) {
    println!("  {}: {:?}", name, result);
}

// ── 5. Analyse (after) ──
let after = analyze_module(&ctx);
println!("Ops: {} → {} ({:.1}% reduction)",
    before.num_ops, after.num_ops,
    (1.0 - after.num_ops as f64 / before.num_ops as f64) * 100.0);

// ── 6. Predict ──
let h100 = CostModel::h100();
let prediction = predict_performance(&after, &h100);
println!("H100: {:.4} ms ({}-bound)", prediction.predicted_time_ms, prediction.bottleneck);

// ── 7. Export ──
let llvm = LlvmExporter::new().export(&ctx).expect("Export failed");
std::fs::write("model.ll", &llvm).unwrap();
println!("Exported {} bytes of LLVM IR", llvm.len());
}

17.2 Quantum Pipeline: Parse → Verify → Optimise → Predict → Export

#![allow(unused)]
fn main() {
use lift_ast::{Lexer, Parser, IrBuilder};
use lift_core::{Context, verifier, pass::PassManager};
use lift_sim::cost::QuantumCostModel;
use lift_export::QasmExporter;

// ── 1. Parse ──
let source = std::fs::read_to_string("circuit.lif").unwrap();
let tokens = Lexer::new(&source).tokenize().to_vec();
let program = Parser::new(tokens).parse().unwrap();
let mut ctx = Context::new();
IrBuilder::new().build_program(&mut ctx, &program).unwrap();

// ── 2. Verify (SSA + linearity) ──
verifier::verify(&ctx).expect("Circuit verification failed");

// ── 3. Optimise ──
let mut pm = PassManager::new();
pm.add_pass(Box::new(lift_opt::GateCancellation));
pm.add_pass(Box::new(lift_opt::RotationMerge));
pm.add_pass(Box::new(lift_opt::NoiseAwareSchedule));
pm.add_pass(Box::new(lift_opt::LayoutMapping));

for (name, result) in pm.run_all(&mut ctx) {
    println!("  {}: {:?}", name, result);
}

// ── 4. Predict fidelity ──
let sc = QuantumCostModel::superconducting_default();
let fidelity = sc.circuit_fidelity(30, 10); // 30×1Q + 10×2Q
println!("Predicted fidelity: {:.6}", fidelity);

// ── 5. Export to OpenQASM 3.0 ──
let qasm = QasmExporter::new().export(&ctx).unwrap();
std::fs::write("circuit.qasm", &qasm).unwrap();
}

17.3 Hybrid Pipeline: VQE with Energy Estimation

#![allow(unused)]
fn main() {
use lift_core::{Context, Attributes, Location};
use lift_sim::cost::{CostModel, QuantumCostModel, EnergyModel, Budget, ReactiveBudget};
use lift_hybrid::gradient::GradientMethod;
use lift_hybrid::encoding::{EncodingStrategy, EncodingConfig};

// ── Setup ──
let encoding = EncodingConfig::new(EncodingStrategy::AngleEncoding, 4);
let gradient = GradientMethod::ParameterShift;
let num_params = 12;

println!("Encoding: {} qubits, depth {}",
    encoding.num_qubits, encoding.strategy.circuit_depth(4));
println!("Gradient: {} evaluations per iteration",
    gradient.circuit_evaluations(num_params));

// ── Budget ──
let budget = Budget {
    max_flops: None,
    max_memory_bytes: None,
    max_time_ms: Some(60_000.0),  // 60 seconds
    min_fidelity: Some(0.80),
    max_circuit_depth: None,
};
let mut tracker = ReactiveBudget::new(budget);

// ── Cost models ──
let qcm = QuantumCostModel::superconducting_default();
let energy = EnergyModel::a100();

// ── VQE loop ──
let evals_per_iter = gradient.circuit_evaluations(num_params);
let time_per_eval_us = qcm.circuit_time_us(10, 5, 1, 8);
let fidelity_per_eval = qcm.circuit_fidelity(10, 5);

for iter in 0..100 {
    let iter_time_ms = (evals_per_iter as f64 * time_per_eval_us) / 1000.0;
    tracker.consume(0, 0, iter_time_ms, fidelity_per_eval);

    if let Err(e) = tracker.check_remaining() {
        println!("Stopped at iteration {}: {}", iter, e);
        break;
    }
}

println!("Total time: {:.2} ms", tracker.elapsed_ms);
println!("Final fidelity: {:.6}", tracker.current_fidelity);
let total_energy_j = energy.quantum_energy_joules(
    tracker.elapsed_ms * 1000.0, encoding.num_qubits);
println!("Energy: {:.2} J", total_energy_j);
}

18. Configuration with .lith Files

18.1 Overview

LIFT uses .lith configuration files to control the compilation pipeline. The format is INI-like with [section] headers and key = value pairs. Comments use # or //.

18.2 Full .lith Example

# my_project.lith — LIFT compilation configuration

[target]
backend = "llvm"        # llvm | qasm
device = "H100"         # A100 | H100
precision = "fp16"      # fp32 | fp16 | bf16 | fp8 | int8

[budget]
max_flops = 1000000000000    # 1 TFLOP
max_memory_bytes = 80000000000  # 80 GB
max_time_ms = 100.0          # 100 ms
min_fidelity = 0.95          # 95% quantum fidelity

[optimisation]
level = O3                   # O0 | O1 | O2 | O3
max_iterations = 20

[simulation]
shape_propagation = true
flop_counting = true
memory_analysis = true
noise_simulation = true

[quantum]
topology = "heavy_hex"
num_qubits = 127
shots = 4096
error_mitigation = "zne"     # zero-noise extrapolation

18.3 Configuration Sections

SectionKeysDescription
[target]backend, device, precisionCompilation target
[budget]max_flops, max_memory_bytes, max_time_ms, min_fidelity, max_circuit_depthResource constraints
[optimisation]level, passes, disabled_passes, max_iterationsPass pipeline control
[simulation]shape_propagation, flop_counting, memory_analysis, noise_simulationAnalysis toggles
[quantum]topology, num_qubits, error_mitigation, shotsQuantum device settings

18.4 Optimisation Levels

LevelPasses
O0No optimisation
O1Canonicalize, DCE
O2Canonicalize, constant folding, DCE, tensor fusion (default)
O3All passes including FlashAttention, CSE, gate cancellation, rotation merge

18.5 Loading Configuration Programmatically

#![allow(unused)]
fn main() {
use lift_config::{ConfigParser, LithConfig};

// From .lith file
let source = std::fs::read_to_string("project.lith").unwrap();
let config = ConfigParser::new().parse(&source).expect("Config parse error");

println!("Backend: {}", config.target.backend);
println!("Opt level: {:?}", config.optimisation.level);

if let Some(q) = &config.quantum {
    println!("Quantum: {} qubits, {} topology", q.num_qubits, q.topology);
}

// From JSON
let json = r#"{"target":{"backend":"qasm","device":null,"precision":"fp32"},
               "budget":{"max_flops":null,"max_memory_bytes":null,
                         "max_time_ms":null,"min_fidelity":0.99,
                         "max_circuit_depth":null},
               "optimisation":{"level":"O2","passes":["canonicalize","dce"],
                               "disabled_passes":[],"max_iterations":10},
               "simulation":{"enable_shape_propagation":true,
                             "enable_flop_counting":true,
                             "enable_memory_analysis":true,
                             "enable_noise_simulation":true},
               "quantum":{"topology":"grid","num_qubits":27,
                          "error_mitigation":null,"shots":4096}}"#;

let config = ConfigParser::new().parse_json(json).expect("JSON parse error");
}

18.6 Default Configuration

When no .lith file is provided, LIFT uses these defaults:

#![allow(unused)]
fn main() {
let config = LithConfig::default();
// target.backend = "llvm"
// target.precision = "fp32"
// optimisation.level = O2
// optimisation.passes = ["canonicalize", "constant-folding", "dce", "tensor-fusion"]
// simulation: all enabled
// quantum: None
}

19. CLI Reference

19.1 Installation

After building with cargo build --release, the CLI binary is at target/release/lift.

19.2 Commands

lift verify — Verify a .lif file

Checks SSA invariants, type correctness, and qubit linearity.

lift verify examples/tensor_mlp.lif

Output:

Verification passed: examples/tensor_mlp.lif
  Values: 11
  Operations: 6
  Blocks: 1
  Regions: 1
# Verbose mode
lift -v verify examples/quantum_bell.lif

lift analyse — Analyse resource usage

Computes FLOPs, memory, gate counts, and fidelity estimates.

lift analyse examples/tensor_mlp.lif

Output:

=== LIFT Analysis Report ===
File: examples/tensor_mlp.lif

Operations: 6
  Tensor ops: 6
  Quantum ops: 0
  Hybrid ops: 0

Compute:
  Total FLOPs: 803.33 KFLOP
  Total memory: 3.10 MiB
  Peak memory: 3.10 MiB

Op breakdown:
  tensor.matmul: 2
  tensor.add: 2
  tensor.relu: 1
  tensor.softmax: 1

JSON output:

lift analyse examples/tensor_mlp.lif --format json

lift print — Print human-readable IR

lift print examples/quantum_bell.lif

Output:

module @bell_state {
    func @bell(%v0: qubit, %v1: qubit) -> (qubit, qubit) {
    ^bb0(%v0: qubit, %v1: qubit):
        %v2 = "quantum.h"(%v0) : (qubit) -> qubit
        %v3, %v4 = "quantum.cx"(%v2, %v1) : (qubit, qubit) -> (qubit, qubit)
    }
}

lift optimise — Run optimisation passes

# Default passes (O2)
lift optimise examples/tensor_mlp.lif -o optimised.lif

# With custom config
lift optimise examples/tensor_mlp.lif --config project.lith -o optimised.lif

Output:

Optimisation results:
  canonicalize -> unchanged
  constant-folding -> unchanged
  dce -> unchanged
  tensor-fusion -> changed
Output written to: optimised.lif

lift predict — Predict performance

# Predict on A100 (default)
lift predict examples/tensor_mlp.lif

# Predict on H100
lift predict examples/tensor_mlp.lif --device h100

Output:

=== LIFT Performance Prediction ===
Device: H100

Compute time: 0.0000 ms
Memory time: 0.0009 ms
Predicted time: 0.0009 ms
Arithmetic intensity: 266.67 FLOP/byte
Bottleneck: memory

lift export — Export to backend

# Export to LLVM IR
lift export examples/tensor_mlp.lif --backend llvm -o model.ll

# Export to ONNX (opset 21)
lift export examples/tensor_mlp.lif --backend onnx -o model.onnx

# Export to OpenQASM 3.0
lift export examples/quantum_bell.lif --backend qasm -o circuit.qasm

# Print to stdout
lift export examples/quantum_bell.lif --backend qasm

19.3 Global Flags

FlagDescription
-v, --verboseEnable debug-level logging
--versionPrint version
--helpPrint help

20. Programmatic Model Generation

20.1 Using lift-codegen

The lift-codegen binary generates models from Rust code and exports all formats automatically:

cargo run --bin lift-codegen

Output:

╔═════════════════════════════════════════════════════════════╗
║  LIFT Code Generator — Models from Rust                      ║
╚═════════════════════════════════════════════════════════════╝

── Generating Phi-3-mini ──
  [WRITE] examples/phi3_generated.lif (2703 bytes)
  [VERIFY] OK — 20 ops, 32 values
  [ANALYSE] FLOPs=54.43 GFLOP, Memory=1.23 GiB, Ops=20
  [OPTIMISE] No changes
  [EXPORT] examples/phi3_generated.ll (5217 bytes)
  [EXPORT] examples/phi3_generated.onnx (10563 bytes)

── Generating VQE Circuit ──
  [WRITE] examples/vqe_generated.lif (345 bytes)
  [VERIFY] OK — 5 ops, 6 values
  [ANALYSE] FLOPs=0 FLOP, Memory=0 B, Ops=5
  [OPTIMISE] No changes
  [EXPORT] examples/vqe_generated.ll (3138 bytes)
  [EXPORT] examples/vqe_generated.onnx (2023 bytes)
  [EXPORT] examples/vqe_generated.qasm (120 bytes)

20.2 ModelBuilder API

Define models programmatically without writing .lif files:

#![allow(unused)]
fn main() {
use lift_core::model_builder::{ModelBuilder, tensor, tensor_2d, DataType};

let model = ModelBuilder::new("my_mlp")
    .function("forward")
        .param("x", tensor(&[1, 784], DataType::FP32))
        .param("w1", tensor_2d(784, 256, DataType::FP32))
        .param("b1", tensor(&[256], DataType::FP32))
        .op("tensor.matmul", &["x", "w1"], "h1", tensor(&[1, 256], DataType::FP32))
        .op("tensor.add", &["h1", "b1"], "h2", tensor(&[1, 256], DataType::FP32))
        .op("tensor.relu", &["h2"], "out", tensor(&[1, 256], DataType::FP32))
        .returns("out")
        .done();

// Write .lif source (parseable by lift-cli)
model.write_lif("my_mlp.lif").unwrap();

// Build IR context for full pipeline
let ctx = model.build_context();
lift_core::verifier::verify(&ctx).unwrap();

// Export to all backends
let llvm = lift_export::LlvmExporter::new().export(&ctx).unwrap();
let onnx = lift_export::OnnxExporter::new().export(&ctx).unwrap();
std::fs::write("my_mlp.ll", &llvm).unwrap();
std::fs::write("my_mlp.onnx", &onnx).unwrap();
}

21. Complete API Reference

21.1 Crate Overview

CratePurpose
lift-coreIR foundation: Context, types, values, operations, blocks, regions, verifier, printer, pass manager
lift-astLexer, parser, IR builder for .lif files
lift-tensorTensor operations (110), shape inference, FLOPs computation
lift-quantumQuantum gates (48), noise models, topology, QEC codes, Kraus channels
lift-hybridHybrid operations (21), encoding strategies, gradient methods
lift-optOptimisation passes (11): canonicalize, fusion, FlashAttention, gate cancellation, etc.
lift-simCost models (GPU + QPU), analysis reports, energy models, budgets
lift-predictRoofline prediction (classical), quantum prediction (fidelity + shots)
lift-importImporters: ONNX, PyTorch FX, OpenQASM 3.0
lift-exportExporters: LLVM IR, ONNX (opset 21), OpenQASM 3.0
lift-config.lith configuration parser
lift-cliCommand-line interface
lift-codegenProgrammatic model generation binary

20.2 lift-core API

Context — central IR container:

MethodDescription
Context::new()Create empty IR context
ctx.intern_string(s)StringIdIntern a string
ctx.resolve_string(id)&strResolve interned string
ctx.intern_type(ty)TypeIdIntern a type
ctx.resolve_type(id)&CoreTypeResolve interned type
ctx.make_integer_type(bits, signed)TypeIdCreate integer type
ctx.make_float_type(bits)TypeIdCreate float type
ctx.make_boolean_type()TypeIdCreate boolean type
ctx.make_tensor_type(shape, dtype, layout)TypeIdCreate tensor type
ctx.make_qubit_type()TypeIdCreate qubit type
ctx.make_bit_type()TypeIdCreate classical bit type
ctx.make_void_type()TypeIdCreate void type
ctx.make_index_type()TypeIdCreate index type
ctx.create_block()BlockKeyCreate a new block
ctx.create_block_arg(block, ty)ValueKeyAdd block argument
ctx.create_op(name, dialect, inputs, types, attrs, loc)(OpKey, Vec<ValueKey>)Create operation
ctx.add_op_to_block(block, op)Add op to block
ctx.create_region()RegionKeyCreate a region
ctx.create_module(name)usizeCreate a module
ctx.snapshot()Snapshot context state

Verifier:

FunctionDescription
verifier::verify(&ctx)Result<(), Vec<VerifyError>>Verify the full IR

Printer:

FunctionDescription
printer::print_ir(&ctx)StringPrint IR as text

Pass Manager:

MethodDescription
PassManager::new()Create pass manager
pm.add_pass(Box<dyn Pass>)Register a pass
pm.run_all(&mut ctx)Vec<(String, PassResult)>Run all passes

Types:

TypeVariants
CoreTypeInteger, Float, Boolean, Tuple, Function, Opaque, Void, Index
TypeDataNone, Tensor(TensorTypeInfo), Qubit, ClassicalBit, Hamiltonian, QuantumState
DataTypeFP32, FP16, BF16, FP64, INT8, INT16, INT32, INT64, UINT8, Bool
DimensionConstant(usize), Dynamic
MemoryLayoutContiguous, Strided, Blocked

Attributes:

TypeVariants
AttributeInteger(i64), Float(f64), String(StringId), Bool(bool), Type(TypeId), Array(Vec), Dict(HashMap)
Attributes.set(key, attr), .get(key), .get_integer(key), .get_float(key), .get_bool(key)

20.3 lift-tensor API

ItemDescription
TensorOp enum110 tensor operations
TensorOp::name()&strGet string name
TensorOp::from_name(s)Option<TensorOp>Parse from string
TensorOp::num_inputs()(usize, usize)Min/max input count
TensorOp::flops_formula()&strTheoretical FLOPs formula
TensorOp::is_zero_flop()boolTrue for shape-only ops
TensorOp::is_activation()boolTrue for activation ops
TensorOp::is_attention()boolTrue for attention variants
TensorOp::is_convolution()boolTrue for conv ops
TensorOp::is_fused()boolTrue for fused kernels
TensorOp::is_gradient()boolTrue for gradient ops
ShapeInference::infer_output_shape(op, inputs)Result<Vec<TensorTypeInfo>>Infer output shapes
ShapeInference::compute_flops(op, inputs)Option<u64>Count FLOPs
ShapeInference::compute_memory_bytes(op, inputs)Option<u64>Estimate memory

20.4 lift-quantum API

ItemDescription
QuantumGate enum48 quantum gates
QuantumGate::op_name()&strGet gate name (e.g. "quantum.h")
QuantumGate::from_name(s)Option<QuantumGate>Parse from string
QuantumGate::num_qubits()usizeGate arity
QuantumGate::is_parametric()boolRequires angle parameters
QuantumGate::is_self_inverse()boolG·G = I
QuantumGate::is_clifford()boolIn Clifford group
QuantumGate::is_measurement()boolMeasurement or control
QuantumGate::is_entangling()boolCreates entanglement
QuantumGate::native_basis(provider)&[QuantumGate]Hardware-native gates
Provider enumIbmEagle, IbmKyoto, Rigetti, IonQ, Quantinuum, Generic
NoiseModel enumIdeal, Depolarizing, AmplitudeDamping, PhaseDamping, BitFlip, PhaseFlip, ThermalRelaxation, Kraus, Composed
NoiseModel::fidelity()f64Compute fidelity
NoiseModel::compose(other)NoiseModelChain noise models
GateNoise::ideal()Perfect gate
GateNoise::with_depolarizing(f, t)Gate with depolarizing noise
CircuitNoise::new()Track circuit-level noise
CircuitNoise::add_gate(noise, is_2q)Add gate to circuit
CircuitNoise::meets_threshold(min)boolCheck fidelity threshold
DeviceTopology::linear(n)Linear chain
DeviceTopology::grid(r, c)2D grid
DeviceTopology::heavy_hex(n)IBM heavy-hex
DeviceTopology::all_to_all(n)Full connectivity
DeviceTopology::tree(n)Binary tree
DeviceTopology::custom(name, edges, fid)Custom topology
topo.are_connected(q0, q1)boolCheck edge
topo.neighbors(q)Vec<usize>Get neighbours
topo.shortest_path(from, to)Option<Vec<usize>>BFS path
topo.swap_distance(from, to)Option<usize>SWAP count
topo.diameter()usizeGraph diameter
topo.avg_connectivity()f64Average degree

20.5 lift-hybrid API

ItemDescription
HybridOp enum21 hybrid operations
HybridOp::op_name()&strGet op name
HybridOp::from_name(s)Option<HybridOp>Parse from string
HybridOp::is_gradient()boolGradient op?
HybridOp::is_variational()boolVariational algorithm?
EncodingStrategy enumAngleEncoding, AmplitudeEncoding, BasisEncoding, IQPEncoding, HamiltonianEncoding, KernelEncoding
EncodingStrategy::qubits_required(dim)usizeQubits needed
EncodingStrategy::circuit_depth(dim)usizeCircuit depth
EncodingConfig::new(strategy, dim)Create config
GradientMethod enumParameterShift, FiniteDifference, SPSA, Adjoint, Backprop
GradientMethod::circuit_evaluations(n)usizeEvaluations needed
GradientMethod::is_exact()boolExact gradient?
JointGradientConfigCombined classical+quantum gradients
JointGradientConfig::total_evaluations()usizeTotal eval count
AnsatzType enumHardwareEfficient, StronglyEntangling, TwoLocal, UCCSD, Custom
SyncPolicy enumBlocking, Asynchronous, Pipeline
FeatureMap enumZZFeatureMap, PauliFeatureMap, AngleEncoding, AmplitudeEncoding

20.6 lift-opt Passes

PassNameDescription
Canonicalize"canonicalize"Simplify: x+0→x, x×1→x, reshape(reshape(x))→reshape(x)
ConstantFolding"constant-folding"Evaluate constant expressions at compile time
DeadCodeElimination"dce"Remove unused operations
TensorFusion"tensor-fusion"Fuse matmul+bias+relu into single kernel
GateCancellation"gate-cancellation"Cancel adjacent inverse gates (H·H→I)
RotationMerge"rotation-merge"Merge rotations: Rz(a)·Rz(b)→Rz(a+b)
FlashAttentionPass"flash-attention"Replace attention with FlashAttention when seq_len > threshold
CommonSubexprElimination"cse"Eliminate duplicate computations
QuantisationPass"quantisation"Annotate quantisable operations
NoiseAwareSchedule"noise-aware-schedule"Reorder gates for minimal noise
LayoutMapping"layout-mapping"Map logical qubits to physical topology

20.7 lift-sim API

ItemDescription
CostModel::a100()NVIDIA A100 profile (312 TFLOPS, 2039 GB/s, 80GB)
CostModel::h100()NVIDIA H100 profile (989 TFLOPS, 3350 GB/s, 80GB)
model.compute_time_ms(flops)f64Compute-only time
model.memory_time_ms(bytes)f64Memory-only time
model.roofline_time_ms(flops, bytes)f64Roofline prediction
model.arithmetic_intensity(flops, bytes)f64FLOP/byte ratio
model.is_compute_bound(flops, bytes)boolCompute or memory bound
model.fits_in_memory(bytes)boolFits in GPU VRAM
model.num_gpus_needed(bytes)usizeGPUs required
QuantumCostModel::superconducting_default()IBM-like QPU
QuantumCostModel::trapped_ion_default()IonQ-like QPU
QuantumCostModel::neutral_atom_default()Neutral-atom QPU
qcm.circuit_fidelity(n_1q, n_2q)f64Gate fidelity product
qcm.circuit_time_us(n_1q, n_2q, n_meas, depth)f64Execution time
qcm.decoherence_fidelity(time_us)f64Decoherence fidelity
EnergyModel::a100() / ::h100()Energy profiles
energy.energy_joules(time_ms, gpus)f64Energy in joules
energy.energy_kwh(time_ms, gpus)f64Energy in kWh
energy.carbon_grams(time_ms, gpus)f64CO₂ in grams
energy.quantum_energy_joules(time_us, qubits)f64Quantum energy
Budget structStatic resource constraints
budget.check_flops(n) / check_memory(n) / check_fidelity(f)Constraint checks
ReactiveBudget::new(budget)Dynamic budget tracker
tracker.consume(flops, mem, time, fidelity)Record usage
tracker.check_remaining()Result<()>Check all constraints
tracker.remaining_flops() / remaining_time_ms()Remaining budget
tracker.utilisation()BudgetUtilisationUsage ratios
analyze_module(&ctx)AnalysisReportFull module analysis
analyze_block(&ctx, block)AnalysisReportSingle block analysis

20.8 lift-predict API

ItemDescription
predict_performance(report, cost_model)RooflineResultClassical roofline prediction
predict_quantum(analysis, qcm, precision)QuantumPredictionQuantum performance prediction
RooflineResult.compute_time_ms, .memory_time_ms, .predicted_time_ms, .arithmetic_intensity, .is_compute_bound, .bottleneck
QuantumPrediction.estimated_fidelity, .circuit_time_us, .num_shots_for_precision, .total_execution_time_ms

21. Troubleshooting

21.1 Common Verification Errors

ErrorCauseFix
SSA violation: value used but not definedUsing a %name that was never createdEnsure all operands are defined before use
SSA violation: value defined more than onceTwo operations produce the same valueUse unique result names
Dominance violationUsing a value before its defining op in block orderReorder operations so definitions come before uses
Type mismatchInput types don't match operation signatureCheck tensor shapes and data types
Linearity violation: qubit consumed more than onceA qubit value used as input to two operationsEach qubit must be consumed exactly once
Linearity violation: qubit not consumed (leaked)A qubit is created but never usedEnsure all qubits are measured or returned
Missing terminatorA block has no return or branch at the endAdd a terminator operation

21.2 Common Parse Errors

ErrorCauseFix
Unexpected tokenSyntax error in .lif fileCheck operation format: %r = "dialect.op"(%args) : (types) -> type
Unknown typeType name not recognisedUse tensor<...>, qubit, bit, f32, i64, bool
Unresolved dialectUsing an op without declaring the dialectAdd #dialect tensor, #dialect quantum, or #dialect hybrid at file top

21.3 Optimisation Issues

IssueCauseFix
Fusion not appliedPattern not matched (e.g. different order)Ensure matmul → add → relu pattern is present
FlashAttention not appliedseq_len attribute missing or below thresholdSet seq_len attribute on attention ops, or lower threshold
Pass returns ErrorIR is in invalid stateRun verify before optimisation

21.4 Performance Debugging

#![allow(unused)]
fn main() {
// Check if compute-bound or memory-bound
let model = CostModel::a100();
let report = analyze_module(&ctx);

if model.is_compute_bound(report.total_flops, report.total_memory_bytes) {
    println!("Compute-bound: reduce FLOPs (quantise, prune, fuse)");
} else {
    println!("Memory-bound: reduce data movement (fusion, recomputation)");
}

// Check per-op breakdown
for (op, count) in &report.op_breakdown {
    println!("  {}: {} instances", op, count);
}
}

21.5 Quantum Debugging

#![allow(unused)]
fn main() {
use lift_quantum::{CircuitNoise, GateNoise};

// Track where fidelity drops
let mut circuit = CircuitNoise::new();
let g1q = GateNoise::with_depolarizing(0.999, 0.02);
let g2q = GateNoise::with_depolarizing(0.99, 0.3);

// After each gate, check fidelity
circuit.add_gate(&g1q, false);
println!("After H: fidelity = {:.6}", circuit.total_fidelity);

circuit.add_gate(&g2q, true);
println!("After CX: fidelity = {:.6}", circuit.total_fidelity);

// 2Q gates dominate fidelity loss!
}

Appendix A — Summary of All Operations

DialectCountCategories
tensor110Arithmetic, activations, normalisation, shape, attention, convolution, pooling, recurrent, math, sparse, quantisation, diffusion, GNN, memory, gradient, parallelism, fused
quantum481Q standard, 1Q parametric, 1Q fixed, 2Q standard, 2Q parametric, IonQ native, 3Q, multi-controlled, measurement, special
hybrid21Encoding, gradient methods, processing, variational, data transfer, co-execution, measurement

Total: 174+ operations across three dialects in a single unified IR.


Appendix B — Quick Reference Card

# Parse and verify
lift verify input.lif

# Analyse (FLOPs, memory, gates)
lift analyse input.lif

# Optimise with default passes
lift optimise input.lif -o optimised.lif

# Optimise with config
lift optimise input.lif --config project.lith -o optimised.lif

# Predict performance on H100
lift predict input.lif --device h100

# Export to LLVM
lift export input.lif --backend llvm -o model.ll

# Export to OpenQASM
lift export input.lif --backend qasm -o circuit.qasm

LIFT v0.4.3 — MIT License — https://github.com/rustnew/Lift

LIFT — Fonctionnalités, Capacités, Limites et Objectifs

Analyse complète basée sur le code source réel (67 fichiers Rust, 13 crates, 505 tests).


Table des matières

  1. Vue d'ensemble
  2. Pipeline de traitement
  3. Fonctionnalités implémentées
  4. Fonctionnalités partielles
  5. Fonctionnalités manquantes
  6. Limites actuelles
  7. Précision des analyses
  8. Ce qui manque pour les objectifs
  9. Feuille de route

1. Vue d'ensemble

LIFT est un compilateur IR unifié pour IA classique + calcul quantique, écrit en Rust (13 crates) :

CrateRôle
lift-coreNoyau : contexte IR, types, vérificateur, printer, pass manager
lift-astLexer, parser, builder pour fichiers .lif
lift-tensor110 opérations IA, inférence de forme, calcul FLOPs
lift-quantum50+ portes quantiques, bruit, Kraus, QEC, topologie
lift-hybrid21 opérations classique↔quantique
lift-opt13 passes d'optimisation
lift-simAnalyse statique, modèles de coût GPU/QPU, énergie
lift-predictPrédiction roofline, prédiction quantique
lift-configParseur fichiers .lith, pipeline par niveau O0-O3, provider quantique
lift-importImport ONNX, PyTorch FX, OpenQASM (squelettes)
lift-exportExport LLVM IR, ONNX (opset 21), OpenQASM 3.0
lift-cliCLI : verify, analyse, print, optimise, predict, export
lift-codegenGénération programmatique de modèles, export multi-format
lift-tests535 tests, 0 échecs

2. Pipeline de traitement

.lif → Lexer → Parser → Builder → Context IR → Vérification → Analyse → Optimisation → Export

Étape 1 — Lexer (COMPLET)

Découpe le texte .lif en tokens : mots-clés, directives #dialect, identifiants @name/%var, littéraux, ponctuation. Gestion d'erreurs incluse.

Étape 2 — Parser (COMPLET)

Construit l'AST : directives de dialecte, modules, fonctions, opérations avec opérandes/attributs/signatures de type. Types tensor (tensor<1x784xf32>), qubit, bit, hamiltonian. Recovery d'erreurs.

Étape 3 — Builder (COMPLET)

Convertit l'AST en IR interne dans le Context : valeurs SSA, opérations, blocs, régions, fonctions, modules.

Étape 4 — Context IR (COMPLET)

Structure centrale avec SlotMaps pour values, ops, blocks, regions, types + StringInterner. Types : Integer (i1-i64), Float (f16-f64, fp8), Boolean, Void, Tuple, Function, Opaque (tensor, qubit, bit, hamiltonian).

Étape 5 — Vérification (COMPLET, 4 passes)

  • SSA : chaque valeur définie une seule fois, chaque usage après définition
  • Bonne formation : aucune référence pendante (ops ↔ valeurs ↔ blocs ↔ régions)
  • Linéarité : chaque qubit consommé exactement une fois (no-cloning)
  • Sémantique : arité des entrées de chaque opération vérifiée contre les signatures des dialectes (core + tensor + quantum + hybrid), via verify_semantics() / verify_with_dialects()

13 types d'erreurs : UndefinedValue, MultipleDefinition, DominanceViolation, TypeMismatch, LinearityViolation, QubitLeaked, BranchLinearityMismatch, DanglingReference, MissingTerminator, OrphanedOperation, OrphanedBlock, InvalidOperation, SemanticError.

Étape 6 — Analyse statique (COMPLET)

Produit : total_flops, total_memory_bytes, peak_memory, num_ops par dialecte, op_breakdown. Quantique : qubits, portes 1Q/2Q/3Q, mesures, circuit_depth, estimated_fidelity, bruit accumulé.

Étape 7 — Optimisation (13 passes)

PasseTypeAction concrète
canonicalizeTensorNormalise les patterns
constant-foldingTensorÉvalue les constantes à la compilation
dceGénéralSupprime les ops dont les résultats sont inutilisés
tensor-fusionTensorFusionne matmul+add+relu → fused_matmul_bias_relu, linear+gelu → fused_linear_gelu, linear+silu → fused_linear_silu, conv2d+bn+relu (2 phases : ternaires puis binaires)
cseGénéralÉlimine les sous-expressions communes
flash-attentionTensorRemplace attention → flash attention
quantisation-passTensorAnnote pour quantisation INT8/INT4
gate-cancellationQuantumAnnule H·H=I, X·X=I, S·Sdg=I, T·Tdg=I — y compris paires non consécutives (séparées par des portes commutantes sur d'autres qubits, chaîne SSA vérifiée)
rotation-mergeQuantumFusionne Rz(a)·Rz(b) → Rz(a+b) — idem, paires non consécutives
noise-aware-scheduleQuantumRéordonne les portes pour minimiser décohérence
layout-mappingQuantumAnnote les portes 2-qubit nécessitant SWAPs
gate-decompositionQuantumDécompose H/T/Tdg/S/Sdg/Y/RX vers les jeux natifs du provider (IBM, Rigetti, IonQ, Quantinuum), piloté par [quantum] provider
real-routingQuantumInsère de vrais quantum.swap (BFS plus court chemin) pour satisfaire la connectivité de la topologie ; suivi placement logique↔physique

Pipelines par niveau ([optimisation] level = O0|O1|O2|O3) :

  • O0 : aucune passe
  • O1 : canonicalize, constant-folding, dce
  • O2 : O1 + cse, tensor-fusion
  • O3 : les 13 passes, incluant gate-decomposition et real-routing

passes explicites priorisent le niveau ; disabled_passes retire des passes ; les passes inconnues déclenchent un warning (OptimisationConfig::validate()). Toutes les passes sont accessibles depuis le CLI.

Étape 8 — Prédiction (COMPLET)

  • Roofline GPU : compute_time_ms, memory_time_ms, bottleneck. Modèles A100 (312 TFLOPS) et H100 (989 TFLOPS).
  • Quantique : fidélité, circuit_time_us, shots nécessaires. 3 modèles : superconducteur, ions piégés, atomes neutres.
  • Budget : vérifie FLOPs max, mémoire max, temps max, fidélité min. ReactiveBudget pour suivi en temps réel.

Étape 9 — Export (3 backends)

  • LLVM IR : ops émises en commentaires avec appels runtime cuBLAS/cuDNN
  • ONNX : protobuf text, opset 21, 70+ opérations mappées (standard + com.microsoft)
  • OpenQASM 3.0 : 10 portes sur 50+ (H, X, Y, Z, CX, CZ, Measure, RZ, RX, RY)

3. Fonctionnalités implémentées

3.1 Dialecte Tensor — 110 opérations

Toutes les 110 opérations sont définies dans l'enum TensorOp avec conversion nom↔enum, nombre d'entrées, classification. Inférence de forme fonctionnelle pour : MatMul, Linear, Conv2D, Conv1D, DepthwiseConv2D, Attention, FlashAttention, MaxPool2D, GlobalAvgPool, BatchNorm, LayerNorm, RMSNorm, InstanceNorm, SparseMatMul, élémentaire, ELU, LeakyReLU, Mish, HardSwish. Calcul FLOPs exact pour MatMul, Linear, Conv2D, Attention, ReLU, élémentaire, fused ops.

3.2 Dialecte Quantum — 50+ portes

Portes : 9 standard 1Q + 7 paramétriques 1Q + 2 angle fixe + 13 portes 2Q + 2 portes 3Q + 2 multi-contrôlées + 8 mesure/contrôle + portes IonQ. Propriétés par porte : num_qubits, is_parametric, is_self_inverse, is_clifford, is_entangling. 5 jeux natifs (IBM, Rigetti, IonQ, Quantinuum, Simulateur). Bruit : GateNoise, CircuitNoise, KrausChannel (6 canaux). Topologie : linear, grid, heavy_hex, all_to_all, tree, custom + BFS. QEC : Surface, Steane, Shor, Repetition, LDPC.

3.3 Dialecte Hybrid — 21 opérations

Encode/Decode, 5 gradients, 4 algorithmes variationnels, 2 transferts, 4 traitements, CoExecute, 2 mesures. AnsatzType, SyncPolicy, FeatureMap, EncodingStrategy.

3.4 CLI — 6 commandes

verify, analyse (texte/JSON), print, optimise (avec .lith), predict (A100/H100), export (llvm/onnx/qasm).

3.5 Génération programmatique — lift-codegen

Binaire lift-codegen : définit des modèles depuis Rust via ModelBuilder, génère automatiquement .lif, .ll, .onnx, .qasm, .lith. 4 modèles pré-définis (Phi-3-mini, MLP, ResNet, VQE).

3.6 Modèles d'énergie

EnergyModel A100/H100 : énergie joules/kWh, CO2 grammes, énergie quantique (cryogénie). Non connecté au CLI.

3.7 Tests — 535 tests, 0 échecs

Types, opérations, formes, FLOPs, mémoire, portes, bruit, topologie, QEC, Kraus, benchmarks (GPT-2, LLaMA-7B, ResNet-50, BERT-base), pipeline O0-O3, vérification sémantique, fusions génériques, décomposition de portes, cancellation/merge non consécutifs, routage réel SWAP. Validation de bout en bout : examples/validate_all.sh (105 checks, incluant les 13 passes).


4. Fonctionnalités partielles (code existe, incomplet)

4.1 Export LLVM IR — SQUELETTE

L'exporteur produit define void @func(ptr %arg0) { entry: ; tensor.matmul ret void }. Les opérations sont en commentaires, pas en vrai LLVM IR. Aucun appel cuBLAS/cuDNN, aucune gestion mémoire.

4.2 Export ONNX — OPÉRATIONNEL

L'exporteur ONNX produit du protobuf text (opset 21) avec 70+ opérations mappées vers les ops standard ONNX et com.microsoft. Les types de données, shapes et nœuds d'initialisation sont générés. Manque : la sérialisation binaire protobuf (actuellement texte uniquement), les graphes de nœuds connectés (les nœuds sont émis séquentiellement sans edges explicites).

4.3 Export OpenQASM — 10 portes sur 50+

Fonctionnel pour H, X, Y, Z, CX, CZ, Measure, RZ, RX, RY. Les 40+ autres → // unsupported gate. Le mapping qubit utilise un compteur, pas le vrai SSA.

4.4 Import ONNX/PyTorch/QASM — SQUELETTES

Les 3 importeurs lisent le format source mais créent un module+fonction vides. Aucun nœud/opération n'est réellement converti en opérations LIFT.

4.5 Layout Mapping — ANNOTATION

Ajoute needs_swap = true sur les portes 2Q non adjacentes. Ne fait pas l'insertion réelle de SWAPs ni le routage.

4.6 Passes non connectées au CLI

6 passes existent mais ne sont pas dans le match de cmd_optimise : rotation-merge, flash-attention, cse, quantisation-pass, noise-aware-schedule, layout-mapping.

4.7 Inférence de forme — PARTIELLE

Fonctionne pour environ 20 opérations sur 110. Manque : Conv3D, ConvTranspose2D, Reshape, Permute, Concat, Split, Slice, LSTM, GRU, RNN, FFT, SVD, Einsum, GNN, MoE, diffusion, quantisation, parallélisme.


5. Fonctionnalités manquantes

5.1 Pas de vérification sémantique des opérations

Le vérificateur vérifie SSA/bonne formation/linéarité mais ne vérifie PAS que tensor.matmul a 2 entrées tensor, que les dimensions sont compatibles, que tensor.conv2d reçoit un tensor 4D, etc.

5.2 Pas d'exécution réelle

LIFT ne peut pas exécuter de programme. C'est purement un compilateur d'analyse. Il n'y a pas de runtime, pas d'interpréteur, pas de backend d'exécution GPU/QPU.

5.3 Pas de simulation quantique réelle

Le module quantum_sim fait de l'analyse statique (comptage de portes, estimation de fidélité). Il ne simule PAS l'état quantique (pas de vecteur d'état, pas de matrice densité, pas de simulation Monte Carlo).

5.4 Pas de génération de code machine

L'export LLVM ne produit pas de code exécutable. Il faudrait : lowering des opérations tensor vers des appels de bibliothèques (cuBLAS, cuDNN, oneDNN), gestion mémoire (allocation/libération), ordonnancement des kernels, code de lancement GPU.

5.5 Pas de support multi-fichiers

Un programme LIFT = un seul fichier .lif. Pas de système d'import/include, pas de modules séparés, pas de linking.

5.6 Pas de décomposition de portes

LIFT ne décompose pas automatiquement les portes non natives vers le jeu natif du hardware cible. Les jeux natifs sont définis mais pas utilisés pour la transpilation.

5.7 Pas de scheduling GPU

Pas de placement des opérations sur des streams CUDA, pas de recouvrement calcul/mémoire, pas de parallélisme d'opérations.

5.8 Pas d'auto-différentiation

Les opérations de gradient sont déclarées (grad_matmul, grad_relu, etc.) mais il n'y a pas de système d'auto-différentiation qui construit automatiquement le graphe backward à partir du forward.

5.9 Pas de gestion de données

Pas de chargement de données (datasets), pas de data loaders, pas de preprocessing. LIFT travaille uniquement sur le graphe de calcul.


6. Limites actuelles

6.1 Limites structurelles

LimiteImpact
Pas d'exécutionLIFT analyse mais ne peut pas exécuter de modèle
Export squeletteLe code généré (LLVM/QASM) n'est pas exécutable en l'état
Import squeletteImpossible d'importer un vrai modèle ONNX/PyTorch
Pas de simulation QCFidélité estimée par formule, pas par simulation réelle
Énergie non connectéeLe modèle d'énergie existe mais n'est pas dans le CLI

6.2 Limites du modèle de coût

  • Le modèle roofline est une approximation grossière : il ne prend pas en compte les effets de cache, la latence de lancement des kernels, le recouvrement calcul/mémoire
  • Le modèle quantique utilise des paramètres de bruit moyens par défaut, pas les propriétés réelles du device cible
  • L'estimation de fidélité suppose un bruit indépendant par porte (pas de corrélations spatiales/temporelles)

6.3 Limites du vérificateur

  • Pas de vérification de types d'opérations (type des entrées vs signature)
  • Pas de vérification de compatibilité de dimensions (forme des tensors)
  • Pas de vérification de dominance complète (CFG)
  • La vérification de linéarité ne gère pas les branches conditionnelles de façon exhaustive
  • La vérification sémantique vérifie l'arité mais pas les dimensions tensorielles

6.4 Limites de l'optimiseur

  • tensor-fusion reconnaît 5 patterns (matmul+bias+relu, matmul+bias, linear+gelu/silu, conv+bn+relu) mais pas les fusions attention+softmax ou layernorm
  • gate-cancellation/rotation-merge détectent les paires non consécutives via chaîne SSA, mais pas les patterns croisés (ex. H·Rz)
  • noise-aware-schedule utilise un tri par temps de porte, pas un vrai algorithme d'ordonnancement contraint
  • real-routing insère des SWAP (BFS) avec placement initial identité ; pas de ré-placement dynamique type SABRE, pas de correction d'orientation des SWAP pour la directionnalité

7. Précision des analyses

7.1 Comptage FLOPs

OpérationPrécisionFormule
MatMul (MxK × KxN)Exacte2 × M × K × N
MatMul batch (BxMxK × BxKxN)Exacte2 × B × M × K × N
Linear (Mx K × KxN + N)Exacte2 × M × K × N + M × N
Conv2DExacte2 × B × Cout × Hout × Wout × Cin × Kh × Kw
AttentionExacte2 × B × H × (S² × D + S × D²)
ReLU / élémentaireExactenombre d'éléments
Reshape, TransposeExacte0 FLOPs (correct)
Fused opsExactesomme des composants
LSTM, GRU, RNNNon implémenté
Conv3D, ConvTransposeNon implémenté
Einsum, FFT, SVDNon implémenté

Précision globale : pour les modèles purement Transformer (GPT, BERT, LLaMA), la précision du comptage FLOPs est excellente (erreur < 1%). Pour les modèles CNN, elle est bonne pour Conv2D mais manque les autres convolutions. Pour les modèles récurrents (LSTM), les FLOPs ne sont pas comptés.

7.2 Estimation mémoire

Calcule éléments × byte_size(dtype) par tensor. Précis pour la mémoire statique mais ne modélise pas : les activations intermédiaires allouées dynamiquement, le fragmentation mémoire GPU, les buffers de workspace (cuDNN), le KV cache pour l'inférence LLM.

7.3 Prédiction de temps (roofline)

AspectPrécision
Identification compute-bound vs memory-boundBonne (cas standard)
Temps absoluOrdre de grandeur (facteur 2-5x d'erreur possible)
Effets de cacheNon modélisé
Latence de lancement kernelNon modélisé
Multi-GPUNon modélisé (suppose 1 GPU)
Recouvrement calcul/mémoireNon modélisé

7.4 Fidélité quantique

L'estimation de fidélité est le produit des fidélités individuelles : F = ∏ f_gate × f_décoherence. C'est une borne supérieure (la vraie fidélité est souvent pire à cause des corrélations de bruit, du crosstalk, des erreurs de lecture).


8. Ce qui manque pour atteindre les objectifs fixés

L'objectif de LIFT est : "Simulate → Predict → Optimise → Compile". Voici l'état actuel :

ObjectifÉtatCe qui manque
Simulate40%Analyse statique OK, mais pas de simulation d'exécution réelle (pas de vecteur d'état quantique, pas d'interpréteur tensor)
Predict70%Roofline GPU OK, prédiction quantique OK, mais modèle trop simplifié (pas de cache, pas de multi-GPU, pas de scheduling)
Optimise70%13 passes connectées, pipeline O0-O3, vérification sémantique, fusions génériques, décomposition de portes, routage réel SWAP ; manque le graphe de réécriture général et les fusions attention/layernorm
Compile10%Export LLVM/QASM squelettes, pas de code exécutable réel

8.1 Pour atteindre Simulate (100%)

  1. Simulateur de vecteur d'état quantique : multiplier les matrices de portes sur un vecteur 2^n. Nécessaire pour valider les circuits quantiques.
  2. Interpréteur tensor : exécuter les opérations tensor avec des vraies valeurs numpy-like. Nécessaire pour valider les modèles IA.
  3. Simulation Monte Carlo : pour estimer la distribution de mesure avec bruit.

8.2 Pour atteindre Predict (100%)

  1. Modèle de coût affiné : intégrer latence de lancement, effets de cache L2, scheduling overlappé.
  2. Profils hardware réels : charger les propriétés réelles des QPU (calibration IBM Quantum, temps de porte par qubit).
  3. Multi-GPU : modèle de communication inter-GPU (NVLink, PCIe).
  4. Prédiction quantique avancée : modèle de bruit corrélé, crosstalk, erreurs de lecture.

8.3 Pour atteindre Optimise (100%)

  1. Connecter les 6 passes manquantes au CLI (quick fix).
  2. Plus de patterns de fusion : matmul+gelu, conv+bn+relu, attention+layernorm.
  3. Gate cancellation non-locale : annuler des paires séparées par des opérations sur d'autres qubits (commutation).
  4. Routage réel : implémenter SABRE ou A* pour le layout mapping avec insertion de SWAPs.
  5. Décomposition de portes : transpiler les portes non natives vers le jeu natif.
  6. Système de réécriture à base de patterns : permettre de définir des règles de transformation déclaratives.

8.4 Pour atteindre Compile (100%)

  1. Lowering tensor → LLVM : générer des appels réels vers cuBLAS/cuDNN/oneDNN.
  2. Lowering quantum → QASM complet : supporter les 50+ portes.
  3. Gestion mémoire : allocateur de mémoire GPU (allocation, libération, réutilisation).
  4. Code de lancement : générer le code host qui orchestre les kernels GPU.
  5. Backend quantique : générer du code pour IBM Qiskit Runtime, Amazon Braket, ou Google Cirq.
  6. Import réel : convertir les vrais graphes ONNX/PyTorch en opérations LIFT.

9. Feuille de route (priorité)

Priorité 1 — Quick fixes (effort faible, impact immédiat)

  • Connecter les 6 passes restantes au CLI (modifier cmd_optimise dans main.rs)
  • Connecter EnergyModel au CLI (ajouter une commande energy)
  • Connecter predict_quantum au CLI (ajouter --quantum à la commande predict)
  • Corriger le fichier lift-test manquant (lift-test/src/config.rs)

Priorité 2 — Import/Export fonctionnels (effort moyen, impact élevé)

  • Import ONNX réel : mapper les nœuds ONNX vers TensorOp
  • Import PyTorch FX réel : mapper les nœuds FX vers TensorOp
  • Export QASM complet : supporter toutes les 50+ portes
  • Import QASM réel : parser les portes et créer les opérations quantum

Priorité 3 — Optimisation avancée (effort moyen)

  • Plus de patterns de fusion tensor
  • Gate cancellation non-locale (commutation)
  • Décomposition de portes vers jeu natif
  • Routage réel (SABRE)

Priorité 4 — Simulation (effort élevé)

  • Simulateur de vecteur d'état (jusqu'à ~25 qubits)
  • Interpréteur tensor simplifié
  • Inférence de forme pour les 90 opérations restantes

Priorité 5 — Compilation réelle (effort très élevé)

  • Lowering tensor → LLVM avec appels cuBLAS
  • Gestion mémoire GPU
  • Backend quantum (Qiskit/Braket)

Résumé final

MétriqueValeur
Crates14
Fichiers Rust67
Tests505 (0 échecs)
Opérations définies179 (110 tensor + 48 quantum + 21 hybrid)
Passes d'optimisation11 (5 connectées au CLI)
Backends d'export3 (LLVM IR, ONNX opset 21, OpenQASM 3.0)
Modèles de coût5 (A100, H100, superconducteur, ions piégés, atomes neutres)
Portes exportées QASM10 / 50+
Ops exportées ONNX70+ / 110
Import fonctionnel0 / 3
Exécution possibleNon
Compilation réelleNon

LIFT est un framework d'analyse et d'optimisation IR solide et bien testé, avec une excellente couverture des dialectes (tensor, quantum, hybrid) et une architecture propre. Son point fort est l'analyse statique (FLOPs, mémoire, fidélité, bruit, coût). L'ajout de l'export ONNX (opset 21) et du binaire lift-codegen permet désormais de générer des modèles programmatiquement et de les exporter vers 3 backends (LLVM, ONNX, QASM). Ce qui lui manque principalement, c'est la capacité d'exécuter réellement du code : l'export LLVM est un squelette, les imports sont vides, et il n'y a pas de runtime. Pour devenir un compilateur complet "Simulate → Predict → Optimise → Compile", il faut implémenter le lowering réel, les imports fonctionnels, et un simulateur.

Ce document est l'analyse complète et honnête de l'état de LIFT.

LIFT Dialect Reference — Complete Guide

The definitive reference for every dialect, type, operation, and syntax rule in LIFT.

After reading this document you will be able to write, read, configure, and assemble any .lif file for any model — classical AI, quantum circuits, or hybrid — without errors.


Table of Contents


Part I — File Structure, Grammar, and Type System

1.1 The .lif File

Every LIFT program is a .lif text file with this structure:

#dialect tensor            ← 1. Dialect declarations (one or more)

module @name {             ← 2. Module
    func @fn(%x: type) -> type {   ← 3. Function
        %y = "op"(%x) : (type) -> type   ← 4. Operations
        return %y                          ← 5. Return
    }
}

Rules

  1. At least one #dialect directive at the top.
  2. At least one module block.
  3. Each module contains one or more func declarations.
  4. Each function has parameters, optional return types, and a body of operations.
  5. The body ends with a return statement.

1.2 Grammar Rules

Dialect Directive

#dialect tensor
#dialect quantum
#dialect hybrid

You can declare multiple dialects in one file.

Module

module @my_model {
    ...
}

Function

func @forward(%x: tensor<1x784xf32>, %w: tensor<784x256xf32>) -> tensor<1x256xf32> {
    ...
    return %out
}

Multiple return types use parentheses:

func @bell(%q0: qubit, %q1: qubit) -> (qubit, qubit) {
    ...
    return %q2, %q3
}

Operation (Assignment)

%result = "dialect.operation"(%input1, %input2) : (input_type1, input_type2) -> output_type

Multiple results:

%r1, %r2 = "quantum.cx"(%q0, %q1) : (qubit, qubit) -> (qubit, qubit)

With attributes:

%y = "quantum.ry"(%q) {angle = 1.5708} : (qubit) -> qubit

1.3 Identifiers

PrefixMeaningExample
@Module or function name@my_model, @forward
%SSA value (variable)%x, %q0, %hidden
^Block label^entry
#dialectDialect directive#dialect tensor

SSA Rule

Every %name is assigned exactly once. No reassignment allowed.

1.4 The Type System

Tensor Types

tensor<shape x dtype>
ExampleDescription
tensor<4xf32>1D, 4 floats
tensor<1x784xf32>2D, batch 1, 784 features
tensor<1x3x224x224xf32>4D image: batch, channels, H, W
tensor<Bx128x64xf16>Symbolic batch dim, float16

Data Types (dtype)

SyntaxBitsUse Case
f6464Scientific computing
f3232Default training/inference
f1616Mixed precision
bf1616A100/H100 training
fp8e4m38H100 FP8 inference
fp8e5m28H100 FP8 training
i6464Large indices
i3232Indices
i1616Quantised weights
i88INT8 quantisation
i44INT4 quantisation
i22Extreme quantisation
u88Pixel values
i11Booleans/masks
index64Loop indices

Quantum Types

SyntaxDescriptionRule
qubitA single qubitLinear: consumed exactly once
bitClassical bit (measurement result)Normal (non-linear)
hamiltonian<N>Hamiltonian on N qubitsNormal

Scalar Types

f32, f64, i32, i64, bool, void, index

1.5 Attributes

Compile-time constants attached to operations:

%y = "tensor.conv2d"(%x, %w) {stride = 2, padding = 1} : ...
TypeExample
Integerstride = 2
Floatrate = 0.5
Booleantraining = true
Stringmode = "same"
Arraykernel_size = [3, 3]

1.6 Comments

// This is a comment (ignored by the parser)

Part II — The tensor Dialect (Classical AI)

Declare with #dialect tensor. Provides 107 operations for ML/AI.

2.1 Arithmetic (9)

OperationSyntaxInputsFLOPs
Add"tensor.add"2N
Sub"tensor.sub"2N
Mul"tensor.mul"2N
Div"tensor.div"2N
Neg"tensor.neg"1N
MatMul"tensor.matmul"22MNK
Linear"tensor.linear"32MNK+N
Conv2D"tensor.conv2d"22CoCiKhKwOhOw
Embedding"tensor.embedding"20 (lookup)
%out = "tensor.matmul"(%x, %w) : (tensor<1x784xf32>, tensor<784x256xf32>) -> tensor<1x256xf32>
%out = "tensor.linear"(%x, %w, %b) : (tensor<1x784xf32>, tensor<784x256xf32>, tensor<256xf32>) -> tensor<1x256xf32>
%feat = "tensor.conv2d"(%img, %k) : (tensor<1x3x224x224xf32>, tensor<64x3x7x7xf32>) -> tensor<1x64x112x112xf32>

2.2 Activations (11)

All: 1 input → 1 output, same shape.

OperationSyntaxFormula
ReLU"tensor.relu"max(0, x)
GeLU"tensor.gelu"x * Phi(x)
SiLU"tensor.silu"x * sigmoid(x)
Sigmoid"tensor.sigmoid"1/(1+e^-x)
Softmax"tensor.softmax"e^xi / sum(e^xj)
Tanh"tensor.tanh"(e^x-e^-x)/(e^x+e^-x)
LeakyReLU"tensor.leaky_relu"max(alpha*x, x)
ELU"tensor.elu"x if x>0, alpha*(e^x-1) else
Mish"tensor.mish"x*tanh(softplus(x))
HardSwish"tensor.hard_swish"x*relu6(x+3)/6
HardSigmoid"tensor.hard_sigmoid"relu6(x+3)/6
%a = "tensor.relu"(%x) : (tensor<1x256xf32>) -> tensor<1x256xf32>
%p = "tensor.softmax"(%logits) : (tensor<1x10xf32>) -> tensor<1x10xf32>

Which to use: CNN → ReLU. Transformer/LLM → GeLU/SiLU. Classifier → Softmax/Sigmoid. Edge → HardSwish.

2.3 Normalisation (5)

OperationSyntaxInputsUse Case
LayerNorm"tensor.layernorm"2-3Transformers
RMSNorm"tensor.rmsnorm"2-3LLaMA, Mistral
BatchNorm"tensor.batchnorm"3-5CNN training
GroupNorm"tensor.groupnorm"2-3Diffusion
InstanceNorm"tensor.instancenorm"2-3Style transfer
// LayerNorm — Transformers (input + scale)
%n1 = "tensor.layernorm"(%x, %scale) : (tensor<1x128x64xf32>, tensor<64xf32>) -> tensor<1x128x64xf32>

// LayerNorm with bias — (input + scale + bias)
%n2 = "tensor.layernorm"(%x, %scale, %bias) : (tensor<1x128x64xf32>, tensor<64xf32>, tensor<64xf32>) -> tensor<1x128x64xf32>

// RMSNorm — LLaMA, Mistral (input + scale)
%n3 = "tensor.rmsnorm"(%x, %scale) : (tensor<1x128x4096xf32>, tensor<4096xf32>) -> tensor<1x128x4096xf32>

// BatchNorm — CNN training (input + scale + bias)
%n4 = "tensor.batchnorm"(%x, %scale, %bias) : (tensor<8x64x32x32xf32>, tensor<64xf32>, tensor<64xf32>) -> tensor<8x64x32x32xf32>

// GroupNorm — Diffusion models (input + scale)
%n5 = "tensor.groupnorm"(%x, %scale) : (tensor<1x256x32x32xf32>, tensor<256xf32>) -> tensor<1x256x32x32xf32>

// InstanceNorm — Style transfer (input + scale)
%n6 = "tensor.instancenorm"(%x, %scale) : (tensor<1x64x256x256xf32>, tensor<64xf32>) -> tensor<1x64x256x256xf32>

2.4 Shape Operations (13) — Zero FLOPs

OperationSyntaxDescription
Reshape"tensor.reshape"Change shape
Transpose"tensor.transpose"Swap dims
Concat"tensor.concat"Join tensors
Split"tensor.split"Split tensor
Gather"tensor.gather"Index select
Scatter"tensor.scatter"Index assign
Squeeze"tensor.squeeze"Remove dim=1
Unsqueeze"tensor.unsqueeze"Add dim=1
Permute"tensor.permute"Reorder dims
Expand"tensor.expand"Broadcast
Slice"tensor.slice"Sub-tensor
Pad"tensor.pad"Add padding
Tile"tensor.tile"Repeat
// Reshape: flatten a 4D image tensor to 2D
%flat = "tensor.reshape"(%x) : (tensor<1x3x224x224xf32>) -> tensor<1x150528xf32>

// Transpose: swap last two dimensions
%t = "tensor.transpose"(%x) : (tensor<128x64xf32>) -> tensor<64x128xf32>

// Concat: join two tensors along batch dimension
%cat = "tensor.concat"(%a, %b) : (tensor<1x128xf32>, tensor<1x128xf32>) -> tensor<2x128xf32>

// Squeeze: remove dimension of size 1
%sq = "tensor.squeeze"(%x) : (tensor<1x64x1x1xf32>) -> tensor<1x64xf32>

// Unsqueeze: add a batch dimension
%us = "tensor.unsqueeze"(%x) : (tensor<64xf32>) -> tensor<1x64xf32>

// Permute: reorder dimensions (e.g. NCHW → NHWC)
%p = "tensor.permute"(%x) : (tensor<1x3x224x224xf32>) -> tensor<1x224x224x3xf32>

// Slice: extract a sub-tensor
%sl = "tensor.slice"(%x) : (tensor<1x100x64xf32>) -> tensor<1x50x64xf32>

// Pad: add zero-padding
%padded = "tensor.pad"(%x) : (tensor<1x3x224x224xf32>) -> tensor<1x3x226x226xf32>

// Gather: index-based selection
%sel = "tensor.gather"(%x, %indices) : (tensor<1000x64xf32>, tensor<10xi32>) -> tensor<10x64xf32>

// Expand: broadcast a tensor
%exp = "tensor.expand"(%x) : (tensor<1x1x64xf32>) -> tensor<8x128x64xf32>

2.5 Attention (8)

All take 3-5 inputs (Q, K, V, optional mask). FLOPs = 2BH*(S²D + SD²).

OperationSyntaxDescription
Attention"tensor.attention"Standard scaled dot-product
MultiHeadAttention"tensor.multi_head_attention"Standard Transformer
MultiQueryAttention"tensor.multi_query_attention"Shared K/V (fast inference)
GroupedQueryAttention"tensor.grouped_query_attention"LLaMA 2 style
FlashAttention"tensor.flash_attention"O(n) memory
SlidingWindowAttention"tensor.sliding_window_attention"Mistral
CrossAttention"tensor.cross_attention"Encoder-decoder
PagedAttention"tensor.paged_attention"vLLM paged KV
// Standard scaled dot-product attention: Q, K, V
%attn = "tensor.attention"(%q, %k, %v) : (tensor<1x128x64xf32>, tensor<1x128x64xf32>, tensor<1x128x64xf32>) -> tensor<1x128x64xf32>

// Multi-head attention (standard Transformer)
%mha = "tensor.multi_head_attention"(%q, %k, %v) : (tensor<1x8x128x64xf32>, tensor<1x8x128x64xf32>, tensor<1x8x128x64xf32>) -> tensor<1x8x128x64xf32>

// Flash attention: same API, O(n) memory, for long sequences
%flash = "tensor.flash_attention"(%q, %k, %v) : (tensor<1x8x4096x64xf32>, tensor<1x8x4096x64xf32>, tensor<1x8x4096x64xf32>) -> tensor<1x8x4096x64xf32>

// Grouped-query attention (LLaMA 2 style): fewer K/V heads
%gqa = "tensor.grouped_query_attention"(%q, %k, %v) : (tensor<1x32x128x64xf32>, tensor<1x8x128x64xf32>, tensor<1x8x128x64xf32>) -> tensor<1x32x128x64xf32>

// Cross attention (encoder-decoder, e.g. translation)
%cross = "tensor.cross_attention"(%decoder_q, %encoder_k, %encoder_v) : (tensor<1x8x64x64xf32>, tensor<1x8x128x64xf32>, tensor<1x8x128x64xf32>) -> tensor<1x8x64x64xf32>

// Sliding window attention (Mistral): local context window
%swa = "tensor.sliding_window_attention"(%q, %k, %v) : (tensor<1x8x4096x64xf32>, tensor<1x8x4096x64xf32>, tensor<1x8x4096x64xf32>) -> tensor<1x8x4096x64xf32>

// Paged attention (vLLM): paged KV cache for efficient serving
%paged = "tensor.paged_attention"(%q, %k_cache, %v_cache) : (tensor<1x8x1x64xf32>, tensor<1x8x4096x64xf32>, tensor<1x8x4096x64xf32>) -> tensor<1x8x1x64xf32>

2.6 Convolution (6)

OperationSyntaxUse Case
Conv1D"tensor.conv1d"Audio, time series
Conv2D"tensor.conv2d"Images
Conv3D"tensor.conv3d"Video, medical 3D
ConvTranspose2D"tensor.conv_transpose2d"Upsampling
DepthwiseConv2D"tensor.depthwise_conv2d"MobileNet
DilatedConv2D"tensor.dilated_conv2d"Segmentation
// Conv1D: audio processing [B, Cin, Length] * [Cout, Cin, K]
%audio_feat = "tensor.conv1d"(%audio, %kernel) : (tensor<1x1x16000xf32>, tensor<64x1x80xf32>) -> tensor<1x64x15921xf32>

// Conv2D: image feature extraction [B, Cin, H, W] * [Cout, Cin, Kh, Kw]
%img_feat = "tensor.conv2d"(%img, %kernel) : (tensor<1x3x224x224xf32>, tensor<64x3x7x7xf32>) -> tensor<1x64x112x112xf32>

// Conv3D: video processing [B, Cin, D, H, W] * [Cout, Cin, Kd, Kh, Kw]
%vid_feat = "tensor.conv3d"(%video, %kernel) : (tensor<1x3x16x112x112xf32>, tensor<64x3x3x3x3xf32>) -> tensor<1x64x14x110x110xf32>

// ConvTranspose2D: upsampling (decoder/generator)
%up = "tensor.conv_transpose2d"(%x, %kernel) : (tensor<1x64x16x16xf32>, tensor<64x32x4x4xf32>) -> tensor<1x32x32x32xf32>

// DepthwiseConv2D: MobileNet-style per-channel conv
%dw = "tensor.depthwise_conv2d"(%x, %kernel) : (tensor<1x64x32x32xf32>, tensor<64x1x3x3xf32>) -> tensor<1x64x32x32xf32>

// DilatedConv2D: large receptive field (segmentation)
%dilated = "tensor.dilated_conv2d"(%x, %kernel) : (tensor<1x64x64x64xf32>, tensor<64x64x3x3xf32>) -> tensor<1x64x64x64xf32>

2.7 Pooling (4)

OperationSyntaxInputs
MaxPool2D"tensor.maxpool2d"2
AvgPool2D"tensor.avgpool2d"2
AdaptiveAvgPool2D"tensor.adaptive_avgpool2d"1
GlobalAvgPool"tensor.global_avgpool"1
// MaxPool2D: downsample by taking maximum in each window
%p1 = "tensor.maxpool2d"(%x, %params) : (tensor<1x64x32x32xf32>, tensor<2xi32>) -> tensor<1x64x16x16xf32>

// AvgPool2D: downsample by averaging each window
%p2 = "tensor.avgpool2d"(%x, %params) : (tensor<1x64x32x32xf32>, tensor<2xi32>) -> tensor<1x64x16x16xf32>

// AdaptiveAvgPool2D: output always has fixed spatial size (e.g. 7x7)
%p3 = "tensor.adaptive_avgpool2d"(%x) : (tensor<1x512x14x14xf32>) -> tensor<1x512x7x7xf32>

// GlobalAvgPool: average all spatial dimensions → 1x1
%p4 = "tensor.global_avgpool"(%x) : (tensor<1x64x7x7xf32>) -> tensor<1x64x1x1xf32>

2.8 Recurrent (3)

OperationSyntaxFLOPs per step
LSTMCell"tensor.lstm_cell"4*(in+hid)hid2
GRUCell"tensor.gru_cell"3*(in+hid)hid2
RNNCell"tensor.rnn_cell"(in+hid)hid2
// LSTMCell: takes current input + previous hidden state, returns new hidden + cell state
%h_new, %c_new = "tensor.lstm_cell"(%x_t, %h_prev) : (tensor<1x128xf32>, tensor<1x256xf32>) -> (tensor<1x256xf32>, tensor<1x256xf32>)

// GRUCell: simpler than LSTM, single hidden state
%h_new = "tensor.gru_cell"(%x_t, %h_prev) : (tensor<1x128xf32>, tensor<1x256xf32>) -> tensor<1x256xf32>

// RNNCell: basic recurrent cell
%h_new = "tensor.rnn_cell"(%x_t, %h_prev) : (tensor<1x128xf32>, tensor<1x256xf32>) -> tensor<1x256xf32>

2.9 Advanced Math (11)

OperationSyntaxComplexity
Einsum"tensor.einsum"Varies
FFT"tensor.fft"O(n log n)
IFFT"tensor.ifft"O(n log n)
SVD"tensor.svd"O(mn min(m,n))
Eig"tensor.eig"O(n³)
Solve"tensor.solve"O(n³)
TopK"tensor.topk"O(n log k)
Sort"tensor.sort"O(n log n)
Cumsum"tensor.cumsum"O(n)
Where"tensor.where"O(n)
Clamp"tensor.clamp"O(n)
// Einsum: flexible tensor contraction (e.g. batch matmul)
%result = "tensor.einsum"(%a, %b) : (tensor<8x128x64xf32>, tensor<8x64x256xf32>) -> tensor<8x128x256xf32>

// FFT: Fast Fourier Transform (signal processing)
%freq = "tensor.fft"(%signal) : (tensor<1x1024xf32>) -> tensor<1x1024xf32>

// IFFT: Inverse FFT (frequency → time domain)
%time = "tensor.ifft"(%freq) : (tensor<1x1024xf32>) -> tensor<1x1024xf32>

// SVD: Singular Value Decomposition (compression, PCA)
%u = "tensor.svd"(%matrix) : (tensor<100x50xf32>) -> tensor<100x50xf32>

// TopK: get top-10 scores from 1000 classes
%top = "tensor.topk"(%scores) : (tensor<1x1000xf32>) -> tensor<1x10xf32>

// Sort: sort a tensor along last dimension
%sorted = "tensor.sort"(%x) : (tensor<1x100xf32>) -> tensor<1x100xf32>

// Cumsum: cumulative sum (prefix sum)
%cs = "tensor.cumsum"(%x) : (tensor<1x10xf32>) -> tensor<1x10xf32>

// Where: conditional selection (like numpy.where)
%selected = "tensor.where"(%cond, %a, %b) : (tensor<4xi1>, tensor<4xf32>, tensor<4xf32>) -> tensor<4xf32>

// Clamp: restrict values to [min, max] range
%clamped = "tensor.clamp"(%x, %min_val, %max_val) : (tensor<4xf32>, tensor<1xf32>, tensor<1xf32>) -> tensor<4xf32>

// Solve: solve linear system Ax = b
%solution = "tensor.solve"(%A, %b) : (tensor<64x64xf32>, tensor<64x1xf32>) -> tensor<64x1xf32>

// Eig: eigenvalue decomposition
%eigenvalues = "tensor.eig"(%matrix) : (tensor<32x32xf32>) -> tensor<32xf32>

2.10 Sparse (2)

"tensor.sparse_matmul", "tensor.sparse_embedding"

// SparseMatMul: sparse × dense matrix multiply (efficient for sparse models)
%result = "tensor.sparse_matmul"(%sparse_w, %x) : (tensor<10000x768xf32>, tensor<768x1xf32>) -> tensor<10000x1xf32>

// SparseEmbedding: sparse lookup (recommendation systems with huge vocab)
%emb = "tensor.sparse_embedding"(%sparse_ids, %table) : (tensor<1x50xi32>, tensor<1000000x128xf32>) -> tensor<1x50x128xf32>

2.11 Quantisation (6)

OperationSyntaxDirection
Quantize"tensor.quantize"f32 → i8
Dequantize"tensor.dequantize"i8 → f32
QuantizeInt4"tensor.quantize_int4"f32 → i4
DequantizeInt4"tensor.dequantize_int4"i4 → f32
QuantizeFp8"tensor.quantize_fp8"f32 → fp8
DequantizeFp8"tensor.dequantize_fp8"fp8 → f32
// INT8 Quantisation: reduce model size 4x
%q8 = "tensor.quantize"(%weights) : (tensor<256x256xf32>) -> tensor<256x256xi8>
%dq8 = "tensor.dequantize"(%q8) : (tensor<256x256xi8>) -> tensor<256x256xf32>

// INT4 Quantisation: reduce model size 8x (GPTQ, AWQ style)
%q4 = "tensor.quantize_int4"(%weights) : (tensor<4096x4096xf32>) -> tensor<4096x4096xi4>
%dq4 = "tensor.dequantize_int4"(%q4) : (tensor<4096x4096xi4>) -> tensor<4096x4096xf32>

// FP8 Quantisation: H100 native format
%qfp8 = "tensor.quantize_fp8"(%weights) : (tensor<4096x4096xf32>) -> tensor<4096x4096xfp8e4m3>
%dqfp8 = "tensor.dequantize_fp8"(%qfp8) : (tensor<4096x4096xfp8e4m3>) -> tensor<4096x4096xf32>

2.12 Diffusion/Generative (3)

"tensor.unet_down_block" (2-3 in), "tensor.unet_up_block" (2-3 in), "tensor.timestep_embedding" (1 in)

// TimestepEmbedding: encode diffusion timestep as a vector
%t_emb = "tensor.timestep_embedding"(%timestep) : (tensor<1xi32>) -> tensor<1x256xf32>

// UNetDownBlock: encoder block of UNet (input + timestep embedding)
%down = "tensor.unet_down_block"(%x, %t_emb) : (tensor<1x64x64x64xf32>, tensor<1x256xf32>) -> tensor<1x128x32x32xf32>

// UNetUpBlock: decoder block of UNet (input + skip connection + timestep)
%up = "tensor.unet_up_block"(%x, %skip, %t_emb) : (tensor<1x128x32x32xf32>, tensor<1x128x32x32xf32>, tensor<1x256xf32>) -> tensor<1x64x64x64xf32>

2.13 GNN (2)

"tensor.gnn_message_passing" (2-3 in), "tensor.gnn_global_pooling" (1 in)

// GNNMessagePassing: propagate node features along edges
%h1 = "tensor.gnn_message_passing"(%nodes, %adj) : (tensor<50x16xf32>, tensor<50x50xf32>) -> tensor<50x16xf32>

// With edge features (3 inputs)
%h2 = "tensor.gnn_message_passing"(%nodes, %adj, %edge_feat) : (tensor<50x16xf32>, tensor<50x50xf32>, tensor<50x50x8xf32>) -> tensor<50x16xf32>

// GNNGlobalPooling: aggregate all node features into a single graph vector
%graph = "tensor.gnn_global_pooling"(%h2) : (tensor<50x16xf32>) -> tensor<1x16xf32>

2.14 MoE (2)

"tensor.moe_dispatch" (2-3 in), "tensor.moe_combine" (2-3 in)

// MoEDispatch: router sends tokens to top-k experts
%dispatched = "tensor.moe_dispatch"(%tokens, %router_logits) : (tensor<8x128x512xf32>, tensor<8x128x8xf32>) -> tensor<8x128x512xf32>

// MoECombine: merge expert outputs weighted by router
%combined = "tensor.moe_combine"(%expert_outputs, %router_weights) : (tensor<8x128x512xf32>, tensor<8x128x8xf32>) -> tensor<8x128x512xf32>

2.15 Constants (5) — Zero inputs

"tensor.constant", "tensor.zeros", "tensor.ones", "tensor.arange", "tensor.full"

// Zeros: create an all-zero tensor (e.g. initial hidden state)
%z = "tensor.zeros"() : () -> tensor<1x256xf32>

// Ones: create an all-one tensor (e.g. attention mask)
%mask = "tensor.ones"() : () -> tensor<1x128xi32>

// Arange: create [0, 1, 2, ..., 127] (e.g. position IDs)
%pos = "tensor.arange"() : () -> tensor<128xi32>

// Full: create a tensor filled with a specific value
%filled = "tensor.full"() : () -> tensor<1x64xf32>

// Constant: arbitrary constant tensor
%c = "tensor.constant"() : () -> tensor<3xf32>

2.16 Memory (3)

"tensor.checkpoint" (activation recompute), "tensor.offload" (to CPU), "tensor.grad_accumulate" (micro-batches)

// Checkpoint: recompute activations during backward instead of storing them
// Saves GPU memory at the cost of extra compute (critical for large models)
%ckpt = "tensor.checkpoint"(%activations) : (tensor<1x4096x4096xf32>) -> tensor<1x4096x4096xf32>

// Offload: move tensor from GPU to CPU memory (for very large models)
%offloaded = "tensor.offload"(%weights) : (tensor<8192x8192xf32>) -> tensor<8192x8192xf32>

// GradAccumulate: accumulate gradients over multiple micro-batches
// Used when actual batch doesn't fit in GPU memory
%acc = "tensor.grad_accumulate"(%grads) : (tensor<256x256xf32>) -> tensor<256x256xf32>

2.17 Gradient/Backward (8)

SyntaxForward Op
"tensor.grad_matmul"MatMul
"tensor.grad_relu"ReLU
"tensor.grad_softmax"Softmax
"tensor.grad_layernorm"LayerNorm
"tensor.grad_attention"Attention
"tensor.grad_conv2d"Conv2D
"tensor.grad_linear"Linear
"tensor.grad_gelu"GeLU
// GradMatMul: backward pass for matrix multiplication
%grad_x = "tensor.grad_matmul"(%upstream_grad, %w) : (tensor<1x256xf32>, tensor<256x784xf32>) -> tensor<1x784xf32>

// GradReLU: backward pass for ReLU (zero where input was negative)
%grad_r = "tensor.grad_relu"(%upstream_grad, %relu_input) : (tensor<1x256xf32>, tensor<1x256xf32>) -> tensor<1x256xf32>

// GradSoftmax: backward pass for softmax
%grad_s = "tensor.grad_softmax"(%upstream_grad, %softmax_output) : (tensor<1x10xf32>, tensor<1x10xf32>) -> tensor<1x10xf32>

// GradLayerNorm: backward pass for layer normalisation
%grad_ln = "tensor.grad_layernorm"(%upstream_grad, %ln_input) : (tensor<1x128x64xf32>, tensor<1x128x64xf32>) -> tensor<1x128x64xf32>

// GradAttention: backward pass for attention
%grad_attn = "tensor.grad_attention"(%upstream_grad, %q, %k) : (tensor<1x128x64xf32>, tensor<1x128x64xf32>, tensor<1x128x64xf32>) -> tensor<1x128x64xf32>

// GradConv2D: backward pass for 2D convolution
%grad_conv = "tensor.grad_conv2d"(%upstream_grad, %conv_input) : (tensor<1x64x112x112xf32>, tensor<1x3x224x224xf32>) -> tensor<1x3x224x224xf32>

// GradLinear: backward pass for linear layer
%grad_lin = "tensor.grad_linear"(%upstream_grad, %w, %b) : (tensor<1x256xf32>, tensor<784x256xf32>, tensor<256xf32>) -> tensor<1x784xf32>

// GradGeLU: backward pass for GeLU activation
%grad_g = "tensor.grad_gelu"(%upstream_grad, %gelu_input) : (tensor<1x256xf32>, tensor<1x256xf32>) -> tensor<1x256xf32>

2.18 Parallelism (4)

"tensor.parallel_split", "tensor.parallel_allreduce", "tensor.pipeline_send", "tensor.pipeline_receive"

// ParallelSplit: split a batch across multiple GPUs (data parallelism)
%shard = "tensor.parallel_split"(%batch) : (tensor<32x128xf32>) -> tensor<8x128xf32>

// ParallelAllReduce: synchronise gradients across all GPUs
%synced = "tensor.parallel_allreduce"(%local_grad) : (tensor<256x256xf32>) -> tensor<256x256xf32>

// PipelineSend: send activation to the next pipeline stage (model parallelism)
%sent = "tensor.pipeline_send"(%activation) : (tensor<1x128x4096xf32>) -> tensor<1x128x4096xf32>

// PipelineReceive: receive activation from the previous pipeline stage
%recv = "tensor.pipeline_receive"(%placeholder) : (tensor<1x128x4096xf32>) -> tensor<1x128x4096xf32>

2.19 Fused Operations (6)

SyntaxEquivalent
"tensor.fused_matmul_bias_relu"matmul+add+relu
"tensor.fused_matmul_bias"matmul+add
"tensor.fused_linear_gelu"linear+gelu
"tensor.fused_attention_layernorm"attention+layernorm
"tensor.fused_linear_silu"linear+silu
"tensor.fused_conv_batchnorm_relu"conv+bn+relu
// FusedMatMulBiasReLU: 3 ops in 1 kernel (most common for MLP hidden layers)
%h = "tensor.fused_matmul_bias_relu"(%x, %w, %b) : (tensor<1x256xf32>, tensor<256x128xf32>, tensor<128xf32>) -> tensor<1x128xf32>

// FusedMatMulBias: matmul + bias only (no activation)
%h2 = "tensor.fused_matmul_bias"(%x, %w, %b) : (tensor<1x128xf32>, tensor<128x64xf32>, tensor<64xf32>) -> tensor<1x64xf32>

// FusedLinearGeLU: used in Transformer FFN (LLM inference)
%ffn = "tensor.fused_linear_gelu"(%x, %w, %b) : (tensor<1x128x4096xf32>, tensor<4096x16384xf32>, tensor<16384xf32>) -> tensor<1x128x16384xf32>

// FusedAttentionLayerNorm: attention + normalisation in one pass
%attn_ln = "tensor.fused_attention_layernorm"(%q, %k, %v, %scale) : (tensor<1x128x64xf32>, tensor<1x128x64xf32>, tensor<1x128x64xf32>, tensor<64xf32>) -> tensor<1x128x64xf32>

// FusedLinearSiLU: used in LLaMA/Mistral gate projections
%gate = "tensor.fused_linear_silu"(%x, %w, %b) : (tensor<1x128x4096xf32>, tensor<4096x11008xf32>, tensor<11008xf32>) -> tensor<1x128x11008xf32>

// FusedConvBatchNormReLU: standard CNN inference fusion
%feat = "tensor.fused_conv_batchnorm_relu"(%img, %w, %bn_s, %bn_b, %bn_m) : (tensor<1x3x224x224xf32>, tensor<64x3x7x7xf32>, tensor<64xf32>, tensor<64xf32>, tensor<64xf32>) -> tensor<1x64x112x112xf32>

Part III — The quantum Dialect (Quantum Computing)

Declare with #dialect quantum. Provides 50+ operations for quantum circuits.

Critical rule: all qubits follow the linearity rule — each qubit value must be consumed exactly once.

3.1 Standard 1-Qubit Gates (9)

All take 1 qubit, return 1 qubit: %q_out = "quantum.gate"(%q_in) : (qubit) -> qubit

GateSyntaxCliffordSelf-InverseDescription
Hadamard"quantum.h"YesYesCreates superposition
Pauli-X"quantum.x"YesYesBit-flip
Pauli-Y"quantum.y"YesYesY rotation
Pauli-Z"quantum.z"YesYesPhase-flip
S"quantum.s"YesNosqrt(Z)
S†"quantum.sdg"YesNoS inverse
T"quantum.t"NoNopi/8 gate
T†"quantum.tdg"NoNoT inverse
SX"quantum.sx"YesNosqrt(X)
%q1 = "quantum.h"(%q0) : (qubit) -> qubit
%q2 = "quantum.x"(%q1) : (qubit) -> qubit
%q3 = "quantum.t"(%q2) : (qubit) -> qubit

3.2 Parametric 1-Qubit Gates (7)

Take 1 qubit + angle attributes, return 1 qubit.

GateSyntaxParametersDescription
RX"quantum.rx"thetaX-axis rotation
RY"quantum.ry"thetaY-axis rotation
RZ"quantum.rz"thetaZ-axis rotation
P"quantum.p"phiPhase gate
U1"quantum.u1"lambda1-param universal
U2"quantum.u2"phi, lambda2-param universal
U3"quantum.u3"theta, phi, lambda3-param universal (any 1Q gate)
%q1 = "quantum.ry"(%q0) {angle = 1.5708} : (qubit) -> qubit
%q1 = "quantum.rz"(%q0) {angle = 0.785} : (qubit) -> qubit
%q1 = "quantum.u3"(%q0) {theta = 1.57, phi = 0.0, lambda = 3.14} : (qubit) -> qubit

3.3 Fixed-Angle 1-Qubit Gates (2)

GateSyntaxAngleSelf-Inverse
Rx90"quantum.rx90"pi/2No
Rx180"quantum.rx180"piYes
// Rx90: fixed pi/2 rotation around X (commonly used in hardware)
%q1 = "quantum.rx90"(%q0) : (qubit) -> qubit

// Rx180: fixed pi rotation around X (equivalent to X gate)
%q2 = "quantum.rx180"(%q1) : (qubit) -> qubit

3.4 2-Qubit Gates (13)

All take 2 qubits, return 2 qubits: %a, %b = "quantum.gate"(%q0, %q1) : (qubit, qubit) -> (qubit, qubit)

GateSyntaxNative OnParametric
CX (CNOT)"quantum.cx"IBMNo
CZ"quantum.cz"GoogleNo
CY"quantum.cy"No
SWAP"quantum.swap"No
iSWAP"quantum.iswap"GoogleNo
ECR"quantum.ecr"IBM EagleNo
RZX"quantum.rzx"Yes
XX"quantum.xx"IonQYes
YY"quantum.yy"Yes
ZZ"quantum.zz"QuantinuumYes
CP"quantum.cp"Yes
CPhase"quantum.cphase"RigettiYes
XY"quantum.xy"RigettiYes

IonQ native gates (3)

GateSyntaxDescription
GPI"quantum.gpi"IonQ single-qubit gate
GPI2"quantum.gpi2"IonQ single-qubit gate 2
MS"quantum.ms"Mølmer-Sørensen (IonQ 2-qubit)
// CX (CNOT): controlled NOT, fundamental entangling gate (IBM native)
%q2, %q3 = "quantum.cx"(%q0, %q1) : (qubit, qubit) -> (qubit, qubit)

// CZ: controlled-Z (Google Sycamore native)
%q2, %q3 = "quantum.cz"(%q0, %q1) : (qubit, qubit) -> (qubit, qubit)

// SWAP: exchange two qubit states
%q2, %q3 = "quantum.swap"(%q0, %q1) : (qubit, qubit) -> (qubit, qubit)

// ECR: echoed cross-resonance (IBM Eagle/Heron native)
%q2, %q3 = "quantum.ecr"(%q0, %q1) : (qubit, qubit) -> (qubit, qubit)

// ZZ: parametric Ising ZZ (Quantinuum native)
%q2, %q3 = "quantum.zz"(%q0, %q1) {angle = 0.5} : (qubit, qubit) -> (qubit, qubit)

// XX: parametric Ising XX (IonQ native)
%q2, %q3 = "quantum.xx"(%q0, %q1) {angle = 1.5708} : (qubit, qubit) -> (qubit, qubit)

// CP: controlled-phase gate (parametric)
%q2, %q3 = "quantum.cp"(%q0, %q1) {angle = 0.7854} : (qubit, qubit) -> (qubit, qubit)

// CPhase: Rigetti native controlled-phase
%q2, %q3 = "quantum.cphase"(%q0, %q1) {angle = 1.5708} : (qubit, qubit) -> (qubit, qubit)

// XY: Rigetti native XY interaction
%q2, %q3 = "quantum.xy"(%q0, %q1) {angle = 0.5} : (qubit, qubit) -> (qubit, qubit)

// iSWAP: imaginary SWAP (Google Sycamore)
%q2, %q3 = "quantum.iswap"(%q0, %q1) : (qubit, qubit) -> (qubit, qubit)

3.5 3-Qubit Gates (2)

GateSyntaxDescription
CCX (Toffoli)"quantum.ccx"Controlled-Controlled-NOT
CSWAP (Fredkin)"quantum.cswap"Controlled-SWAP
// CCX (Toffoli): 2 controls + 1 target, flips target if both controls are |1>
%a, %b, %c = "quantum.ccx"(%q0, %q1, %q2) : (qubit, qubit, qubit) -> (qubit, qubit, qubit)

// CSWAP (Fredkin): controlled swap, swaps q1/q2 if q0 is |1>
%d, %e, %f = "quantum.cswap"(%q3, %q4, %q5) : (qubit, qubit, qubit) -> (qubit, qubit, qubit)

3.6 Multi-Controlled Gates (2)

GateSyntaxQubits
MCX"quantum.mcx"N (variable)
MCZ"quantum.mcz"N (variable)
// MCX with 4 qubits: 3 controls + 1 target
%a, %b, %c, %d = "quantum.mcx"(%q0, %q1, %q2, %q3) : (qubit, qubit, qubit, qubit) -> (qubit, qubit, qubit, qubit)

// MCZ with 3 qubits: 2 controls + 1 target
%e, %f, %g = "quantum.mcz"(%q4, %q5, %q6) : (qubit, qubit, qubit) -> (qubit, qubit, qubit)

3.7 Measurement and Control (8)

OperationSyntaxInOutDescription
Measure"quantum.measure"1 qubitqubitMeasure qubit
MeasureAll"quantum.measure_all"NNMeasure all
Reset"quantum.reset"1 qubitqubitReset to |0>
Barrier"quantum.barrier"NPrevent reordering
Init"quantum.init"1 qubitqubitInitialise register
Delay"quantum.delay"Time delay
VirtualRZ"quantum.virtual_rz"1 qubitqubitZero-cost virtual Z
IfElse"quantum.if_else"Classical conditional
ParamGate"quantum.param_gate"Generic parameterised gate
%m = "quantum.measure"(%q0) : (qubit) -> qubit
%r = "quantum.reset"(%q0) : (qubit) -> qubit
%q1 = "quantum.virtual_rz"(%q0) {angle = 0.785} : (qubit) -> qubit

3.8 Hardware Native Gate Sets

Each provider has a fixed set of natively supported gates. All other gates are decomposed automatically.

ProviderNative Gates
IBM Eagle / Kyotorz, sx, x, cx, ecr
Rigettirz, rx, cz, cphase, xy
IonQgpi, gpi2, ms
Quantinuumrz, rx, ry, zz
Simulatorh, x, y, z, s, t, rx, ry, rz, cx, cz, ccx, swap

Example — same entangling operation on different hardware:

// IBM Eagle: uses CX (CNOT) natively
%a, %b = "quantum.cx"(%q0, %q1) : (qubit, qubit) -> (qubit, qubit)

// Google Sycamore: uses CZ natively
%a, %b = "quantum.cz"(%q0, %q1) : (qubit, qubit) -> (qubit, qubit)

// IonQ: uses MS (Mølmer-Sørensen) natively
%a, %b = "quantum.ms"(%q0, %q1) : (qubit, qubit) -> (qubit, qubit)

// Quantinuum: uses ZZ natively
%a, %b = "quantum.zz"(%q0, %q1) {angle = 1.5708} : (qubit, qubit) -> (qubit, qubit)

// Rigetti: uses CPhase natively
%a, %b = "quantum.cphase"(%q0, %q1) {angle = 3.14159} : (qubit, qubit) -> (qubit, qubit)

Note: LIFT automatically decomposes non-native gates into the target hardware's native set during compilation. You can write using any gate and the compiler handles the rest.

3.9 Gate Properties

PropertyWhat it meansChecked by
num_qubitsExpected input countCompile-time verification
is_parametricNeeds angle attributesAttribute validation
is_self_inverseG·G = IdentityGate cancellation pass
is_cliffordEfficient classical simulationOptimiser heuristics
is_entanglingCreates entanglementCircuit analysis
is_measurementCollapses stateControl flow analysis

3.10 Qubit Linearity Rule

The most important rule in the quantum dialect.

Every qubit must be consumed exactly once:

// CORRECT
%q1 = "quantum.h"(%q0) : (qubit) -> qubit       // q0 consumed → q1 produced
%q2, %q3 = "quantum.cx"(%q1, %q_b) : ...        // q1 consumed

// ERROR: q0 used twice (no-cloning violation)
%q1 = "quantum.h"(%q0) : (qubit) -> qubit
%q2 = "quantum.x"(%q0) : (qubit) -> qubit        // COMPILE ERROR

// ERROR: q1 never used (qubit leak)
%q1 = "quantum.h"(%q0) : (qubit) -> qubit
return                                             // COMPILE ERROR

3.11 Complete Bell State Example

#dialect quantum

module @bell_state {
    func @bell(%q0: qubit, %q1: qubit) -> (qubit, qubit) {
        %q2 = "quantum.h"(%q0) : (qubit) -> qubit
        %q3, %q4 = "quantum.cx"(%q2, %q1) : (qubit, qubit) -> (qubit, qubit)
        return %q3, %q4
    }
}

3.12 Complete GHZ State Example (3 qubits)

#dialect quantum

module @ghz {
    func @ghz3(%q0: qubit, %q1: qubit, %q2: qubit) -> (qubit, qubit, qubit) {
        %a = "quantum.h"(%q0) : (qubit) -> qubit
        %b, %c = "quantum.cx"(%a, %q1) : (qubit, qubit) -> (qubit, qubit)
        %d, %e = "quantum.cx"(%c, %q2) : (qubit, qubit) -> (qubit, qubit)
        return %b, %d, %e
    }
}

3.13 Complete Variational Circuit Example

#dialect quantum

module @variational {
    func @layer(%q0: qubit, %q1: qubit) -> (qubit, qubit) {
        // RY rotations (parametric)
        %a = "quantum.ry"(%q0) {angle = 0.5} : (qubit) -> qubit
        %b = "quantum.ry"(%q1) {angle = 1.2} : (qubit) -> qubit
        // Entangling
        %c, %d = "quantum.cx"(%a, %b) : (qubit, qubit) -> (qubit, qubit)
        // More rotations
        %e = "quantum.rz"(%c) {angle = 0.3} : (qubit) -> qubit
        %f = "quantum.rz"(%d) {angle = 0.7} : (qubit) -> qubit
        return %e, %f
    }
}

Part IV — The hybrid Dialect (Classical + Quantum Bridge)

Declare with #dialect hybrid (usually combined with #dialect tensor and #dialect quantum). Provides 21 operations that bridge classical and quantum computing.

4.1 Encoding / Decoding (2)

OperationSyntaxDescription
Encode"hybrid.encode"Classical tensor → quantum state
Decode"hybrid.decode"Quantum state → classical tensor
%encoded = "hybrid.encode"(%data) {strategy = "angle"} : (tensor<1x4xf32>) -> qubit
%decoded = "hybrid.decode"(%qstate) : (qubit) -> tensor<1x4xf32>

Encoding Strategies

StrategyAttribute ValueQubits for N featuresDepthBest For
Angle"angle"N1Small vectors (<20)
Amplitude"amplitude"ceil(log2(N))NLarge vectors
Basis"basis"N1Binary data
IQP"iqp"N2NHigh expressivity
Hamiltonian"hamiltonian"NNPhysics problems
Kernel"kernel"N3NQuantum kernel methods

4.2 Gradient Methods (6)

OperationSyntaxEvaluationsExact
ParameterShift"hybrid.parameter_shift"2NYes
FiniteDifference"hybrid.finite_difference"N+1No
SPSA"hybrid.spsa"2No
AdjointDiff"hybrid.adjoint_diff"1Yes
StochasticParamShift"hybrid.stochastic_param_shift"2No
JointGradient"hybrid.joint_gradient"VariableMixed

Which to choose

SituationMethod
Few params (<50)Parameter Shift
Many params (>100)SPSA
Simulator onlyAdjoint Diff
Mixed classical+quantumJoint Gradient
Noisy hardwareStochastic Parameter Shift
// ParameterShift: exact gradient via 2 circuit evaluations per parameter
%grad1 = "hybrid.parameter_shift"(%expectation) : (tensor<1xf32>) -> tensor<1x16xf32>

// FiniteDifference: approximate gradient via N+1 evaluations
%grad2 = "hybrid.finite_difference"(%expectation) : (tensor<1xf32>) -> tensor<1x16xf32>

// SPSA: stochastic gradient, only 2 evaluations regardless of parameter count
%grad3 = "hybrid.spsa"(%expectation) : (tensor<1xf32>) -> tensor<1x16xf32>

// AdjointDiff: exact gradient in 1 evaluation (simulator only)
%grad4 = "hybrid.adjoint_diff"(%expectation) : (tensor<1xf32>) -> tensor<1x16xf32>

// JointGradient: use different methods for classical vs quantum parts
%grad5 = "hybrid.joint_gradient"(%hybrid_loss) : (tensor<1xf32>) -> tensor<1x32xf32>

4.3 Variational Algorithms (4)

OperationSyntaxDescription
VqcLayer"hybrid.vqc_layer"Generic variational circuit layer
VqeAnsatz"hybrid.vqe_ansatz"VQE chemistry ansatz
QaoaLayer"hybrid.qaoa_layer"QAOA combinatorial optimisation
QuantumKernel"hybrid.quantum_kernel"Quantum kernel (SVM)

Ansatz Types

TypeValueUse
HardwareEfficient"hardware_efficient"Near-term hardware
StronglyEntangling"strongly_entangling"Max expressivity
TwoLocal"two_local"General purpose
UCCSD"uccsd"Chemistry (VQE)
Custom"custom"User-defined
%q_out = "hybrid.vqc_layer"(%q_in) {ansatz = "hardware_efficient", layers = 3} : (qubit) -> qubit
%q_out = "hybrid.vqe_ansatz"(%q_in) {ansatz = "uccsd"} : (qubit) -> qubit
%q_out = "hybrid.qaoa_layer"(%q_in) {gamma = 0.5, beta = 0.3} : (qubit) -> qubit

4.4 Data Transfer (2)

OperationSyntaxDirection
GpuToQpu"hybrid.gpu_to_qpu"GPU → QPU
QpuToGpu"hybrid.qpu_to_gpu"QPU → GPU
%qubits = "hybrid.gpu_to_qpu"(%encoded) : (tensor<1x4xf32>) -> qubit
%results = "hybrid.qpu_to_gpu"(%measured) : (qubit) -> tensor<1x4xf32>

4.5 Processing (4)

OperationSyntaxDescription
ClassicalPreprocess"hybrid.classical_preprocess"Pre-quantum classical processing
QuantumPostprocess"hybrid.quantum_postprocess"Post-quantum processing
HybridForward"hybrid.forward"Full hybrid forward pass
HybridBackward"hybrid.backward"Full hybrid backward pass
// ClassicalPreprocess: transform classical data before quantum encoding
%prep = "hybrid.classical_preprocess"(%raw_data) : (tensor<1x100xf32>) -> tensor<1x8xf32>

// QuantumPostprocess: transform quantum measurement results
%post = "hybrid.quantum_postprocess"(%raw_measurement) : (tensor<4096xi32>) -> tensor<1x4xf32>

// HybridForward: execute the full classical+quantum forward pass
%fwd = "hybrid.forward"(%input) : (tensor<1x64xf32>) -> tensor<1x2xf32>

// HybridBackward: compute gradients through the full hybrid pipeline
%bwd = "hybrid.backward"(%loss) : (tensor<1xf32>) -> tensor<1x64xf32>

4.6 Co-Execution (1)

OperationSyntaxDescription
CoExecute"hybrid.co_execute"Run GPU + QPU simultaneously

Synchronisation Policies

PolicyValueDescription
Blocking"blocking"GPU waits for QPU
Asynchronous"async"Independent execution
Pipeline"pipeline"Streaming tasks
%result = "hybrid.co_execute"(%gpu_task, %qpu_task) {sync = "pipeline"} : (tensor<1x128xf32>, qubit) -> tensor<1x128xf32>

4.7 Measurement (2)

OperationSyntaxOutputDescription
MeasureExpectation"hybrid.measure_expectation"scalarExpectation value
MeasureSamples"hybrid.measure_samples"tensorRaw shot results
%val = "hybrid.measure_expectation"(%qubits) : (qubit) -> tensor<1xf32>
%samples = "hybrid.measure_samples"(%qubits) {shots = 4096} : (qubit) -> tensor<4096xi32>

4.8 Feature Maps (for quantum kernels)

Feature MapDescription
ZZFeatureMapZZ interactions
PauliFeatureMapPauli products
AngleEncodingRotation encoding
AmplitudeEncodingState amplitude
// Quantum kernel with ZZ feature map: compute kernel value between two data points
%kernel_val = "hybrid.quantum_kernel"(%encoded_x1, %encoded_x2) {feature_map = "zz"} : (qubit, qubit) -> tensor<1x1xf32>

// Quantum kernel with Pauli feature map
%kernel_val2 = "hybrid.quantum_kernel"(%encoded_a, %encoded_b) {feature_map = "pauli"} : (qubit, qubit) -> tensor<1x1xf32>

4.9 Complete Hybrid Example — Medical Imaging (CNN + VQC)

#dialect tensor
#dialect quantum
#dialect hybrid

module @medical_hybrid {
    func @classify(
        %img: tensor<1x1x28x28xf32>,
        %conv_w: tensor<16x1x3x3xf32>,
        %fc_w: tensor<784x4xf32>,
        %fc_b: tensor<4xf32>,
        %q0: qubit, %q1: qubit, %q2: qubit, %q3: qubit
    ) -> tensor<1x2xf32> {
        // Classical preprocessing: CNN feature extraction
        %feat = "tensor.conv2d"(%img, %conv_w) : (tensor<1x1x28x28xf32>, tensor<16x1x3x3xf32>) -> tensor<1x16x26x26xf32>
        %act = "tensor.relu"(%feat) : (tensor<1x16x26x26xf32>) -> tensor<1x16x26x26xf32>
        %pool = "tensor.global_avgpool"(%act) : (tensor<1x16x26x26xf32>) -> tensor<1x16x1x1xf32>
        %flat = "tensor.reshape"(%pool) : (tensor<1x16x1x1xf32>) -> tensor<1x16xf32>

        // Reduce to 4 features for 4 qubits
        %reduced = "tensor.linear"(%flat, %fc_w, %fc_b) : (tensor<1x16xf32>, tensor<16x4xf32>, tensor<4xf32>) -> tensor<1x4xf32>

        // Encode into quantum state
        %encoded = "hybrid.encode"(%reduced) {strategy = "angle"} : (tensor<1x4xf32>) -> qubit

        // Quantum processing
        %q_a = "hybrid.vqc_layer"(%encoded) {ansatz = "hardware_efficient", layers = 2} : (qubit) -> qubit

        // Measure expectation values
        %expectation = "hybrid.measure_expectation"(%q_a) : (qubit) -> tensor<1x2xf32>

        // Classical postprocessing
        %probs = "tensor.softmax"(%expectation) : (tensor<1x2xf32>) -> tensor<1x2xf32>
        return %probs
    }
}

4.10 Complete Hybrid Example — VQE for Chemistry

#dialect tensor
#dialect quantum
#dialect hybrid

module @vqe_molecule {
    func @energy_estimation(
        %params: tensor<1x16xf32>,
        %q0: qubit, %q1: qubit, %q2: qubit, %q3: qubit
    ) -> tensor<1xf32> {
        // Encode parameters into quantum state
        %encoded = "hybrid.encode"(%params) {strategy = "amplitude"} : (tensor<1x16xf32>) -> qubit

        // Apply VQE ansatz (UCCSD for chemistry)
        %ansatz_out = "hybrid.vqe_ansatz"(%encoded) {ansatz = "uccsd"} : (qubit) -> qubit

        // Measure energy expectation
        %energy = "hybrid.measure_expectation"(%ansatz_out) : (qubit) -> tensor<1xf32>

        // Compute gradient for parameter update
        %grad = "hybrid.parameter_shift"(%energy) : (tensor<1xf32>) -> tensor<1x16xf32>

        return %energy
    }
}

4.11 Complete Hybrid Example — QAOA for Optimisation

#dialect tensor
#dialect quantum
#dialect hybrid

module @qaoa_portfolio {
    func @optimise(
        %gamma: tensor<1xf32>,
        %beta: tensor<1xf32>,
        %q0: qubit, %q1: qubit, %q2: qubit, %q3: qubit, %q4: qubit
    ) -> tensor<1xf32> {
        // QAOA layer with problem-specific parameters
        %q_out = "hybrid.qaoa_layer"(%q0) {gamma = 0.5, beta = 0.3} : (qubit) -> qubit

        // Sample the result
        %samples = "hybrid.measure_samples"(%q_out) {shots = 8192} : (qubit) -> tensor<8192xi32>

        // Classical post-processing: evaluate cost function
        %cost = "hybrid.quantum_postprocess"(%samples) : (tensor<8192xi32>) -> tensor<1xf32>

        return %cost
    }
}

Part V — Configuration (.lith Files)

The .lith file controls compilation, optimisation, budgets, and hardware targeting. It uses a simple INI format.

5.1 File Format

# Comment (ignored)
// Also a comment

[section_name]
key = value
key2 = "quoted value"

5.2 [target] Section

KeyTypeValuesDefault
backendstringllvm, onnx, qasmllvm
devicestringA100, H100, ibm_eagle, ibm_kyoto, rigetti, ionq, quantinuumnone
precisionstringfp64, fp32, fp16, bf16fp32
[target]
backend = llvm
device = A100
precision = fp32
  • llvm backend → exports to LLVM IR (CUDA PTX, x86-64, ARM)
  • onnx backend → exports to ONNX protobuf text (opset 21, PyTorch/TensorFlow/TensorRT interop)
  • qasm backend → exports to OpenQASM 3.0 (IBM Quantum, Amazon Braket, Azure Quantum)

5.3 [budget] Section

All fields are optional. Omitted fields impose no constraint.

KeyTypeDescription
max_flopsu64Maximum FLOPs allowed
max_memory_bytesu64Maximum memory in bytes
max_time_msf64Maximum execution time (ms)
min_fidelityf64Minimum quantum fidelity (0.0–1.0)
max_circuit_depthusizeMaximum quantum circuit depth
[budget]
max_flops = 10000000000
max_memory_bytes = 80000000000
max_time_ms = 100.0
min_fidelity = 0.90
max_circuit_depth = 1000

5.4 [optimisation] Section

KeyTypeValuesDefault
levelenumO0, O1, O2, O3O2
max_iterationsusizeAny positive integer10
[optimisation]
level = O2
max_iterations = 10

Optimisation Levels

LevelWhat it does
O0No optimisation (debug mode)
O1Canonicalize + Dead Code Elimination
O2+ Tensor Fusion + Constant Folding + Gate Cancellation + Rotation Merge
O3+ Flash Attention + CSE + Quantisation Pass + Noise-Aware Schedule + Layout Mapping

Default passes at O2

canonicalize, constant-folding, dce, tensor-fusion

All available optimisation passes

PassDialectDescription
canonicalizeAllSimplify operations to canonical forms
constant-foldingTensorEvaluate constant expressions at compile time
dceAllRemove dead (unused) operations
tensor-fusionTensorFuse adjacent tensor operations into single kernels
flash-attentionTensorReplace standard attention with flash attention
cseAllCommon Subexpression Elimination
quantisation-passTensorApply INT8/INT4/FP8 quantisation
gate-cancellationQuantumCancel adjacent inverse gates (H·H=I, X·X=I)
rotation-mergeQuantumMerge consecutive rotations (RZ(a)·RZ(b)=RZ(a+b))
noise-aware-scheduleQuantumSchedule gates considering hardware noise
layout-mappingQuantumMap logical qubits to physical qubits (SABRE algorithm)

5.5 [simulation] Section

KeyTypeDefault
shape_propagationbooltrue
flop_countingbooltrue
memory_analysisbooltrue
noise_simulationbooltrue
[simulation]
shape_propagation = true
flop_counting = true
memory_analysis = true
noise_simulation = true

5.6 [quantum] Section

Only needed for quantum or hybrid programs.

KeyTypeValuesDefault
topologystringgrid, heavy_hex, all_to_all, linear, treelinear
num_qubitsusizeAny positive integer5
error_mitigationstringMitigation strategy namenone
shotsusizeNumber of measurement shotsnone
[quantum]
topology = heavy_hex
num_qubits = 127
error_mitigation = zne
shots = 8192

Quantum Topologies

TopologyDescriptionProvider
linearQubits in a lineGeneral
grid2D gridGoogle Sycamore
heavy_hexHeavy-hexagonal latticeIBM Eagle/Heron
all_to_allFull connectivityIonQ, Quantinuum
treeTree structureCustom

5.7 Complete .lith Examples

Classical AI (GPU inference)

# config_gpu.lith — Optimised GPU inference
[target]
backend = llvm
device = A100
precision = fp16

[budget]
max_memory_bytes = 16000000000
max_time_ms = 50.0

[optimisation]
level = O3
max_iterations = 20

[simulation]
shape_propagation = true
flop_counting = true
memory_analysis = true
noise_simulation = false

Quantum circuit (IBM hardware)

# config_ibm.lith — IBM Eagle quantum processor
[target]
backend = qasm
device = ibm_eagle

[budget]
min_fidelity = 0.85
max_circuit_depth = 500

[optimisation]
level = O3
max_iterations = 15

[simulation]
shape_propagation = false
flop_counting = false
memory_analysis = false
noise_simulation = true

[quantum]
topology = heavy_hex
num_qubits = 127
error_mitigation = zne
shots = 4096

Hybrid (GPU + QPU)

# config_hybrid.lith — Medical imaging hybrid
[target]
backend = llvm
device = A100
precision = fp32

[budget]
max_memory_bytes = 40000000000
max_time_ms = 10000.0
min_fidelity = 0.80
max_circuit_depth = 200

[optimisation]
level = O2
max_iterations = 10

[simulation]
shape_propagation = true
flop_counting = true
memory_analysis = true
noise_simulation = true

[quantum]
topology = heavy_hex
num_qubits = 16
shots = 4096

Edge deployment (low power)

# config_edge.lith — Edge device deployment
[target]
backend = llvm
device = ARM
precision = fp16

[budget]
max_memory_bytes = 500000000
max_time_ms = 30.0

[optimisation]
level = O3
max_iterations = 30

[simulation]
shape_propagation = true
flop_counting = true
memory_analysis = true
noise_simulation = false

Part VI — Assembling Dialects Together

6.1 Single-Dialect Programs

Tensor only — MLP classifier

#dialect tensor

module @mlp {
    func @forward(
        %x: tensor<1x784xf32>,
        %w1: tensor<784x256xf32>, %b1: tensor<256xf32>,
        %w2: tensor<256x10xf32>, %b2: tensor<10xf32>
    ) -> tensor<1x10xf32> {
        %h1 = "tensor.matmul"(%x, %w1) : (tensor<1x784xf32>, tensor<784x256xf32>) -> tensor<1x256xf32>
        %h2 = "tensor.add"(%h1, %b1) : (tensor<1x256xf32>, tensor<256xf32>) -> tensor<1x256xf32>
        %h3 = "tensor.relu"(%h2) : (tensor<1x256xf32>) -> tensor<1x256xf32>
        %h4 = "tensor.matmul"(%h3, %w2) : (tensor<1x256xf32>, tensor<256x10xf32>) -> tensor<1x10xf32>
        %h5 = "tensor.add"(%h4, %b2) : (tensor<1x10xf32>, tensor<10xf32>) -> tensor<1x10xf32>
        %out = "tensor.softmax"(%h5) : (tensor<1x10xf32>) -> tensor<1x10xf32>
        return %out
    }
}

Tensor only — Transformer self-attention

#dialect tensor

module @transformer {
    func @self_attention(
        %q: tensor<1x128x64xf32>,
        %k: tensor<1x128x64xf32>,
        %v: tensor<1x128x64xf32>,
        %norm_w: tensor<64xf32>
    ) -> tensor<1x128x64xf32> {
        %attn = "tensor.attention"(%q, %k, %v) : (tensor<1x128x64xf32>, tensor<1x128x64xf32>, tensor<1x128x64xf32>) -> tensor<1x128x64xf32>
        %normed = "tensor.layernorm"(%attn, %norm_w) : (tensor<1x128x64xf32>, tensor<64xf32>) -> tensor<1x128x64xf32>
        return %normed
    }
}

Tensor only — CNN for image classification

#dialect tensor

module @cnn {
    func @forward(
        %img: tensor<1x3x224x224xf32>,
        %conv1_w: tensor<64x3x7x7xf32>,
        %bn_s: tensor<64xf32>, %bn_b: tensor<64xf32>, %bn_m: tensor<64xf32>,
        %fc_w: tensor<1024x1000xf32>, %fc_b: tensor<1000xf32>
    ) -> tensor<1x1000xf32> {
        // Conv + BatchNorm + ReLU (fused)
        %c1 = "tensor.fused_conv_batchnorm_relu"(%img, %conv1_w, %bn_s, %bn_b, %bn_m) : (tensor<1x3x224x224xf32>, tensor<64x3x7x7xf32>, tensor<64xf32>, tensor<64xf32>, tensor<64xf32>) -> tensor<1x64x112x112xf32>
        // Pooling
        %p1 = "tensor.global_avgpool"(%c1) : (tensor<1x64x112x112xf32>) -> tensor<1x64x1x1xf32>
        %flat = "tensor.reshape"(%p1) : (tensor<1x64x1x1xf32>) -> tensor<1x64xf32>
        // Classifier
        %logits = "tensor.linear"(%flat, %fc_w, %fc_b) : (tensor<1x64xf32>, tensor<64x1000xf32>, tensor<1000xf32>) -> tensor<1x1000xf32>
        %probs = "tensor.softmax"(%logits) : (tensor<1x1000xf32>) -> tensor<1x1000xf32>
        return %probs
    }
}

Tensor only — GNN

#dialect tensor

module @gnn {
    func @forward(
        %nodes: tensor<100x16xf32>,
        %edges: tensor<100x100xf32>,
        %w: tensor<16x16xf32>, %b: tensor<16xf32>
    ) -> tensor<1x16xf32> {
        // Message passing
        %h1 = "tensor.gnn_message_passing"(%nodes, %edges) : (tensor<100x16xf32>, tensor<100x100xf32>) -> tensor<100x16xf32>
        %h2 = "tensor.relu"(%h1) : (tensor<100x16xf32>) -> tensor<100x16xf32>
        // Second layer
        %h3 = "tensor.gnn_message_passing"(%h2, %edges) : (tensor<100x16xf32>, tensor<100x100xf32>) -> tensor<100x16xf32>
        // Global pooling
        %graph = "tensor.gnn_global_pooling"(%h3) : (tensor<100x16xf32>) -> tensor<1x16xf32>
        return %graph
    }
}

Quantum only — Quantum Teleportation

#dialect quantum

module @teleportation {
    func @teleport(%psi: qubit, %q1: qubit, %q2: qubit) -> (qubit, qubit, qubit) {
        // Create Bell pair between q1 and q2
        %a = "quantum.h"(%q1) : (qubit) -> qubit
        %b, %c = "quantum.cx"(%a, %q2) : (qubit, qubit) -> (qubit, qubit)

        // Bell measurement on psi and b
        %d, %e = "quantum.cx"(%psi, %b) : (qubit, qubit) -> (qubit, qubit)
        %f = "quantum.h"(%d) : (qubit) -> qubit

        // Measure
        %m1 = "quantum.measure"(%f) : (qubit) -> qubit
        %m2 = "quantum.measure"(%e) : (qubit) -> qubit

        return %m1, %m2, %c
    }
}

Quantum only — Quantum Fourier Transform (3 qubits)

#dialect quantum

module @qft {
    func @qft3(%q0: qubit, %q1: qubit, %q2: qubit) -> (qubit, qubit, qubit) {
        // First qubit
        %a = "quantum.h"(%q0) : (qubit) -> qubit
        %b, %c = "quantum.cp"(%q1, %a) {angle = 1.5708} : (qubit, qubit) -> (qubit, qubit)
        %d, %e = "quantum.cp"(%q2, %c) {angle = 0.7854} : (qubit, qubit) -> (qubit, qubit)

        // Second qubit
        %f = "quantum.h"(%b) : (qubit) -> qubit
        %g, %h = "quantum.cp"(%d, %f) {angle = 1.5708} : (qubit, qubit) -> (qubit, qubit)

        // Third qubit
        %i = "quantum.h"(%g) : (qubit) -> qubit

        // Swap first and last
        %j, %k = "quantum.swap"(%e, %i) : (qubit, qubit) -> (qubit, qubit)

        return %j, %h, %k
    }
}

6.2 Multi-Dialect Programs

Tensor + Quantum — Feature extraction + quantum classification

#dialect tensor
#dialect quantum
#dialect hybrid

module @hybrid_classifier {
    func @forward(
        %img: tensor<1x1x28x28xf32>,
        %w1: tensor<16x1x5x5xf32>,
        %w2: tensor<256x4xf32>, %b2: tensor<4xf32>,
        %q0: qubit, %q1: qubit, %q2: qubit, %q3: qubit
    ) -> tensor<1x2xf32> {

        // ──── Stage 1: Classical (tensor dialect) ────
        %conv = "tensor.conv2d"(%img, %w1) : (tensor<1x1x28x28xf32>, tensor<16x1x5x5xf32>) -> tensor<1x16x24x24xf32>
        %act = "tensor.relu"(%conv) : (tensor<1x16x24x24xf32>) -> tensor<1x16x24x24xf32>
        %pool = "tensor.adaptive_avgpool2d"(%act) : (tensor<1x16x24x24xf32>) -> tensor<1x16x4x4xf32>
        %flat = "tensor.reshape"(%pool) : (tensor<1x16x4x4xf32>) -> tensor<1x256xf32>
        %features = "tensor.linear"(%flat, %w2, %b2) : (tensor<1x256xf32>, tensor<256x4xf32>, tensor<4xf32>) -> tensor<1x4xf32>

        // ──── Stage 2: Encoding (hybrid dialect) ────
        %encoded = "hybrid.encode"(%features) {strategy = "angle"} : (tensor<1x4xf32>) -> qubit

        // ──── Stage 3: Quantum circuit (quantum dialect via hybrid) ────
        %processed = "hybrid.vqc_layer"(%encoded) {ansatz = "strongly_entangling", layers = 4} : (qubit) -> qubit

        // ──── Stage 4: Measurement (hybrid dialect) ────
        %raw = "hybrid.measure_expectation"(%processed) : (qubit) -> tensor<1x2xf32>

        // ──── Stage 5: Post-processing (tensor dialect) ────
        %probs = "tensor.softmax"(%raw) : (tensor<1x2xf32>) -> tensor<1x2xf32>

        return %probs
    }
}

Drug Discovery — GNN + VQE

#dialect tensor
#dialect quantum
#dialect hybrid

module @drug_discovery {
    func @screen_molecule(
        %atoms: tensor<50x16xf32>,
        %bonds: tensor<50x50xf32>,
        %q0: qubit, %q1: qubit, %q2: qubit, %q3: qubit
    ) -> tensor<1xf32> {

        // Stage 1: GNN feature extraction
        %h1 = "tensor.gnn_message_passing"(%atoms, %bonds) : (tensor<50x16xf32>, tensor<50x50xf32>) -> tensor<50x16xf32>
        %h2 = "tensor.relu"(%h1) : (tensor<50x16xf32>) -> tensor<50x16xf32>
        %h3 = "tensor.gnn_message_passing"(%h2, %bonds) : (tensor<50x16xf32>, tensor<50x50xf32>) -> tensor<50x16xf32>
        %mol = "tensor.gnn_global_pooling"(%h3) : (tensor<50x16xf32>) -> tensor<1x16xf32>

        // Stage 2: Reduce to qubit count and encode
        %flat = "tensor.reshape"(%mol) : (tensor<1x16xf32>) -> tensor<1x16xf32>
        %encoded = "hybrid.encode"(%flat) {strategy = "amplitude"} : (tensor<1x16xf32>) -> qubit

        // Stage 3: VQE for energy calculation
        %ansatz = "hybrid.vqe_ansatz"(%encoded) {ansatz = "uccsd"} : (qubit) -> qubit

        // Stage 4: Energy measurement
        %energy = "hybrid.measure_expectation"(%ansatz) : (qubit) -> tensor<1xf32>

        return %energy
    }
}

Quantum Finance — QAOA Portfolio Optimisation

#dialect tensor
#dialect quantum
#dialect hybrid

module @quantum_finance {
    func @optimise_portfolio(
        %returns: tensor<1x10xf32>,
        %covariance: tensor<10x10xf32>,
        %q0: qubit, %q1: qubit, %q2: qubit, %q3: qubit, %q4: qubit
    ) -> tensor<1x5xf32> {

        // Classical: compute expected returns
        %scores = "tensor.matmul"(%returns, %covariance) : (tensor<1x10xf32>, tensor<10x10xf32>) -> tensor<1x10xf32>

        // Preprocess for quantum
        %preprocessed = "hybrid.classical_preprocess"(%scores) : (tensor<1x10xf32>) -> tensor<1x5xf32>

        // Encode
        %encoded = "hybrid.encode"(%preprocessed) {strategy = "angle"} : (tensor<1x5xf32>) -> qubit

        // QAOA optimisation
        %qaoa_result = "hybrid.qaoa_layer"(%encoded) {gamma = 0.7, beta = 0.4} : (qubit) -> qubit

        // Measure
        %samples = "hybrid.measure_samples"(%qaoa_result) {shots = 8192} : (qubit) -> tensor<8192xi32>

        // Post-process: extract best portfolio allocation
        %allocation = "hybrid.quantum_postprocess"(%samples) : (tensor<8192xi32>) -> tensor<1x5xf32>

        return %allocation
    }
}

6.3 Multi-Function Modules

A module can contain multiple functions that call different dialects:

#dialect tensor
#dialect quantum
#dialect hybrid

module @full_pipeline {

    // Classical preprocessing function
    func @preprocess(%img: tensor<1x3x224x224xf32>, %w: tensor<64x3x7x7xf32>) -> tensor<1x64xf32> {
        %c = "tensor.conv2d"(%img, %w) : (tensor<1x3x224x224xf32>, tensor<64x3x7x7xf32>) -> tensor<1x64x112x112xf32>
        %a = "tensor.relu"(%c) : (tensor<1x64x112x112xf32>) -> tensor<1x64x112x112xf32>
        %p = "tensor.global_avgpool"(%a) : (tensor<1x64x112x112xf32>) -> tensor<1x64x1x1xf32>
        %f = "tensor.reshape"(%p) : (tensor<1x64x1x1xf32>) -> tensor<1x64xf32>
        return %f
    }

    // Quantum processing function
    func @quantum_layer(%q0: qubit, %q1: qubit) -> (qubit, qubit) {
        %a = "quantum.ry"(%q0) {angle = 0.5} : (qubit) -> qubit
        %b = "quantum.ry"(%q1) {angle = 1.0} : (qubit) -> qubit
        %c, %d = "quantum.cx"(%a, %b) : (qubit, qubit) -> (qubit, qubit)
        %e = "quantum.rz"(%c) {angle = 0.3} : (qubit) -> qubit
        return %e, %d
    }

    // Hybrid pipeline function
    func @classify(
        %features: tensor<1x4xf32>,
        %q0: qubit, %q1: qubit
    ) -> tensor<1x2xf32> {
        %encoded = "hybrid.encode"(%features) {strategy = "angle"} : (tensor<1x4xf32>) -> qubit
        %processed = "hybrid.vqc_layer"(%encoded) {ansatz = "hardware_efficient", layers = 2} : (qubit) -> qubit
        %result = "hybrid.measure_expectation"(%processed) : (qubit) -> tensor<1x2xf32>
        %probs = "tensor.softmax"(%result) : (tensor<1x2xf32>) -> tensor<1x2xf32>
        return %probs
    }
}

6.4 Common Patterns and Recipes

Pattern 1: Linear Layer (matmul + bias + activation)

%h = "tensor.matmul"(%x, %w) : (tensor<BxMxf32>, tensor<MxNxf32>) -> tensor<BxNxf32>
%b = "tensor.add"(%h, %bias) : (tensor<BxNxf32>, tensor<Nxf32>) -> tensor<BxNxf32>
%a = "tensor.relu"(%b) : (tensor<BxNxf32>) -> tensor<BxNxf32>

Or fused:

%a = "tensor.fused_matmul_bias_relu"(%x, %w, %bias) : (tensor<BxMxf32>, tensor<MxNxf32>, tensor<Nxf32>) -> tensor<BxNxf32>

Pattern 2: Transformer Block

%attn = "tensor.multi_head_attention"(%q, %k, %v) : ...
%res1 = "tensor.add"(%attn, %input) : ...
%norm1 = "tensor.layernorm"(%res1, %scale1) : ...
%ff1 = "tensor.linear"(%norm1, %w1, %b1) : ...
%act = "tensor.gelu"(%ff1) : ...
%ff2 = "tensor.linear"(%act, %w2, %b2) : ...
%res2 = "tensor.add"(%ff2, %norm1) : ...
%norm2 = "tensor.layernorm"(%res2, %scale2) : ...

Pattern 3: Bell Pair + Measurement

%h = "quantum.h"(%q0) : (qubit) -> qubit
%a, %b = "quantum.cx"(%h, %q1) : (qubit, qubit) -> (qubit, qubit)
%m0 = "quantum.measure"(%a) : (qubit) -> qubit
%m1 = "quantum.measure"(%b) : (qubit) -> qubit

Pattern 4: Variational Layer (rotation + entangling + rotation)

%r0 = "quantum.ry"(%q0) {angle = 0.5} : (qubit) -> qubit
%r1 = "quantum.ry"(%q1) {angle = 0.8} : (qubit) -> qubit
%e0, %e1 = "quantum.cx"(%r0, %r1) : (qubit, qubit) -> (qubit, qubit)
%f0 = "quantum.rz"(%e0) {angle = 0.3} : (qubit) -> qubit
%f1 = "quantum.rz"(%e1) {angle = 0.7} : (qubit) -> qubit

Pattern 5: Hybrid Pipeline (encode → process → measure → postprocess)

%enc = "hybrid.encode"(%data) {strategy = "angle"} : (tensor<...>) -> qubit
%proc = "hybrid.vqc_layer"(%enc) {ansatz = "hardware_efficient", layers = 3} : (qubit) -> qubit
%meas = "hybrid.measure_expectation"(%proc) : (qubit) -> tensor<...>
%out = "tensor.softmax"(%meas) : (tensor<...>) -> tensor<...>

Pattern 6: Quantisation for Edge Deployment

%q_weights = "tensor.quantize"(%weights) : (tensor<256x256xf32>) -> tensor<256x256xi8>
%output = "tensor.matmul"(%input, %q_weights) : ...
%dq = "tensor.dequantize"(%output) : (tensor<...xi8>) -> tensor<...xf32>

Pattern 7: Training with Gradient Accumulation

%fwd = "tensor.linear"(%x, %w, %b) : ...
%loss = "tensor.softmax"(%fwd) : ...
%grad = "tensor.grad_linear"(%loss, %w, %b) : ...
%acc = "tensor.grad_accumulate"(%grad) : ...

Pattern 8: Distributed Training

%split = "tensor.parallel_split"(%batch) : ...
%local = "tensor.matmul"(%split, %w) : ...
%synced = "tensor.parallel_allreduce"(%local) : ...

6.5 Error Checklist

Common mistakes and how to avoid them:

ErrorCauseFix
Unknown operation: tensor.xxxTypo in operation nameCheck exact name in this reference
Unknown operation: quantum.xxxMissing #dialect quantumAdd #dialect quantum at top
SSA violation%name assigned twiceUse a new name for each result
Linearity violationQubit used twiceEach qubit value consumed exactly once
Qubit leakedQubit created but not consumedReturn or measure all qubits
Wrong number of inputsOperation got wrong operand countCheck input count in tables above
Type mismatchTensor shapes incompatibleVerify shapes match (e.g. matmul: [M,K]×[K,N])
Missing type signatureNo : (types) -> typeAlways include type signature
Missing #dialectUsing ops without declaring dialectAdd #dialect <name> at file top
Attribute errorParametric gate missing angleAdd {angle = ...} for RX, RY, RZ, etc.

6.6 Quick Syntax Reference Card

┌─────────────────────────────────────────────────────┐
│ #dialect tensor / quantum / hybrid                  │
│                                                     │
│ module @name {                                      │
│   func @fn(%x: type, ...) -> type {                 │
│     %y = "dialect.op"(%x) {attrs} : (T) -> T       │
│     %a, %b = "dialect.op"(%x, %y) : (T,T) -> (T,T) │
│     return %y                                       │
│   }                                                 │
│ }                                                   │
├─────────────────────────────────────────────────────┤
│ TYPES:                                              │
│   tensor<DxDxDxdtype>  e.g. tensor<1x784xf32>      │
│   qubit                (linear — consumed once)     │
│   bit                  (classical measurement)      │
│   hamiltonian<N>       (N-qubit operator)           │
│   f32, i32, bool, void, index                       │
├─────────────────────────────────────────────────────┤
│ DTYPES:                                             │
│   f64 f32 f16 bf16 fp8e4m3 fp8e5m2                 │
│   i64 i32 i16 i8 i4 i2 u8 i1 index                │
├─────────────────────────────────────────────────────┤
│ ATTRIBUTES:                                         │
│   {key = 42, rate = 0.5, flag = true, s = "text"}  │
│   {arr = [1, 2, 3]}                                │
├─────────────────────────────────────────────────────┤
│ DIALECTS:                                           │
│   tensor: 96 ops  (AI / ML)                        │
│   quantum: 50+ ops (quantum circuits)              │
│   hybrid:  21 ops  (classical ↔ quantum bridge)    │
└─────────────────────────────────────────────────────┘

Appendix — Complete Operation Index

A.1 All Tensor Operations (96)

#CategorySyntax
1Arithmetictensor.add
2Arithmetictensor.sub
3Arithmetictensor.mul
4Arithmetictensor.div
5Arithmetictensor.neg
6Arithmetictensor.matmul
7Arithmetictensor.linear
8Arithmetictensor.conv2d
9Arithmetictensor.embedding
10Activationtensor.relu
11Activationtensor.gelu
12Activationtensor.silu
13Activationtensor.sigmoid
14Activationtensor.softmax
15Activationtensor.tanh
16Activationtensor.leaky_relu
17Activationtensor.elu
18Activationtensor.mish
19Activationtensor.hard_swish
20Activationtensor.hard_sigmoid
21Normalisationtensor.layernorm
22Normalisationtensor.rmsnorm
23Normalisationtensor.batchnorm
24Normalisationtensor.groupnorm
25Normalisationtensor.instancenorm
26Shapetensor.reshape
27Shapetensor.transpose
28Shapetensor.concat
29Shapetensor.split
30Shapetensor.gather
31Shapetensor.scatter
32Shapetensor.squeeze
33Shapetensor.unsqueeze
34Shapetensor.permute
35Shapetensor.expand
36Shapetensor.slice
37Shapetensor.pad
38Shapetensor.tile
39Attentiontensor.attention
40Attentiontensor.multi_head_attention
41Attentiontensor.multi_query_attention
42Attentiontensor.grouped_query_attention
43Attentiontensor.flash_attention
44Attentiontensor.sliding_window_attention
45Attentiontensor.cross_attention
46Attentiontensor.paged_attention
47Convolutiontensor.conv1d
48Convolutiontensor.conv3d
49Convolutiontensor.conv_transpose2d
50Convolutiontensor.depthwise_conv2d
51Convolutiontensor.dilated_conv2d
52Poolingtensor.maxpool2d
53Poolingtensor.avgpool2d
54Poolingtensor.adaptive_avgpool2d
55Poolingtensor.global_avgpool
56Recurrenttensor.lstm_cell
57Recurrenttensor.gru_cell
58Recurrenttensor.rnn_cell
59Mathtensor.einsum
60Mathtensor.fft
61Mathtensor.ifft
62Mathtensor.svd
63Mathtensor.eig
64Mathtensor.solve
65Mathtensor.topk
66Mathtensor.sort
67Mathtensor.cumsum
68Mathtensor.where
69Mathtensor.clamp
70Sparsetensor.sparse_matmul
71Sparsetensor.sparse_embedding
72Quantisationtensor.quantize
73Quantisationtensor.dequantize
74Quantisationtensor.quantize_int4
75Quantisationtensor.dequantize_int4
76Quantisationtensor.quantize_fp8
77Quantisationtensor.dequantize_fp8
78Generativetensor.unet_down_block
79Generativetensor.unet_up_block
80Generativetensor.timestep_embedding
81GNNtensor.gnn_message_passing
82GNNtensor.gnn_global_pooling
83MoEtensor.moe_dispatch
84MoEtensor.moe_combine
85Constantstensor.constant
86Constantstensor.zeros
87Constantstensor.ones
88Constantstensor.arange
89Constantstensor.full
90Memorytensor.checkpoint
91Memorytensor.offload
92Memorytensor.grad_accumulate
93Gradienttensor.grad_matmul
94Gradienttensor.grad_relu
95Gradienttensor.grad_softmax
96Gradienttensor.grad_layernorm
97Gradienttensor.grad_attention
98Gradienttensor.grad_conv2d
99Gradienttensor.grad_linear
100Gradienttensor.grad_gelu
101Parallelismtensor.parallel_split
102Parallelismtensor.parallel_allreduce
103Parallelismtensor.pipeline_send
104Parallelismtensor.pipeline_receive
105Fusedtensor.fused_matmul_bias_relu
106Fusedtensor.fused_matmul_bias
107Fusedtensor.fused_linear_gelu
108Fusedtensor.fused_attention_layernorm
109Fusedtensor.fused_linear_silu
110Fusedtensor.fused_conv_batchnorm_relu

A.2 All Quantum Operations (50+)

#CategorySyntaxQubits
11Q Standardquantum.h1
21Q Standardquantum.x1
31Q Standardquantum.y1
41Q Standardquantum.z1
51Q Standardquantum.s1
61Q Standardquantum.sdg1
71Q Standardquantum.t1
81Q Standardquantum.tdg1
91Q Standardquantum.sx1
101Q Parametricquantum.rx1
111Q Parametricquantum.ry1
121Q Parametricquantum.rz1
131Q Parametricquantum.p1
141Q Parametricquantum.u11
151Q Parametricquantum.u21
161Q Parametricquantum.u31
171Q Fixedquantum.rx901
181Q Fixedquantum.rx1801
192Qquantum.cx2
202Qquantum.cz2
212Qquantum.cy2
222Qquantum.swap2
232Qquantum.iswap2
242Qquantum.ecr2
252Qquantum.rzx2
262Qquantum.xx2
272Qquantum.yy2
282Qquantum.zz2
292Qquantum.cp2
302Qquantum.cphase2
312Qquantum.xy2
32IonQquantum.gpi1
33IonQquantum.gpi21
34IonQquantum.ms2
353Qquantum.ccx3
363Qquantum.cswap3
37Multiquantum.mcxN
38Multiquantum.mczN
39Controlquantum.measure1
40Controlquantum.measure_allN
41Controlquantum.reset1
42Controlquantum.barrierN
43Controlquantum.init1
44Controlquantum.delay0
45Controlquantum.virtual_rz1
46Controlquantum.if_else0
47Specialquantum.global_phase0
48Specialquantum.param_gate0

A.3 All Hybrid Operations (21)

#CategorySyntax
1Encodinghybrid.encode
2Encodinghybrid.decode
3Gradienthybrid.parameter_shift
4Gradienthybrid.finite_difference
5Gradienthybrid.spsa
6Gradienthybrid.adjoint_diff
7Gradienthybrid.stochastic_param_shift
8Gradienthybrid.joint_gradient
9Processinghybrid.classical_preprocess
10Processinghybrid.quantum_postprocess
11Processinghybrid.forward
12Processinghybrid.backward
13Variationalhybrid.vqc_layer
14Variationalhybrid.vqe_ansatz
15Variationalhybrid.qaoa_layer
16Variationalhybrid.quantum_kernel
17Transferhybrid.gpu_to_qpu
18Transferhybrid.qpu_to_gpu
19Executionhybrid.co_execute
20Measurementhybrid.measure_expectation
21Measurementhybrid.measure_samples

End of LIFT Dialect Reference.

Total operations documented: 110 tensor + 48 quantum + 21 hybrid = 179 operations.

This document is the complete, error-free, authoritative reference for all LIFT dialects, their syntax, configuration, and assembly.

LIFT Framework

LIFT

Language for Intelligent Frameworks and Technologies

The first Intermediate Representation built natively for both AI and Quantum Computing.

Simulate before you run. Compile once. Optimise everywhere.

License: MIT Rust Tests Version Status


Overview

LIFT is a unified compiler infrastructure that treats AI computation (tensors, gradients, attention) and quantum computation (qubits, gates, noise models) as first-class citizens in the same SSA-based intermediate representation. One .lif source file, one .lith config, one pipeline: simulate, predict, optimise, compile.

 .lif source ──► LIFT-CORE (SSA IR) ──► SIMULATE ──► PREDICT ──► OPTIMISE ──► COMPILE
                      │                                                          │
          ┌───────────┼───────────┐                                 ┌────────────┼────────────┐
     LIFT-TENSOR  LIFT-QUANTUM  LIFT-HYBRID                    CUDA (GPU)   OpenQASM 3   LLVM (CPU)   ONNX
     110 tensor   48 gates     21 hybrid                      H100/A100    IBM/Rigetti   AVX-512      TensorRT
     operations   Kraus/QEC     VQC/VQE ops                    MI300        IonQ          OpenMP       PyTorch

Why LIFT?

No existing IR handles both AI and quantum in a single representation.

CapabilityMLIRONNXOpenQASMQiskitLIFT
AI tensor operationsYY--Y
Quantum gate operations--YYY
Unified AI + Quantum IR---~Y
Noise as type-level attribute----Y
Linear qubit types (no-cloning)----Y
Budget enforcement before compile----Y
Single config for entire pipeline----Y
Performance prediction engine----Y

Key: Y = implemented, ~ = partial, - = not supported

What makes LIFT unique

  1. One IR for AI + Quantum -- Both are equal citizens in the same SSA graph. Joint optimisation across classical and quantum operations.
  2. Noise in the type system -- Every quantum gate carries T1/T2, fidelity, crosstalk metadata. The compiler reasons about noise at every stage.
  3. Linear qubit types -- The no-cloning theorem enforced at compile time. Double-use of a qubit is a type error, not a runtime crash.
  4. Simulation-first compilation -- FLOP count, peak memory, circuit depth, expected fidelity, energy cost -- all computed before hardware runs. Budget violations halt compilation with actionable suggestions.
  5. One config language -- The .lith file replaces 6-8 separate configuration files across frameworks.

Architecture

  USER        .lif source  |  .lith config  |  lift(1) CLI
  FRONTEND    Lexer > Parser > AST > SSA Builder  |  Importers: ONNX, PyTorch FX, OpenQASM 3
  DIALECTS    LIFT-CORE  |  LIFT-TENSOR  |  LIFT-QUANTUM  |  LIFT-HYBRID
  ANALYSIS    Shape inference  |  FLOP count  |  Noise sim  |  Energy model  |  Roofline
  PASSES      TensorFusion  FlashAttention  GateCancellation  RotationMerge  LayoutMapping  CSE ...
  BACKENDS    CUDA (PTX)  |  OpenQASM 3  |  LLVM IR  |  ONNX (opset 21)  |  XLA (planned)
  HARDWARE    H100 / A100 / MI300  |  IBM Kyoto / Rigetti / IonQ  |  TPU

Crate Map

CratePurposeKey contents
lift-coreSSA IR foundationTypes, values, operations, blocks, regions, verifier, printer, pass manager
lift-astFrontendLexer, parser, AST, IR builder for .lif files
lift-tensorAI dialect110 ops (attention, conv, pooling, MoE, quantisation, GNN, fused), shape inference
lift-quantumQuantum dialect48 gates (IBM/Rigetti/IonQ native), noise models, Kraus channels, QEC, topology
lift-hybridFusion dialect21 ops (VQC, VQE, QAOA), gradient methods, encoding strategies, GPU-QPU transfer
lift-simAnalysis engineCost models (A100/H100), quantum cost (superconducting/trapped-ion/neutral-atom), energy, carbon
lift-predictPredictionRoofline model, budget enforcement
lift-optOptimisation13 passes: DCE, constant fold, tensor fusion, flash attention, gate cancel, rotation merge, CSE, quantisation, noise-aware schedule, layout mapping, canonicalise, gate decomposition, real routing
lift-importImportersONNX, PyTorch FX, OpenQASM 3
lift-exportBackendsLLVM IR, ONNX (opset 21), OpenQASM 3
lift-configConfiguration.lith parser and validator
lift-cliCLIlift verify, lift analyse, lift print, lift optimise, lift predict, lift export
lift-codegenCodegenProgrammatic model generation, multi-format export

Quick Start

# Install Rust 1.80+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Clone and build
git clone https://github.com/rustnew/Lift.git
cd lift
cargo build --release

# Run tests (535 tests)
cargo test --workspace

Example: Tensor Program

cat > hello.lif << 'EOF'
#dialect tensor
module @test {
    func @forward(%x: tensor<4xf32>) -> tensor<4xf32> {
        %out = "tensor.relu"(%x) : (tensor<4xf32>) -> tensor<4xf32>
        return %out
    }
}
EOF

lift verify  hello.lif    # Check IR well-formedness
lift analyse hello.lif    # FLOPs, shapes, memory estimate
lift print   hello.lif    # Pretty-print the IR

Example: Quantum Circuit

#dialect quantum
module @bell {
    func @bell_state() -> (bit, bit) {
        %q0 = "quantum.init"() : () -> qubit
        %q1 = "quantum.init"() : () -> qubit
        %q0 = "quantum.h"(%q0)         : (qubit) -> qubit
        %q0, %q1 = "quantum.cx"(%q0, %q1) : (qubit, qubit) -> (qubit, qubit)
        %b0 = "quantum.measure"(%q0) : (qubit) -> bit
        %b1 = "quantum.measure"(%q1) : (qubit) -> bit
        return %b0, %b1
    }
}

The .lith Configuration

One file controls the entire compilation pipeline:

compilation {
    target {
        gpu  { backend = "cuda"  arch = "sm_90"  memory_limit_gb = 80 }
        qpu  { provider = "ibm"  backend_name = "ibm_kyoto"  shots = 4096 }
    }
}
optimization {
    pipeline = ["canonicalize", "tensor-fusion", "gate-cancellation", "layout-mapping"]
}
prediction {
    budget { max_latency_ms = 200  min_fidelity = 0.92  max_memory_gb = 40 }
}

Optimisation Passes

PassDomainDescription
CanonicaliseAllNormalise IR to canonical form
Constant FoldingAllEvaluate compile-time constants
Dead Code EliminationAllRemove unused operations
Tensor FusionAIFuse MatMul+Bias+ReLU chains (30-50% bandwidth reduction)
Flash AttentionAIReplace O(n^2) attention with tiled O(n) (10-20x speedup)
QuantisationAIINT8/FP8 annotation (4x model size reduction)
Common Subexpression EliminationAllDeduplicate identical computations
Gate CancellationQuantumH*H=I, Rz(a)*Rz(b)=Rz(a+b) (15-40% depth reduction)
Rotation MergeQuantumMerge consecutive rotation gates
Noise-Aware ScheduleQuantumReorder gates for maximum fidelity
Layout MappingQuantumSABRE routing to physical qubit topology

Current Status

ComponentStatusCoverage
lift-coreStableSSA IR, types, verifier, printer, pass manager
lift-astStableFull lexer, parser, AST, IR builder
lift-tensorStable110 operations, shape inference, FLOP counting
lift-quantumStable48 gates, noise models, Kraus channels, QEC codes, topology
lift-hybridStable21 operations, gradient methods, encoding strategies
lift-simStableCost models, energy model, quantum simulation, budget tracking
lift-predictStableRoofline model, budget enforcement
lift-optStable11 optimisation passes
lift-importActiveONNX, PyTorch FX, OpenQASM 3 importers
lift-exportActiveLLVM IR, ONNX (opset 21), OpenQASM 3 exporters
lift-configStable.lith parser and types
lift-cliStableverify, analyse, print, optimise, predict, export
lift-codegenStableprogrammatic model generation, multi-format export

Test suite: 535 tests, 100% pass rate across 14 crates.


Roadmap

PhaseTargetMilestone
Core IR + DialectsDoneSSA IR, tensor/quantum/hybrid dialects complete
Optimisation PassesDone13 passes implemented and tested
Analysis EngineDoneCost models, energy, noise simulation
Import/ExportActiveONNX, PyTorch FX, LLVM, ONNX (opset 21), OpenQASM
Hardware BackendsPlannedCUDA PTX, native OpenQASM execution
Python BindingsPlannedPyO3-based Python API
v1.0 ReleaseQ4 2026Full pipeline, benchmarks, arXiv paper

Contributing

AreaDifficultyDescription
CUDA PTX backendHardGPU code generation for tensor ops
State vector simulatorMediumQuantum circuit simulator (CPU + GPU)
Qiskit importerMediumImport Qiskit circuits into LIFT IR
API documentationEasyRustdoc for all public items
TutorialsEasyGetting started guides and examples

See CONTRIBUTING.md for code style and PR process.


Citation

@software{lift2025,
  title  = {LIFT: Language for Intelligent Frameworks and Technologies},
  author = {Martial-FOSSOUO},
  year   = {2025},
  url    = {https://github.com/lift-framework/lift},
  note   = {Unified IR for AI and Quantum Computing}
}

License

MIT -- see LICENSE.


LIFT -- Because the future of computation is both intelligent and quantum, and it deserves a unified foundation.

LIFT v0.5 — Development Plan

Status: Active development target Scope: Execution engine, functional importers, real LLVM lowering Version bump: 0.5.0 (minor — new features, no breaking IR changes)

This plan breaks down the v0.5 milestone into concrete, independently mergeable work items. Each item lists the crates and files involved, the deliverable, and the acceptance criteria.


Overview

v0.5 moves LIFT from a static analysis compiler to an execution-capable compiler:

flowchart LR
    A["Static analysis (v0.4)"] --> B["State-vector simulation (v0.5)"]
    B --> C["Tensor interpreter (v0.5)"]
    C --> D["Real LLVM lowering (v0.5)"]
    D --> E["Functional importers (v0.5)"]

The four work streams are independent and can be developed in parallel.


Workstream 1 — State-vector quantum simulator

Target: simulate quantum circuits on CPU (up to ~25 qubits) to validate circuits before deploying to real QPUs.

Status today: crates/lift-sim/src/quantum_sim.rs performs static analysis only (gate counts, depth, fidelity estimates). There is no numerical simulation.

Tasks

#TaskFile(s)Acceptance
1.1Amplitude vector type Vec<Complex64> with 2^N layoutcrates/lift-sim/src/state.rsState::new(num_qubits) allocates 2^N amplitudes
1.2Gate matrix kernels (Pauli, Clifford, H, T, RX/RY/RZ, CNOT, SWAP)crates/lift-sim/src/kernels.rsEach gate applies correctly to an amplitude vector
1.3Circuit executor — walk LIFT IR ops, apply gates in ordercrates/lift-sim/src/executor.rsExecutes any quantum circuit expressed in lift-quantum dialect
1.4Measurement with probability samplingcrates/lift-sim/src/measure.rsmeasure(qubit) collapses state per Born rule
1.5Noise channel application (depolarising, amplitude damping)crates/lift-sim/src/noise.rsKraus operators applied to density matrix (mixed state mode)
1.6CLI subcommand lift sim --quantum file.lifcrates/lift-cli/src/main.rsPrints final state amplitudes + measurement counts

Deliverable

lift sim --quantum examples/quantum_bell.lif prints:

Qubits: 2
State:  |00⟩: 0.7071  |11⟩: 0.7071
Measurements (1024 shots): 00: 512, 11: 512

Workstream 2 — Tensor interpreter

Target: execute tensor ops with real values (numpy-like), enabling in-compiler evaluation of constant subgraphs.

Status today: no runtime values; the IR holds shapes/types only.

Tasks

#TaskFile(s)Acceptance
2.1Runtime tensor value Tensor { data: Vec<f64>, shape: Vec<usize> }crates/lift-sim/src/tensor.rsBasic constructors and indexing
2.2Core arithmetic kernels — add, sub, mul, div, matmul, broadcastcrates/lift-sim/src/tensor_ops.rsMatches numpy semantics on shape mismatch
2.3Reduction + reshape ops — sum, mean, max, reshape, transposecrates/lift-sim/src/tensor_ops.rsCorrect output shapes
2.4Dialect op → kernel dispatchercrates/lift-sim/src/interp.rsEvery lift-tensor op maps to a kernel or errors clearly
2.5CLI subcommand lift sim --tensor file.lifcrates/lift-cli/src/main.rsPrints output tensors

Deliverable

lift sim --tensor examples/tensor_mlp.lif evaluates the MLP forward pass and prints each layer's output tensor.


Workstream 3 — Real LLVM IR lowering

Target: emit executable LLVM IR with cuBLAS/cuDNN runtime calls (GPU) and a fallback CPU path.

Status today: lift-export/src/llvm.rs emits a textual skeleton — module declarations and function signatures, without real code generation.

Tasks

#TaskFile(s)Acceptance
3.1Map LIFT tensor ops to cuBLAS calls (gemm, bias, relu fusion)crates/lift-export/src/llvm.rsmatmul emits cublasSgemm
3.2Map quantum measurement/shots to a runtime harnesscrates/lift-export/src/llvm.rsQPU bridge stubs generated
3.3CPU fallback path (no GPU required to run)crates/lift-export/src/llvm.rsEmitted .ll compiles with clang
3.4Verify emitted IR with llvm-as / lli in CI.github/workflows/ci.ymllli executes a trivial kernel

Deliverable

lift export --backend llvm examples/phi3_mini.lif produces an .ll file that compiles with clang and runs on CPU without a GPU.


Workstream 4 — Functional importers

Target: import ONNX, PyTorch FX, and OpenQASM 3 files into LIFT IR.

Status today: crates/lift-import/src/{onnx,pytorch,qasm}.rs are stubs — error types and importer structs exist, but no parsing.

Tasks

#TaskFile(s)Acceptance
4.1ONNX protobuf decoding (opset ≤ 21)crates/lift-import/src/onnx.rsLoads a real .onnx from examples/
4.2ONNX op → LIFT tensor op mappingcrates/lift-import/src/onnx.rsConv, Gemm, Relu, Softmax map correctly
4.3OpenQASM 3 parser (grammar subset)crates/lift-import/src/qasm.rsParses quantum_bell.lif-equivalent QASM
4.4QASM gate → LIFT quantum op mappingcrates/lift-import/src/qasm.rsH, CNOT, measure round-trip
4.5PyTorch FX graph export ingestioncrates/lift-import/src/pytorch.rsReads a .fx.json graph
4.6CLI subcommand lift import <file>crates/lift-cli/src/main.rsImports and prints the IR

Deliverable

lift import examples/phi3_generated.onnx produces a valid LIFT IR that passes lift verify.


Testing strategy

  • Every new kernel/simulator function gets unit tests in-crate.
  • Round-trip tests: export .qasm/.onnx → import → verify.
  • examples/validate_all.sh extended with sim and import steps.
  • CI keeps cargo fmt --check, clippy -D warnings, cargo test --workspace.

Suggested PR sequence

  1. feat(sim): state-vector simulator — Workstream 1 (items 1.1–1.5)
  2. feat(cli): sim subcommands — items 1.6 + 2.5
  3. feat(sim): tensor interpreter — Workstream 2 (2.1–2.4)
  4. feat(import): ONNX importer — Workstream 4 (4.1–4.2)
  5. feat(import): OpenQASM importer — Workstream 4 (4.3–4.4)
  6. feat(export): real LLVM lowering — Workstream 3
  7. feat(import): PyTorch FX — Workstream 4 (4.5–4.6)

Each PR is independently mergeable and keeps main green.

Changelog

All notable changes to LIFT are documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

Planned (v0.5)

  • State-vector quantum simulator (CPU, up to ~25 qubits)
  • Tensor interpreter (numpy-like execution of tensor ops)
  • Real LLVM IR lowering with cuBLAS/cuDNN runtime calls
  • Functional importers — ONNX, PyTorch FX, OpenQASM 3 (currently stubs)
  • SABRE-style dynamic qubit re-placement

Planned (v0.6)

  • True automatic differentiation (backward graph construction)
  • PyO3 Python bindings
  • Multi-file support (include / linking)
  • v1.0 release — full pipeline, benchmarks, arXiv paper

[0.4.4] — 2026-08-05

Changed

  • Automated releases via crates.io Trusted Publishing (OIDC) — no API token needed. All 13 crates configured with rustnew/Lift workflow publish.yml; pushing a v* tag publishes every crate in dependency order from CI (.github/workflows/publish.yml).
  • Version bump 0.4.3 → 0.4.4 across workspace and docs.

[0.4.3] — 2026-08-05

Changed

  • Optimised crate descriptions for discoverability: every description now leads with "LIFT compiler", so the crates surface in crates.io searches for "compiler", "compiler framework", "quantum compiler", and "AI compiler".
  • All 13 crates republished to crates.io at v0.4.3.

[0.4.2] — 2026-08-05

Fixed

  • LICENSE now ships in every published crate package (was missing from crates.io tarballs because Cargo only auto-includes LICENSE files located in each package directory, not the workspace root).
  • Repository field corrected to rustnew/Lift in all published manifests (the GitHub rename from Litf-IR had not been propagated to crates.io).
  • Docs version references bumped to 0.4.2.

Changed

  • All 13 crates republished to crates.io at v0.4.2.

[0.4.1] — 2026-08-05

Fixed

  • Corrected op/gate counts in docs (110 tensor ops, 48 quantum gates, 21 hybrid ops).
  • README examples now compile against the real API (GateDecomposition::new(Provider::IbmKyoto), DataType re-export from model_builder).
  • Repository references updated to rustnew/Lift (renamed from Litf-IR).

Changed

  • Architecture diagrams moved to Mermaid (pipeline, dependency layers, roadmap).
  • All 13 crates republished to crates.io at v0.4.1.

[0.4.0] — 2026-08-05

Added

  • Optimisation levels O0O3 with explicit-pass override and per-pass enable/disable.
  • Semantic verification (op arity vs dialect signatures).
  • 13 optimisation passes including generic tensor fusion, hardware-native gate decomposition, real qubit routing (SWAP + BFS), non-adjacent gate cancellation & rotation merging.
  • All 13 crates published to crates.io (first full workspace release).

[0.3.0] — 2026-04-30

Added

  • Tensor / quantum / hybrid dialects.
  • Cost modelling (FLOPs, memory, energy/carbon).
  • Performance prediction (roofline analysis).
  • Export backends (LLVM IR, ONNX, OpenQASM 3.0).

[0.2.1] — 2026-04-30

Changed

  • Stability tuning.

[0.2.0] — 2026-03-31

Added

  • Initial public release of the LIFT compiler framework.
  • SSA-based intermediate representation.
  • Tensor, quantum, and hybrid dialects.
  • Core compiler infrastructure (types, values, operations, blocks, regions, verifier).

Contributing to LIFT

Thanks for your interest in contributing to LIFT — a unified intermediate representation for AI and quantum computing.

This guide covers the development workflow, project layout, and how to get your changes reviewed and merged.

Table of contents

Development setup

Requirements:

  • Rust 1.80 or newer (see rust-version in Cargo.toml)
  • Cargo (comes with Rust)

Clone and build:

git clone git@github.com:rustnew/Lift.git
cd Lift
cargo build --workspace

Project layout

LIFT is a Cargo workspace of 13 published crates, organised by dependency layer:

LayerCratesPurpose
L0 — Foundationlift-core, lift-configSSA IR, verifier; O0–O3 pipeline config
L1 — Dialects & Frontendlift-ast, lift-tensor, lift-quantumlexer/parser; AI ops; quantum gates & noise
L2 — Analysis & I/Olift-opt, lift-sim, lift-export, lift-import, lift-hybridpasses; cost model; backends; importers; fusion
L3 — Predictionlift-predictroofline / performance prediction
L4 — Toolslift-cli, lift-codegenCLI; programmatic model generation

lift-tests is a private crate (publish = false) used for integration tests.

Building and testing

# Build the whole workspace
cargo build --workspace

# Run all tests
cargo test --workspace

# Build a single crate
cargo build -p lift-core

Code style

  • Run rustfmt — CI enforces cargo fmt --all --check.
  • Run clippy with warnings denied — CI enforces cargo clippy --all-targets -- -D warnings.
  • Keep changes minimal and focused on a single concern.
cargo fmt --all
cargo clippy --all-targets -- -D warnings

Validation

Before submitting, run the end-to-end validation script, which exercises the full pipeline (verify → analyse → optimise → predict → export) across all example models:

bash examples/validate_all.sh

This is also run in CI on every push to main and on pull requests.

Publishing

Releases are published to crates.io. The process:

  1. Bump the version in Cargo.toml ([workspace.package] version) and update version references across README.md and the docs (LIFT_Guide.md, LIFT_Manual.md, LIFT_design.md, DIALECTS.md).

  2. Update CHANGELOG.md.

  3. Push a version tag — the publish workflow publishes all 13 crates automatically in dependency order (L0 → L1 → L2 → L3 → L4) using Trusted Publishing (OIDC, no API token):

    git tag v0.4.4
    git push origin v0.4.4
    

    Trusted Publishing is configured per crate on crates.io (Settings → Trusted Publishing) for rustnew/Lift, workflow publish.yml. The workflow can also be triggered manually via the Actions tab (workflow_dispatch).

    crates.io does not allow overwriting a published version — a fix to an already-published release requires a new version bump.

  4. Create a GitHub release:

    gh release create v0.4.4 --title "..." --notes "..."
    

Manual fallback

If you need to publish outside CI (e.g. the very first release of a new crate), publish in dependency order with the API token:

cargo publish -p lift-core
cargo publish -p lift-config
# ... then L1, L2, L3, L4 ...

Commit conventions

Use conventional commit prefixes:

  • feat: — new feature
  • fix: — bug fix
  • docs: — documentation only
  • chore: — maintenance (bumps, metadata, tooling)
  • refactor: — code change that neither fixes a bug nor adds a feature
  • test: — adding or updating tests

Example: docs: add vision, roadmap, and layer-graph diagrams to README

Opening a pull request

  1. Fork the repository and create a feature branch.
  2. Make your changes, keeping them focused.
  3. Run cargo fmt, cargo clippy, cargo test, and bash examples/validate_all.sh.
  4. Push your branch and open a pull request against main.
  5. CI runs automatically (fmt, clippy, tests, validation). All checks must pass before merge.

Thank you for contributing to LIFT!

LIFT — Publishing & Visibility Tracker

This document tracks where LIFT is published and referenced across the Rust, AI, and quantum ecosystems, plus the channels still to pursue.

Published & live

ChannelURLStatus
crates.io (13 crates)https://crates.io/crates/lift-core✅ v0.4.4
docs.rs (13 crates)https://docs.rs/lift-core
GitHub repohttps://github.com/rustnew/Lift
GitHub Releaseshttps://github.com/rustnew/Lift/releases✅ 7 releases
GitHub Pages (docs book)https://rustnew.github.io/Lift/
GitHub Discussionshttps://github.com/rustnew/Lift/discussions
crates.io Trusted Publishing13 crates → rustnew/Lift workflow publish.yml✅ configured

Publishing is now secure: all 13 crates use Trusted Publishing (OIDC, no API token). Pushing a v* tag triggers .github/workflows/publish.yml, which publishes every crate in dependency order. See CONTRIBUTING.md.

Pull requests submitted (awaiting merge)

ListPRSection
qosf/awesome-quantum-software#178Quantum full-stack libraries + Quantum compilers (Rust)
merrymercy/awesome-tensor-compilers#47Open Source Projects
rust-unofficial/awesome-rust#2689Machine learning

To do — other awesome lists

ListSectionStatus
invictvs-choi/awesome-quantum-compilerSkipped — list is research-papers only, not open-source tools
zwang4/awesome-machine-learning-in-compilersSkipped — list is "ML applied to compilers", not "ML compilers"

Community announcements

Ready-to-post texts for each channel are in docs/ANNOUNCEMENTS.md.

ChannelStatus
This Week in RustText ready — submit via https://this-week-in-rust.org/
users.rust-lang.org (Announcements)Text ready
Reddit r/rustText ready
Reddit r/QuantumComputingText ready
Reddit r/MachineLearningText ready
Hacker News (Show HN)Text ready
Lobste.rsReuse the HN/r/rust text
Rust Discord / ZulipReuse the announcement text

To do — academic / long-term

ChannelWhenNotes
arXiv paperv1.0 (Q4 2026)Already in roadmap
Papers With CodeAfter arXivLink the repo
Quantum Open Source Foundation (QOSF)Any timeCommunity + mentorship
Unitary FundAny timeGrants for open-source quantum projects

Notes

  • The crate name lift is taken on crates.io (a DB migration tool, unrelated). lift-ir is available if a standalone brand name is ever needed.
  • lib.rs indexes crates.io automatically; no manual submission needed.

Capabilities & readiness (v0.4.4) — truth check for marketing & reprise

Written 2026-08-05 (pause until ~2026-09). Keep this in sync with every release so the messaging never overpromises. Rule of thumb: announce what the code does today, not what the roadmap plans.

✅ Already usable today

AreaStatusAudience
IR construction (modules, functions, blocks, ops, regions, values, types)SolidCompiler developers
Dialects: 110 tensor ops, 48 quantum gates, 21 hybrid ops (full types/API)RealAPI consumers
13 optimisation passes (fusion, DCE, rewrites…) + pass frameworkRealPass developers
IR verifierRealProgram validation
Quantum analysis: circuit depth, estimated fidelity, depolarising noiseReal but staticEstimation only, no execution
Export: ONNX / QASM / LLVM-IR textPartialPrototyping

❌ NOT yet usable (honest gaps — these are the v0.5/v0.6 plan)

GapImpact
No real simulator — quantum_sim.rs is static analysis, not state-vector simulationCannot run a circuit to get states/amplitudes
Importers are ~55-line skeletons (ONNX / PyTorch FX / QASM), not full parsersCannot load a real .onnx / .qasm file end-to-end
No real LLVM lowering — backend emits IR text, not executable bytecodeCannot compile-and-run natively
No tensor execution — numpy-like interpreter is planned (v0.5)Tensor ops do not compute yet

🎯 One-line positioning (use in all marketing)

"Rust compiler framework: unified SSA IR for AI + quantum, 13 optimisation passes, O0-O3 pipelines, LLVM/ONNX/QASM backends."

This is accurate today. It is a framework (build compilers with it), not yet an end-to-end compiler you can feed a model/circuit into and run.

LIFT — Community Announcements

Ready-to-post announcement texts for each community channel. Each is tuned to the platform's tone and audience. Replace the placeholder links if needed.

Key facts (verified):

  • 13 crates on crates.io (v0.4.4), docs on docs.rs
  • 110 tensor ops, 48 quantum gates, 21 hybrid ops
  • 13 optimisation passes, O0–O3 pipelines
  • 3 backends: LLVM IR, ONNX (opset 21), OpenQASM 3.0
  • Docs book: https://rustnew.github.io/Lift/

Reddit — r/rust (showcase)

Title: LIFT — a unified compiler framework for AI and quantum computing in Rust

Body:

I've been building LIFT, a compiler framework that treats AI and quantum computing as one problem instead of two.

The core idea: a single SSA intermediate representation where tensor ops, quantum gates, and classical-quantum hybrids are equal citizens. So you can optimise a hybrid VQE/QAOA workload and a transformer model in the same pipeline, with the same passes.

What it does today:

  • 110 tensor ops — attention (Flash/Paged/GQA), MoE, quantisation, GNN, diffusion
  • 48 quantum gates — with noise models, Kraus channels, QEC codes
  • 13 optimisation passes — tensor fusion, FlashAttention replacement, gate cancellation, noise-aware scheduling, qubit routing (SWAP + BFS), gate decomposition
  • O0–O3 pipelines with per-pass control
  • 3 backends — LLVM IR, ONNX (opset 21), OpenQASM 3.0
  • Cost modelling — FLOPs, memory, energy, roofline prediction before hardware runs

It's published as 13 crates on crates.io, with full docs.

  • GitHub: https://github.com/rustnew/Lift
  • crates.io: https://crates.io/crates/lift-core
  • docs.rs: https://docs.rs/lift-core
  • Docs book: https://rustnew.github.io/Lift/

Happy to hear feedback — especially from anyone working on MLIR, TVM, or quantum compilers. The roadmap (simulator, importers, real LLVM lowering) is open for contributions.


Reddit — r/QuantumComputing

Title: LIFT — a Rust compiler that unifies AI tensor and quantum circuit compilation

Body:

Sharing a project I've been working on: LIFT, a compiler framework with a single SSA IR that spans tensor operations and quantum gates.

For the quantum side, it includes:

  • 48 quantum gates with noise models, Kraus channels, and QEC codes
  • Noise-aware scheduling — the compiler reasons about T1/T2/fidelity at every stage
  • Linear qubit types — the no-cloning theorem is enforced at compile time
  • Qubit layout mapping and real qubit routing (SWAP + BFS)
  • Hardware-native gate decomposition (IBM, Rigetti, IonQ, Quantinuum)
  • OpenQASM 3.0 export

The differentiator: because AI tensors and quantum gates share one IR, hybrid classical-quantum workloads (VQE, QAOA, quantum chemistry) can be optimised jointly with the classical parts.

  • GitHub: https://github.com/rustnew/Lift
  • crates.io: https://crates.io/crates/lift-core
  • Docs: https://rustnew.github.io/Lift/

The state-vector simulator and importers (Qiskit, OpenQASM) are on the roadmap.


Reddit — r/MachineLearning

Title: [P] LIFT — a Rust compiler framework for AI and quantum workloads

Body:

I've been working on LIFT, a compiler framework that unifies AI and quantum computation under one SSA intermediate representation.

The ML-relevant parts:

  • 110 tensor ops including attention (Flash/Paged/GQA), MoE, quantisation, GNN, diffusion
  • 13 optimisation passes including tensor fusion and FlashAttention replacement
  • Cost modelling: FLOPs, peak memory, energy, and roofline prediction computed before hardware runs — budget violations halt compilation with suggestions
  • ONNX (opset 21) export for PyTorch/TensorFlow/TensorRT interop

It's written in Rust and published as 13 crates.

  • GitHub: https://github.com/rustnew/Lift
  • crates.io: https://crates.io/crates/lift-core
  • Docs: https://rustnew.github.io/Lift/

The tensor interpreter (numpy-like execution) and real LLVM lowering are on the roadmap. Feedback welcome.


Hacker News — Show HN

Title: Show HN: LIFT — a unified compiler for AI and quantum computing

Body:

I've been working on a compiler framework that treats AI and quantum computing as a single problem. LIFT uses one SSA intermediate representation where tensor ops, quantum gates, and classical-quantum hybrids are all first-class.

Why this matters: hybrid workloads (VQE, QAOA, quantum chemistry) need both classical and quantum compilation, but today they live in separate toolchains with separate IRs. LIFT lets you optimise them together.

Current state:

  • 110 tensor ops, 48 quantum gates, 21 hybrid ops
  • 13 optimisation passes, O0–O3 pipelines
  • Noise-aware scheduling + linear qubit types (no-cloning enforced at compile time)
  • Cost modelling before hardware runs (FLOPs, memory, energy, roofline)
  • LLVM IR / ONNX / OpenQASM 3.0 backends
  • 13 crates on crates.io, MIT licensed

Written in Rust. Docs: https://rustnew.github.io/Lift/

The roadmap (state-vector simulator, importers, real LLVM lowering) is open. Would love feedback from compiler folks — especially anyone who's worked with MLIR or quantum transpilers.


This Week in Rust — submission

Title: LIFT: a unified compiler framework for AI and quantum computing

Body:

LIFT is a Rust compiler framework with a single SSA intermediate representation spanning tensor operations, quantum gates, and classical-quantum hybrids. It ships 13 optimisation passes, O0–O3 pipelines, cost modelling, and LLVM IR / ONNX / OpenQASM 3.0 backends across 13 crates on crates.io.


users.rust-lang.org — Announcements

Title: LIFT — a unified compiler framework for AI and quantum computing

Body:

I'm announcing LIFT, a Rust compiler framework that unifies AI and quantum computation under a single SSA intermediate representation.

Highlights:

  • 110 tensor ops, 48 quantum gates, 21 hybrid ops
  • 13 optimisation passes, O0–O3 pipelines
  • Noise-aware scheduling and linear qubit types
  • Cost modelling (FLOPs, memory, energy, roofline) before hardware runs
  • LLVM IR / ONNX / OpenQASM 3.0 backends
  • 13 crates on crates.io, MIT licensed

Links:

  • GitHub: https://github.com/rustnew/Lift
  • crates.io: https://crates.io/crates/lift-core
  • docs.rs: https://docs.rs/lift-core
  • Docs book: https://rustnew.github.io/Lift/

Contributions welcome — see CONTRIBUTING.md.