Source code for nkdsl.compiler.core.signature

# Copyright (c) 2026 The neuraLQX and nkDSL Authors - All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


"""Compilation-signature helpers for deterministic artifact caching."""

from __future__ import annotations

import dataclasses
import hashlib
import json
from collections.abc import Mapping
from typing import Any

from nkdsl.compiler.core.context import (
    SymbolicCompilationContext,
)


def _stable_hash(payload: Any) -> str:
    """Returns a stable SHA-256 hex digest over a JSON-serializable payload."""
    raw = json.dumps(payload, sort_keys=True, default=str)
    return hashlib.sha256(raw.encode("utf-8")).hexdigest()


[docs] @dataclasses.dataclass(frozen=True, repr=False) class SymbolicCompilationSignature: """ Deterministic compilation signature for cache-key generation. Attributes: operator_ir_fingerprint: Stable digest of the operator IR. backend_target: Resolved backend name. hilbert_size: Hilbert space size. dtype_str: Matrix-element dtype string. options_signature: Static compiler-options signature. """ operator_ir_fingerprint: str backend_target: str hilbert_size: int dtype_str: str options_signature: tuple = dataclasses.field(default_factory=tuple) @classmethod def from_context( cls, context: SymbolicCompilationContext, ) -> "SymbolicCompilationSignature": """Builds a signature from a post-backend-selection context.""" selected_backend = ( context.selected_backend if context.selected_backend is not None else context.options.backend_preference ) return cls( operator_ir_fingerprint=context.ir.static_fingerprint(), backend_target=str(selected_backend), hilbert_size=context.ir.hilbert_size, dtype_str=context.ir.dtype_str, options_signature=context.options.static_signature(), ) def build_cache_key( self, *, namespace: str, extension_context: Mapping[str, Any] | None = None, ) -> "SymbolicCacheKey": """ Builds a deterministic cache key. Args: namespace: Cache namespace string. extension_context: Optional extra context included in the key. Returns: Immutable cache key. """ payload: dict[str, Any] = { "namespace": namespace, "operator_ir_fingerprint": self.operator_ir_fingerprint, "backend_target": self.backend_target, "hilbert_size": self.hilbert_size, "dtype_str": self.dtype_str, "options_signature": list(self.options_signature), } if extension_context is not None: payload["extension_context"] = extension_context token = _stable_hash(payload) return SymbolicCacheKey(token=token, namespace=namespace) def as_dict(self) -> dict[str, Any]: """Returns dictionary-form signature payload.""" return { "operator_ir_fingerprint": self.operator_ir_fingerprint, "backend_target": self.backend_target, "hilbert_size": self.hilbert_size, "dtype_str": self.dtype_str, "options_signature": list(self.options_signature), } def __repr__(self) -> str: return ( f"SymbolicCompilationSignature(" f"operator_ir_fingerprint={self.operator_ir_fingerprint[:12]!r}..., " f"backend_target={self.backend_target!r})" )
[docs] @dataclasses.dataclass(frozen=True) class SymbolicCacheKey: """Immutable cache key for compiled symbolic operator artifacts.""" token: str namespace: str def __str__(self) -> str: return self.token
__all__ = [ "SymbolicCacheKey", "SymbolicCompilationSignature", ]