PySparQ.pysparq.dynamic_operator

PySparQ dynamic operator extension module - provides runtime compilation and loading of custom C++ operators.

Warning

compile_operator() merely compiles the user-provided operator()/dag() into a shared library and calls it via ctypes; a successful compilation only means the code passes C++ type checking. It does not imply, and cannot statically or dynamically prove, that the operator is unitary or that operator()/dag() are inverses of each other. Any implementation that overwrites registers on its own, implements dag() by zeroing registers, or destroys information in some other way will compile without complaint.

Therefore, the QCFD paths supported by this repository (QECC.Lang-driven qfvm/qnls/qham) are forbidden from using dynamic operators compiled via compile_operator. All semantics must be expressed through named, statically checkable PySparQ built-in operators (or Python composite operators built from built-in operators), and validated with the conformance test matrix provided by pysparq.conformance (arbitrary non-zero outputs, exhaustive/sampled basis states, collision detection, linearity on superpositions, positive/negative/ multiple controls, and forward+dagger and dagger+forward identity). compile_operator remains a general-purpose (not QCFD-specific) runtime operator compilation tool that can be used for prototyping, teaching, or experiments unrelated to QCFD, but it must not be treated as having passed any unitarity proof.

Submodules

Exceptions

CompilationError

Compilation error exception.

DynamicOperatorError

Dynamic operator error.

DynamicOperatorFactoryError

Factory function invocation error.

DynamicOperatorLoadError

Dynamic library load error.

Classes

CompilerConfig

Compiler configuration.

CppOperatorWrapper

C++ operator wrapper

Functions

cleanup_all_instances()

Clean up all active dynamic operator instances

clear_cache(→ int)

Clear the compilation cache

compile_cpp_code(→ str)

Compile C++ code into a shared library

compile_operator(→ Type)

Compile C++ code into a dynamic operator class.

compute_code_hash(→ str)

Compute the code hash used for caching

create_operator_class(→ Type)

Create a dynamic operator Python class

find_project_root(→ Optional[pathlib.Path])

Locate the project root directory or the installed package directory

format_compile_error(→ str)

Format compiler error output

generate_cpp_source(→ str)

Generate the complete C++ source file

get_cache_info(→ dict)

Get cache information

quick_compile(→ str)

Quickly compile C++ operator code

Package Contents

exception PySparQ.pysparq.dynamic_operator.CompilationError(message: str, stderr: str = '', returncode: int = 0)[source]

Bases: Exception

Compilation error exception.

Initialize self. See help(type(self)) for accurate signature.

returncode = 0
stderr = ''
exception PySparQ.pysparq.dynamic_operator.DynamicOperatorError[source]

Bases: Exception

Dynamic operator error.

Initialize self. See help(type(self)) for accurate signature.

exception PySparQ.pysparq.dynamic_operator.DynamicOperatorFactoryError[source]

Bases: DynamicOperatorError

Factory function invocation error.

Initialize self. See help(type(self)) for accurate signature.

exception PySparQ.pysparq.dynamic_operator.DynamicOperatorLoadError[source]

Bases: DynamicOperatorError

Dynamic library load error.

Initialize self. See help(type(self)) for accurate signature.

class PySparQ.pysparq.dynamic_operator.CompilerConfig(cxx: str = 'g++', std: str = 'c++17', opt_level: str = 'O2', include_paths: list | None = None, lib_paths: list | None = None, libraries: list | None = None, extra_flags: list | None = None, template: str | None = None)[source]

Compiler configuration.

Initialize the compiler configuration

Parameters:
  • cxx – C++ compiler command (default g++)

  • std – C++ standard version (default c++17)

  • opt_level – Optimization level (default O2)

  • include_paths – Extra header search paths

  • lib_paths – Extra library search paths

  • libraries – Libraries to link against

  • extra_flags – Extra compiler flags

  • template – Custom code template

get_compile_flags() → list[source]

Generate the list of compiler flags.

DEFAULT_TEMPLATE = Multiline-String
Show Value
"""#include "basic_components.h"
#include <vector>
#include <complex>

using namespace qram_simulator;

{USER_CPP_CODE}

extern "C" BaseOperator* create_operator({CTOR_PARAMS}) {{
    return new {CLASS_NAME}({CTOR_ARGS});
}}

extern "C" void destroy_operator(BaseOperator* op) {{
    delete op;
}}

extern "C" const char* get_operator_name() {{
    return "{CLASS_NAME}";
}}
"""
PYTHON_TEMPLATE = Multiline-String
Show Value
"""#include "basic_components.h"
#include <vector>
#include <complex>

using namespace qram_simulator;

{USER_CPP_CODE}

extern "C" BaseOperator* create_operator({CTOR_PARAMS}) {{
    return new {CLASS_NAME}({CTOR_ARGS});
}}

extern "C" void destroy_operator(BaseOperator* op) {{
    delete op;
}}

extern "C" const char* get_operator_name() {{
    return "{CLASS_NAME}";
}}

// Python call helper - applies the operator to a SparseState
// The Python side obtains the C++ SparseState* pointer via state._cpp_ptr(),
// which ctypes passes as ctypes.c_void_p.
extern "C" void apply_operator(BaseOperator* op, SparseState* state) {{
    if (op && state) {{
        (*op)(*state);
    }}
}}

// Python call helper - applies the dagger
extern "C" void apply_operator_dag(BaseOperator* op, SparseState* state) {{
    if (op && state) {{
        op->dag(*state);
    }}
}}

// Returns the base class type
extern "C" const char* get_base_class() {{
    return "{BASE_CLASS}";
}}
"""
cxx = 'g++'
extra_flags = []
include_paths = []
lib_paths = []
libraries = []
opt_level = 'O2'
std = 'c++17'
template = Multiline-String
Show Value
"""#include "basic_components.h"
#include <vector>
#include <complex>

using namespace qram_simulator;

{USER_CPP_CODE}

extern "C" BaseOperator* create_operator({CTOR_PARAMS}) {{
    return new {CLASS_NAME}({CTOR_ARGS});
}}

extern "C" void destroy_operator(BaseOperator* op) {{
    delete op;
}}

extern "C" const char* get_operator_name() {{
    return "{CLASS_NAME}";
}}
"""
class PySparQ.pysparq.dynamic_operator.CppOperatorWrapper(lib_path: str)[source]

C++ operator wrapper

Loads the dynamic library and invokes the factory functions to create/destroy C++ operator objects

Initialize the wrapper

Parameters:

lib_path – Dynamic library path

apply(ptr: int, state_cpp_ptr: int)[source]

Apply the operator to a SparseState

Parameters:
  • ptr – Operator object address

  • state_cpp_ptr – C++ SparseState* pointer (obtained via state._cpp_ptr())

apply_dag(ptr: int, state_cpp_ptr: int)[source]

Apply the dagger to a SparseState

Parameters:
  • ptr – Operator object address

  • state_cpp_ptr – C++ SparseState* pointer (obtained via state._cpp_ptr())

close()[source]

Close the dynamic library and release resources

Note: on Windows, all C++ objects must already be destroyed before the dynamic library file can be deleted successfully

create(*args) → int[source]

Create a C++ operator instance

Parameters:

*args – Constructor arguments

Returns:

C++ object address (as a Python int)

destroy(ptr: int)[source]

Destroy a C++ operator instance

Parameters:

ptr – C++ object address

get_base_class() → str[source]

Get the base class name.

get_name() → str[source]

Get the operator name.

load(arg_types: List[str] = None)[source]

Load the dynamic library

Parameters:

arg_types – List of constructor argument types

Raises:

DynamicOperatorLoadError – Load failed

lib_path
PySparQ.pysparq.dynamic_operator.cleanup_all_instances()[source]

Clean up all active dynamic operator instances

PySparQ.pysparq.dynamic_operator.clear_cache(cache_dir: str | None = None) → int[source]

Clear the compilation cache

Parameters:

cache_dir – Cache directory (defaults to the system temporary directory)

Returns:

The number of deleted files

PySparQ.pysparq.dynamic_operator.compile_cpp_code(cpp_code: str, class_name: str, cache_dir: str | None = None, ctor_params: str = '', ctor_args: str = '', config: CompilerConfig | None = None, project_root: str | None = None, verbose: bool = False) → str[source]

Compile C++ code into a shared library

Parameters:
  • cpp_code – User-provided C++ code (containing the class definition)

  • class_name – Operator class name

  • cache_dir – Cache directory (defaults to the system temporary directory)

  • ctor_params – Constructor parameter declarations

  • ctor_args – Constructor call arguments

  • config – Compiler configuration

  • project_root – Project root directory (auto-detected)

  • verbose – Whether to print verbose logs

Returns:

Path of the compiled shared library (.so file)

Raises:
PySparQ.pysparq.dynamic_operator.compile_operator(name: str, cpp_code: str, base_class: str = 'BaseOperator', extra_includes: List[str] = None, extra_libs: List[str] = None, constructor_args: List[Tuple[str, str]] = None, cache_dir: str | None = None, verbose: bool = False) → Type[source]

Compile C++ code into a dynamic operator class.

This is a high-level function that compiles user-provided C++ code into a shared library and wraps it into an operator class that can be used directly from Python. A dynamic operator can be applied to a SparseState just like a native PySparQ operator.

Warning

A successful compilation only means operator()/dag() passed C++ type checking; it constitutes no unitarity proof whatsoever: this function neither statically nor dynamically verifies that the generated operator is unitary, or that dag() is actually the inverse of operator(). Hence the supported QCFD paths (QECC.Lang-driven qfvm/qnls/qham) forbid the use of dynamic operators compiled by this function; QCFD semantics must use named PySparQ built-in operators and be validated with the pysparq.conformance conformance test matrix.

Parameters:
  • name – Operator class name. Must be a valid Python class name and must match the class name in the C++ code.

  • cpp_code – C++ source code, containing only the class definition part. The code must inherit from BaseOperator or SelfAdjointOperator and implement the operator() method.

  • base_class – Base class name, determines dagger behavior. Allowed values: - “BaseOperator”: general operator, requires a manually implemented dag() method - “SelfAdjointOperator”: Hermitian operator, dag() automatically equals operator() Defaults to “BaseOperator”.

  • extra_includes – List of extra header search paths. PySparQ headers are included automatically.

  • extra_libs – List of extra libraries to link. Most operators need no extra libraries.

  • constructor_args – List of constructor arguments in the form [(type, name), …]. Supported types: size_t, int, long, double, float, bool, uint64_t. Example: [(“size_t”, “reg_id”), (“double”, “phase”)]

  • cache_dir – Cache directory path. Defaults to pysparq_dynamic_ops/ under the system temporary directory.

  • verbose – Whether to print verbose compilation logs, useful for debugging.

Returns:

The dynamically generated operator class. Instances are created with keyword arguments, e.g.: OpClass(reg_id=0, phase=1.0)

Raises:

Example

Create a simple flip operator:

>>> from pysparq.dynamic_operator import compile_operator
>>>
>>> cpp_code = '''
... class FlipOp : public SelfAdjointOperator {
...     size_t reg_id;
... public:
...     FlipOp(size_t r) : reg_id(r) {}
...     void operator()(std::vector<System>& state) const override {
...         for (auto& s : state) {
...             s.get(reg_id).value ^= 1;
...         }
...     }
... };
... '''
>>>
>>> FlipOp = compile_operator(
...     name="FlipOp",
...     cpp_code=cpp_code,
...     base_class="SelfAdjointOperator",
...     constructor_args=[("size_t", "reg_id")]
... )
>>>
>>> # Create an instance
>>> op = FlipOp(reg_id=0)
>>> print(repr(op))  # FlipOp(reg_id=0)

Note

  • Compiled libraries are cached by code hash to avoid redundant compilation.

  • ABI compatibility issues may exist on Windows (MSVC vs MinGW).

  • The C++ class name must match the Python name parameter.

  • State access inside operators: s.get(reg_id).value gets the value, s.amplitude gets the amplitude.

See also

get_cache_info: Query the compilation cache status. clear_cache: Clear the compilation cache. CompilerConfig: Advanced compiler configuration.

PySparQ.pysparq.dynamic_operator.compute_code_hash(cpp_code: str, class_name: str, config: CompilerConfig) → str[source]

Compute the code hash used for caching

The hash covers: code content, class name, compiler version, and configuration

Parameters:
  • cpp_code – User C++ code

  • class_name – Operator class name

  • config – Compiler configuration

Returns:

A 16-character hexadecimal hash string

PySparQ.pysparq.dynamic_operator.create_operator_class(name: str, lib_path: str, base_class: str = 'BaseOperator', constructor_args: List[Tuple[str, str]] = None) → Type[source]

Create a dynamic operator Python class

Parameters:
  • name – Operator class name

  • lib_path – Dynamic library path

  • base_class – Base class name (“BaseOperator” or “SelfAdjointOperator”)

  • constructor_args – List of constructor arguments [(type, name), …]

Returns:

The dynamically created operator class

PySparQ.pysparq.dynamic_operator.find_project_root() → pathlib.Path | None[source]

Locate the project root directory or the installed package directory

For an installed package, the directory layout is: - site-packages/pysparq/ (Python package) - site-packages/include/ (headers, including basic_components.h)

For a source checkout (the SparQSim repository): - The project root contains extern/qram-simulator/ (C++ core submodule) and PySparQ/

Returns:

The project root path or the installed package directory; None if not found

PySparQ.pysparq.dynamic_operator.format_compile_error(stderr: str, source_path: str) → str[source]

Format compiler error output

  • Simplifies file paths

  • Highlights error lines

  • Extracts the key error information

Parameters:
  • stderr – Compiler standard error output

  • source_path – Source file path

Returns:

The formatted error message

PySparQ.pysparq.dynamic_operator.generate_cpp_source(cpp_code: str, class_name: str, ctor_params: str = '', ctor_args: str = '', config: CompilerConfig | None = None) → str[source]

Generate the complete C++ source file

Parameters:
  • cpp_code – User-provided C++ code (containing the class definition)

  • class_name – Operator class name

  • ctor_params – Constructor parameter declarations (e.g. “int n, double theta”)

  • ctor_args – Constructor call arguments (e.g. “n, theta”)

  • config – Compiler configuration (provides the template)

Returns:

The complete C++ source code string

PySparQ.pysparq.dynamic_operator.get_cache_info(cache_dir: str | None = None) → dict[source]

Get cache information

Parameters:

cache_dir – Cache directory

Returns:

A dictionary with cache statistics

PySparQ.pysparq.dynamic_operator.quick_compile(class_code: str, class_name: str, verbose: bool = False) → str[source]

Quickly compile C++ operator code

Parameters:
  • class_code – C++ code containing the class definition

  • class_name – Class name

  • verbose – Whether to print verbose logs

Returns:

The shared library file path