Skip to content

quast_decisiontree.algorithms.hybrid.hybrid_algorithm

quast_decisiontree.algorithms.hybrid.hybrid_algorithm

HybridAlgorithm

Bases: ABC

Base class for hybrid quantum-classical algorithms.

Integrates with AutoClassBuilder: subclasses declare HYPERPARAMS and their init receives kwargs matching those names.

Subclasses declare INPUT_KEYS to specify which problem data they need, then implement run_algorithm() with the actual logic.

Source code in src/quast_decisiontree/algorithms/hybrid/hybrid_algorithm.py
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
class HybridAlgorithm(ABC):
    """Base class for hybrid quantum-classical algorithms.

    Integrates with AutoClassBuilder: subclasses declare HYPERPARAMS
    and their __init__ receives kwargs matching those names.

    Subclasses declare INPUT_KEYS to specify which problem data they need,
    then implement run_algorithm() with the actual logic.
    """

    HYPERPARAMS: ClassVar[list] = []
    """List of HyperParam instances; override in subclass."""

    INPUT_KEYS: ClassVar[Sequence[str]] = ()
    """Keys the algorithm expects (e.g., 'qubo_matrix', 'graph', 'cost_operator')."""

    def __init__(self, **kwargs: Any) -> None:
        """Initialize from keyword arguments matching HYPERPARAMS names.

        This constructor signature is compatible with AutoClassBuilder.build().
        """
        for hp in self.HYPERPARAMS:
            value = kwargs.get(hp.name, hp.default if hp.has_default else None)
            setattr(self, hp.name, value)
        self._reset_input()
        self.backend: Backend | None = None

    # --- Input management ---

    @property
    def input(self) -> dict[str, Any]:
        return self._input

    def set_input(self, input_dict: dict[str, Any]) -> None:
        """Validate and store input data. Raises on unknown keys."""
        self._reset_input()
        # FIX: was `for key, val in input_dict:` — needs .items()
        for key, val in input_dict.items():
            if key in self.INPUT_KEYS:
                self._input[key] = val
            else:
                raise ValueError(
                    f"Invalid input key {key!r} for {self.__class__.__name__}. "
                    f"Allowed: {list(self.INPUT_KEYS)}"
                )

    def _reset_input(self) -> None:
        self._input = {key: None for key in self.INPUT_KEYS}

    def _validate_input(self) -> None:
        """Check that all required keys have been set (are not None)."""
        missing = [k for k, v in self._input.items() if v is None]
        if missing:
            raise ValueError(f"{self.__class__.__name__} missing required inputs: {missing}")

    def reset(self) -> None:
        """Clear input and backend state after execution."""
        self._reset_input()
        self.backend = None

    # --- Execution ---

    def execute(self, backend: Backend, **kwargs: Any) -> Any:
        """Execute the hybrid algorithm.

        Args:
            backend: Backend instance supporting run()/run_batch().
            **kwargs: Must match INPUT_KEYS (e.g., qubo_matrix=..., graph=...).

        Returns:
            Algorithm-specific result.
        """
        self.set_input(kwargs)
        self._validate_input()
        self.backend = backend
        try:
            result = self.run_algorithm(backend=self.backend, input=self._input)
        finally:
            # Always clean up, even on error
            self.reset()
        return result

    @abstractmethod
    def run_algorithm(self, backend: Backend, input: dict[str, Any]) -> Any:
        """Algorithm-specific execution. Override in subclass.

        Backend usage:
            - backend(circuit, shots=None) or backend.run(circuit, shots=None)
            - backend.run_batch(circuits, shots=None)

        Backends return Dict[str, int] mapping bitstrings to counts.

        Args:
            backend: The quantum backend to submit circuits to.
            input: Dict with keys from INPUT_KEYS, all guaranteed non-None.

        Returns:
            Algorithm result (solution dict, counts, optimal value, etc.)
        """

    # --- Builder integration ---

    @classmethod
    def get_builder(cls, name: str | None = None, description: str | None = None):
        """Create an AutoClassBuilder for this algorithm class."""
        from quast_decisiontree.algorithms.hybrid.builder import HybridAlgorithmBuilder
        from quast_decisiontree.core.builder import HyperParam

        # Copy hyperparams so builders don't share mutable state
        copied = [
            HyperParam(
                name=hp.name,
                hparam_type=hp.type,
                description=hp.description,
                default=hp.default if hp.has_default else "",
                test=hp.test,
                allow_multiple=hp.allow_multiple,
            )
            for hp in cls.HYPERPARAMS
        ]
        return HybridAlgorithmBuilder(
            superclass=cls,
            hyperparams=copied,
            name=name or cls.__name__,
            description=description or cls.__doc__ or "",
            input_keys=cls.INPUT_KEYS,
        )

HYPERPARAMS class-attribute

HYPERPARAMS = []

List of HyperParam instances; override in subclass.

INPUT_KEYS class-attribute

INPUT_KEYS = ()

Keys the algorithm expects (e.g., 'qubo_matrix', 'graph', 'cost_operator').

backend instance-attribute

backend = None

input property

input

__init__

__init__(**kwargs)

Initialize from keyword arguments matching HYPERPARAMS names.

This constructor signature is compatible with AutoClassBuilder.build().

Source code in src/quast_decisiontree/algorithms/hybrid/hybrid_algorithm.py
32
33
34
35
36
37
38
39
40
41
def __init__(self, **kwargs: Any) -> None:
    """Initialize from keyword arguments matching HYPERPARAMS names.

    This constructor signature is compatible with AutoClassBuilder.build().
    """
    for hp in self.HYPERPARAMS:
        value = kwargs.get(hp.name, hp.default if hp.has_default else None)
        setattr(self, hp.name, value)
    self._reset_input()
    self.backend: Backend | None = None

set_input

set_input(input_dict)

Validate and store input data. Raises on unknown keys.

Source code in src/quast_decisiontree/algorithms/hybrid/hybrid_algorithm.py
49
50
51
52
53
54
55
56
57
58
59
60
def set_input(self, input_dict: dict[str, Any]) -> None:
    """Validate and store input data. Raises on unknown keys."""
    self._reset_input()
    # FIX: was `for key, val in input_dict:` — needs .items()
    for key, val in input_dict.items():
        if key in self.INPUT_KEYS:
            self._input[key] = val
        else:
            raise ValueError(
                f"Invalid input key {key!r} for {self.__class__.__name__}. "
                f"Allowed: {list(self.INPUT_KEYS)}"
            )

reset

reset()

Clear input and backend state after execution.

Source code in src/quast_decisiontree/algorithms/hybrid/hybrid_algorithm.py
71
72
73
74
def reset(self) -> None:
    """Clear input and backend state after execution."""
    self._reset_input()
    self.backend = None

execute

execute(backend, **kwargs)

Execute the hybrid algorithm.

Parameters:

Name Type Description Default
backend Backend

Backend instance supporting run()/run_batch().

required
**kwargs Any

Must match INPUT_KEYS (e.g., qubo_matrix=..., graph=...).

{}

Returns:

Type Description
Any

Algorithm-specific result.

Source code in src/quast_decisiontree/algorithms/hybrid/hybrid_algorithm.py
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def execute(self, backend: Backend, **kwargs: Any) -> Any:
    """Execute the hybrid algorithm.

    Args:
        backend: Backend instance supporting run()/run_batch().
        **kwargs: Must match INPUT_KEYS (e.g., qubo_matrix=..., graph=...).

    Returns:
        Algorithm-specific result.
    """
    self.set_input(kwargs)
    self._validate_input()
    self.backend = backend
    try:
        result = self.run_algorithm(backend=self.backend, input=self._input)
    finally:
        # Always clean up, even on error
        self.reset()
    return result

run_algorithm abstractmethod

run_algorithm(backend, input)

Algorithm-specific execution. Override in subclass.

Backend usage
  • backend(circuit, shots=None) or backend.run(circuit, shots=None)
  • backend.run_batch(circuits, shots=None)

Backends return Dict[str, int] mapping bitstrings to counts.

Parameters:

Name Type Description Default
backend Backend

The quantum backend to submit circuits to.

required
input dict[str, Any]

Dict with keys from INPUT_KEYS, all guaranteed non-None.

required

Returns:

Type Description
Any

Algorithm result (solution dict, counts, optimal value, etc.)

Source code in src/quast_decisiontree/algorithms/hybrid/hybrid_algorithm.py
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
@abstractmethod
def run_algorithm(self, backend: Backend, input: dict[str, Any]) -> Any:
    """Algorithm-specific execution. Override in subclass.

    Backend usage:
        - backend(circuit, shots=None) or backend.run(circuit, shots=None)
        - backend.run_batch(circuits, shots=None)

    Backends return Dict[str, int] mapping bitstrings to counts.

    Args:
        backend: The quantum backend to submit circuits to.
        input: Dict with keys from INPUT_KEYS, all guaranteed non-None.

    Returns:
        Algorithm result (solution dict, counts, optimal value, etc.)
    """

get_builder classmethod

get_builder(name=None, description=None)

Create an AutoClassBuilder for this algorithm class.

Source code in src/quast_decisiontree/algorithms/hybrid/hybrid_algorithm.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
@classmethod
def get_builder(cls, name: str | None = None, description: str | None = None):
    """Create an AutoClassBuilder for this algorithm class."""
    from quast_decisiontree.algorithms.hybrid.builder import HybridAlgorithmBuilder
    from quast_decisiontree.core.builder import HyperParam

    # Copy hyperparams so builders don't share mutable state
    copied = [
        HyperParam(
            name=hp.name,
            hparam_type=hp.type,
            description=hp.description,
            default=hp.default if hp.has_default else "",
            test=hp.test,
            allow_multiple=hp.allow_multiple,
        )
        for hp in cls.HYPERPARAMS
    ]
    return HybridAlgorithmBuilder(
        superclass=cls,
        hyperparams=copied,
        name=name or cls.__name__,
        description=description or cls.__doc__ or "",
        input_keys=cls.INPUT_KEYS,
    )