Skip to content

Python SDK

Classiq SDK.

analyzer special

analyzer

Analyzer module, implementing facilities for analyzing circuits using Classiq platform.

Analyzer (AnalyzerUtilities)

Analyzer is the wrapper object for all analysis capabilities.

Source code in classiq/analyzer/analyzer.py
class Analyzer(AnalyzerUtilities):
    """Analyzer is the wrapper object for all analysis capabilities."""

    def __init__(self, circuit: generator_result.QuantumProgram) -> None:
        """Init self.

        Args:
            circuit (): The circuit to be analyzed.
        """
        if circuit.qasm is None:
            raise ClassiqAnalyzerError(
                "Analysis requires a circuit with valid QASM code"
            )
        params: analysis_params.AnalysisParams = analysis_params.AnalysisParams(
            qasm=circuit.qasm
        )
        super().__init__(
            params=params,
            circuit=circuit,
            available_devices=dict(),
            hardware_graphs=dict(),
        )

        self.hardware_comparison_table: Optional[go.Figure] = None

        self.transpilation_params = analysis_params.AnalysisHardwareTranspilationParams(
            hardware_data=self.circuit.hardware_data,
            random_seed=self.circuit.model.execution_preferences.random_seed,
            transpilation_option=self.circuit.model.execution_preferences.transpile_to_hardware,
        )

    def analyzer_app(self) -> None:
        """Opens the analyzer app with synthesis interactive results.

        Returns:
            None.
        """
        result = async_utils.run(ApiWrapper.call_analyzer_app(self.circuit))
        webbrowser.open_new_tab(
            urljoin(
                client_ide_base_url(),
                circuit_page_uri(
                    circuit_id=result.id, circuit_version=self.circuit.version
                ),
            )
        )

    def get_available_devices(
        self, providers: Optional[List[ProviderNameEnum]] = None
    ) -> Dict[ProviderNameEnum, List[DeviceName]]:
        """Deprecated. Use get_all_hardware_devices instead.

        Returns dict of the available devices by the providers. only devices
        with sufficient number of qubits are returns

        Args: providers (): List of providers (string or `AnalyzerProviderVendor`).
        if None, the table include all the available hardware.

        Returns:
            available devices (): dict of the available devices (Dict[str,List[str]]).
        """
        if providers is None:
            providers = list(AnalyzerProviderVendor)
        async_utils.run(self._request_available_devices_async(providers=providers))
        return {
            provider: self._filter_devices_by_qubits_count(provider)
            for provider in providers
        }

    def plot_hardware_connectivity(
        self,
        provider: Optional[ProviderNameEnum] = None,
        device: Optional[DeviceName] = None,
    ) -> VBox:
        """plot the hardware_connectivity graph. It is required to required  install the
        analyzer_sdk extra.

        Args:
            provider (): provider name (optional - string or `AnalyzerProviderVendor`).
            device (): device name (optional - string).
        Returns:
         hardware_connectivity_graph (): interactive graph.
        """

        self._validate_analyzer_extra()
        interactive_hardware = InteractiveHardware(
            circuit=self.circuit,
            params=self._params,
            available_devices=self.available_devices,
            hardware_graphs=self.hardware_graphs,
        )
        async_utils.run(interactive_hardware.enable_interactivity_async())
        if provider is not None:
            interactive_hardware.providers_combobox.value = provider
            if device is not None:
                interactive_hardware.devices_combobox.value = device

        return interactive_hardware.show_interactive_graph()

    def get_hardware_comparison_table(
        self,
        providers: Optional[Sequence[Union[str, AnalyzerProviderVendor]]] = None,
        devices: Optional[List[str]] = None,
    ) -> None:
        """create a comparison table between the transpiled circuits result on different hardware.
        The  comparison table included the depth, multi qubit gates count,and total gates count of the circuits.

        Args: providers (): List of providers (string or `AnalyzerProviderVendor`). if None, the table include all
        the available hardware.
        devices (): List of devices (string). if None, the table include all the available devices of the selected
        providers.
        Returns: None.
        """
        if providers is None:
            providers = list(AnalyzerProviderVendor)
        params = analysis_params.AnalysisHardwareListParams(
            qasm=self._params.qasm,
            providers=providers,
            devices=devices,
            transpilation_params=self.transpilation_params,
        )
        result = async_utils.run(ApiWrapper.call_table_graphs_task(params=params))
        self.hardware_comparison_table = go.Figure(json.loads(result.details))

    def plot_hardware_comparison_table(
        self,
        providers: Optional[List[Union[str, AnalyzerProviderVendor]]] = None,
        devices: Optional[List[str]] = None,
    ) -> None:
        """plot the comparison table. if it has not been created it, it first creates the table using all the
        available hardware.

        Returns:
            None.
        """
        self._hardware_comparison_condition(providers=providers, devices=devices)
        self.hardware_comparison_table.show()  # type: ignore[union-attr]

    def _hardware_comparison_condition(
        self,
        providers: Optional[Sequence[Union[str, AnalyzerProviderVendor]]] = None,
        devices: Optional[List[str]] = None,
    ) -> None:
        if (
            providers is not None
            or devices is not None
            or self.hardware_comparison_table is None
        ):
            self.get_hardware_comparison_table(providers=providers, devices=devices)

    @staticmethod
    def _open_route(path: str) -> None:
        backend_uri = client.client().get_backend_uri()
        webbrowser.open_new_tab(f"{backend_uri}{path}")

    @staticmethod
    def _validate_analyzer_extra() -> None:
        if find_ipywidgets is None:
            raise ClassiqAnalyzerError(
                "To use this method, please install the `analyzer sdk`. Run the  \
                following line: - pip install classiq[analyzer_sdk]"
            )
__init__(self, circuit) special

Init self.

Parameters:

Name Type Description Default
circuit

The circuit to be analyzed.

required
Source code in classiq/analyzer/analyzer.py
def __init__(self, circuit: generator_result.QuantumProgram) -> None:
    """Init self.

    Args:
        circuit (): The circuit to be analyzed.
    """
    if circuit.qasm is None:
        raise ClassiqAnalyzerError(
            "Analysis requires a circuit with valid QASM code"
        )
    params: analysis_params.AnalysisParams = analysis_params.AnalysisParams(
        qasm=circuit.qasm
    )
    super().__init__(
        params=params,
        circuit=circuit,
        available_devices=dict(),
        hardware_graphs=dict(),
    )

    self.hardware_comparison_table: Optional[go.Figure] = None

    self.transpilation_params = analysis_params.AnalysisHardwareTranspilationParams(
        hardware_data=self.circuit.hardware_data,
        random_seed=self.circuit.model.execution_preferences.random_seed,
        transpilation_option=self.circuit.model.execution_preferences.transpile_to_hardware,
    )
analyzer_app(self)

Opens the analyzer app with synthesis interactive results.

Returns:

Type Description
None

None.

Source code in classiq/analyzer/analyzer.py
def analyzer_app(self) -> None:
    """Opens the analyzer app with synthesis interactive results.

    Returns:
        None.
    """
    result = async_utils.run(ApiWrapper.call_analyzer_app(self.circuit))
    webbrowser.open_new_tab(
        urljoin(
            client_ide_base_url(),
            circuit_page_uri(
                circuit_id=result.id, circuit_version=self.circuit.version
            ),
        )
    )
get_available_devices(self, providers=None)

Deprecated. Use get_all_hardware_devices instead.

Returns dict of the available devices by the providers. only devices with sufficient number of qubits are returns

Args: providers (): List of providers (string or AnalyzerProviderVendor). if None, the table include all the available hardware.

Returns:

Type Description
available devices ()

dict of the available devices (Dict[str,List[str]]).

Source code in classiq/analyzer/analyzer.py
def get_available_devices(
    self, providers: Optional[List[ProviderNameEnum]] = None
) -> Dict[ProviderNameEnum, List[DeviceName]]:
    """Deprecated. Use get_all_hardware_devices instead.

    Returns dict of the available devices by the providers. only devices
    with sufficient number of qubits are returns

    Args: providers (): List of providers (string or `AnalyzerProviderVendor`).
    if None, the table include all the available hardware.

    Returns:
        available devices (): dict of the available devices (Dict[str,List[str]]).
    """
    if providers is None:
        providers = list(AnalyzerProviderVendor)
    async_utils.run(self._request_available_devices_async(providers=providers))
    return {
        provider: self._filter_devices_by_qubits_count(provider)
        for provider in providers
    }
get_hardware_comparison_table(self, providers=None, devices=None)

create a comparison table between the transpiled circuits result on different hardware. The comparison table included the depth, multi qubit gates count,and total gates count of the circuits.

Args: providers (): List of providers (string or AnalyzerProviderVendor). if None, the table include all the available hardware. devices (): List of devices (string). if None, the table include all the available devices of the selected providers. Returns: None.

Source code in classiq/analyzer/analyzer.py
def get_hardware_comparison_table(
    self,
    providers: Optional[Sequence[Union[str, AnalyzerProviderVendor]]] = None,
    devices: Optional[List[str]] = None,
) -> None:
    """create a comparison table between the transpiled circuits result on different hardware.
    The  comparison table included the depth, multi qubit gates count,and total gates count of the circuits.

    Args: providers (): List of providers (string or `AnalyzerProviderVendor`). if None, the table include all
    the available hardware.
    devices (): List of devices (string). if None, the table include all the available devices of the selected
    providers.
    Returns: None.
    """
    if providers is None:
        providers = list(AnalyzerProviderVendor)
    params = analysis_params.AnalysisHardwareListParams(
        qasm=self._params.qasm,
        providers=providers,
        devices=devices,
        transpilation_params=self.transpilation_params,
    )
    result = async_utils.run(ApiWrapper.call_table_graphs_task(params=params))
    self.hardware_comparison_table = go.Figure(json.loads(result.details))
plot_hardware_comparison_table(self, providers=None, devices=None)

plot the comparison table. if it has not been created it, it first creates the table using all the available hardware.

Returns:

Type Description
None

None.

Source code in classiq/analyzer/analyzer.py
def plot_hardware_comparison_table(
    self,
    providers: Optional[List[Union[str, AnalyzerProviderVendor]]] = None,
    devices: Optional[List[str]] = None,
) -> None:
    """plot the comparison table. if it has not been created it, it first creates the table using all the
    available hardware.

    Returns:
        None.
    """
    self._hardware_comparison_condition(providers=providers, devices=devices)
    self.hardware_comparison_table.show()  # type: ignore[union-attr]
plot_hardware_connectivity(self, provider=None, device=None)

plot the hardware_connectivity graph. It is required to required install the analyzer_sdk extra.

Parameters:

Name Type Description Default
provider

provider name (optional - string or AnalyzerProviderVendor).

None
device

device name (optional - string).

None

Returns:

Type Description
hardware_connectivity_graph ()

interactive graph.

Source code in classiq/analyzer/analyzer.py
def plot_hardware_connectivity(
    self,
    provider: Optional[ProviderNameEnum] = None,
    device: Optional[DeviceName] = None,
) -> VBox:
    """plot the hardware_connectivity graph. It is required to required  install the
    analyzer_sdk extra.

    Args:
        provider (): provider name (optional - string or `AnalyzerProviderVendor`).
        device (): device name (optional - string).
    Returns:
     hardware_connectivity_graph (): interactive graph.
    """

    self._validate_analyzer_extra()
    interactive_hardware = InteractiveHardware(
        circuit=self.circuit,
        params=self._params,
        available_devices=self.available_devices,
        hardware_graphs=self.hardware_graphs,
    )
    async_utils.run(interactive_hardware.enable_interactivity_async())
    if provider is not None:
        interactive_hardware.providers_combobox.value = provider
        if device is not None:
            interactive_hardware.devices_combobox.value = device

    return interactive_hardware.show_interactive_graph()

rb

RBAnalysis

Source code in classiq/analyzer/rb.py
class RBAnalysis:
    def __init__(self, experiments_data: List[AnalysisRBParams]) -> None:
        """Init self.

        Args:
            experiments_data: List of results from varius RB experiments.
        """

        self.experiments_data = experiments_data
        self._total_results: pd.DataFrame = pd.DataFrame()

    async def _get_multiple_hardware_results_async(self) -> Dict[str, RbResults]:
        total_result: Dict[str, RbResults] = {}
        for batch in self.experiments_data:
            if len(batch.num_clifford) < 5:
                raise ClassiqAnalyzerError(
                    f"An experiment mush contain at least five sequences,"
                    f" this sequence is {len(batch.num_clifford)}"
                )
            rb_result = await ApiWrapper.call_rb_analysis_task(batch)
            total_result[batch.hardware] = rb_result
        return total_result

    @staticmethod
    def _get_df_indices(results: Dict[str, RbResults]) -> List[str]:
        temp_res = results.copy()
        _, rb_result_keys = temp_res.popitem()
        return list(rb_result_keys.__dict__.keys())

    async def show_multiple_hardware_data_async(self) -> pd.DataFrame:
        """Run the RB analysis.

        Returns:
            The RB result.
        """
        results = await self._get_multiple_hardware_results_async()
        indices = RBAnalysis._get_df_indices(results)
        result_df = pd.DataFrame(index=indices)
        for hardware, result in results.items():
            result_df[hardware] = result.__dict__.values()
        self._total_results = result_df
        return result_df

    def plot_multiple_hardware_results(self) -> go.Figure:
        """Plot Bar graph of the results.

        Returns:
            None.
        """
        df = self._total_results.loc[["mean_fidelity", "average_error"]].transpose()
        hardware = list(df.index)
        params = list(df.columns)
        data = [
            go.Bar(name=param, x=hardware, y=df[param].values * 100) for param in params
        ]
        fig = go.Figure(data).update_layout(
            title="RB hardware comparison",
            barmode="group",
            yaxis=dict(title="Fidelity in %"),
            xaxis=dict(title="Hardware"),
        )
        return fig
__init__(self, experiments_data) special

Init self.

Parameters:

Name Type Description Default
experiments_data List[classiq.interface.analyzer.analysis_params.AnalysisRBParams]

List of results from varius RB experiments.

required
Source code in classiq/analyzer/rb.py
def __init__(self, experiments_data: List[AnalysisRBParams]) -> None:
    """Init self.

    Args:
        experiments_data: List of results from varius RB experiments.
    """

    self.experiments_data = experiments_data
    self._total_results: pd.DataFrame = pd.DataFrame()
plot_multiple_hardware_results(self)

Plot Bar graph of the results.

Returns:

Type Description
Figure

None.

Source code in classiq/analyzer/rb.py
def plot_multiple_hardware_results(self) -> go.Figure:
    """Plot Bar graph of the results.

    Returns:
        None.
    """
    df = self._total_results.loc[["mean_fidelity", "average_error"]].transpose()
    hardware = list(df.index)
    params = list(df.columns)
    data = [
        go.Bar(name=param, x=hardware, y=df[param].values * 100) for param in params
    ]
    fig = go.Figure(data).update_layout(
        title="RB hardware comparison",
        barmode="group",
        yaxis=dict(title="Fidelity in %"),
        xaxis=dict(title="Hardware"),
    )
    return fig
show_multiple_hardware_data_async(self) async

Run the RB analysis.

Returns:

Type Description
DataFrame

The RB result.

Source code in classiq/analyzer/rb.py
async def show_multiple_hardware_data_async(self) -> pd.DataFrame:
    """Run the RB analysis.

    Returns:
        The RB result.
    """
    results = await self._get_multiple_hardware_results_async()
    indices = RBAnalysis._get_df_indices(results)
    result_df = pd.DataFrame(index=indices)
    for hardware, result in results.items():
        result_df[hardware] = result.__dict__.values()
    self._total_results = result_df
    return result_df

applications special

chemistry special

ansatz_parameters

HEAParameters dataclass

HEAParameters(reps: int, num_qubits: int, connectivity_map: List[Tuple[int, int]], one_qubit_gates: List[str], two_qubit_gates: List[str])

Source code in classiq/applications/chemistry/ansatz_parameters.py
@dataclasses.dataclass
class HEAParameters:
    reps: int
    num_qubits: int
    connectivity_map: List[Tuple[int, int]]
    one_qubit_gates: List[str]
    two_qubit_gates: List[str]
HVAParameters dataclass

HVAParameters(reps: int)

Source code in classiq/applications/chemistry/ansatz_parameters.py
@dataclasses.dataclass
class HVAParameters:
    reps: int
UCCParameters dataclass

UCCParameters(excitations: List[int] = )

Source code in classiq/applications/chemistry/ansatz_parameters.py
@dataclasses.dataclass
class UCCParameters:
    excitations: EXCITATIONS_TYPE_EXACT = dataclasses.field(
        default_factory=default_excitation_factory
    )

chemistry_execution_parameters

ChemistryExecutionParameters dataclass

ChemistryExecutionParameters(optimizer: classiq.interface.executor.optimizer_preferences.OptimizerType, max_iteration: int, initial_point: Optional[numpy.ndarray] = None, tolerance: float = 0.0, step_size: float = 0.0, skip_compute_variance: bool = False)

Source code in classiq/applications/chemistry/chemistry_execution_parameters.py
@dataclasses.dataclass
class ChemistryExecutionParameters:
    optimizer: OptimizerType
    max_iteration: int
    initial_point: Optional[np.ndarray] = dataclasses.field(default=None)
    tolerance: float = dataclasses.field(default=0.0)
    step_size: float = dataclasses.field(default=0.0)
    skip_compute_variance: bool = dataclasses.field(default=False)

combinatorial_helpers special

encoding_mapping

VarExpressionMapping dataclass

VarExpressionMapping(var: pyomo.core.base.var._GeneralVarData, expr: pyomo.core.base.expression.Expression, encodings_vars: List[pyomo.core.base.var._GeneralVarData] = )

Source code in classiq/applications/combinatorial_helpers/encoding_mapping.py
@dataclass
class VarExpressionMapping:
    var: _GeneralVarData
    expr: pyo.Expression
    encodings_vars: List[_GeneralVarData] = field(default_factory=list)

pauli_helpers special

pauli_sparsing
SparsePauliOp
Source code in classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py
class SparsePauliOp:
    def __init__(self, paulis: Any, coeffs: Any) -> None:
        assert len(paulis) == len(
            coeffs
        ), "Paulis and coefficients lists must have the same length."
        self.paulis = np.array(paulis)
        self.coeffs = np.array(coeffs, dtype=complex)

    def __str__(self) -> str:
        terms = [f"{coef}*{pauli}" for coef, pauli in zip(self.coeffs, self.paulis)]
        return " + ".join(terms)

    def __add__(self, other: "SparsePauliOp") -> "SparsePauliOp":
        """Add two SparsePauliOp objects."""
        if not isinstance(other, SparsePauliOp):
            raise ValueError("Can only add SparsePauliOp objects.")
        new_paulis = np.concatenate([self.paulis, other.paulis])
        new_coeffs = np.concatenate([self.coeffs, other.coeffs])
        return SparsePauliOp(new_paulis, new_coeffs)

    def __mul__(self, other: Union[int, float, complex]) -> "SparsePauliOp":
        """Scalar multiplication of a SparsePauliOp."""
        if not isinstance(other, (int, float, complex)):
            raise ValueError("Can only multiply by scalar values.")
        new_coeffs = self.coeffs * other
        return SparsePauliOp(self.paulis, new_coeffs)
__add__(self, other) special

Add two SparsePauliOp objects.

Source code in classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py
def __add__(self, other: "SparsePauliOp") -> "SparsePauliOp":
    """Add two SparsePauliOp objects."""
    if not isinstance(other, SparsePauliOp):
        raise ValueError("Can only add SparsePauliOp objects.")
    new_paulis = np.concatenate([self.paulis, other.paulis])
    new_coeffs = np.concatenate([self.coeffs, other.coeffs])
    return SparsePauliOp(new_paulis, new_coeffs)
__mul__(self, other) special

Scalar multiplication of a SparsePauliOp.

Source code in classiq/applications/combinatorial_helpers/pauli_helpers/pauli_sparsing.py
def __mul__(self, other: Union[int, float, complex]) -> "SparsePauliOp":
    """Scalar multiplication of a SparsePauliOp."""
    if not isinstance(other, (int, float, complex)):
        raise ValueError("Can only multiply by scalar values.")
    new_coeffs = self.coeffs * other
    return SparsePauliOp(self.paulis, new_coeffs)

pyomo_utils

CombinatorialOptimizationStructDeclaration (StructDeclaration) pydantic-model
Source code in classiq/applications/combinatorial_helpers/pyomo_utils.py
class CombinatorialOptimizationStructDeclaration(StructDeclaration):
    variable_lower_bound: int = pydantic.Field(default=0)
    variable_upper_bound: int = pydantic.Field(default=1)
    constraints: List[Expression] = pydantic.Field(
        default_factory=list, description="List of constraint expressions"
    )
    objective_type: ObjectiveType = pydantic.Field(
        description="Specify whether the optimization problem is Min or Max"
    )
    objective_function: Expression = pydantic.Field(
        description="The expression to optimize, according to the objective type"
    )
constraints: List[classiq.interface.generator.expressions.expression.Expression] pydantic-field

List of constraint expressions

objective_function: Expression pydantic-field required

The expression to optimize, according to the objective type

objective_type: ObjectiveType pydantic-field required

Specify whether the optimization problem is Min or Max

combinatorial_optimization special

combinatorial_optimization_config

OptimizerConfig dataclass

OptimizerConfig(opt_type: classiq.interface.executor.optimizer_preferences.OptimizerType = , max_iteration: Optional[int] = None, tolerance: float = 0.0, step_size: float = 0.0, skip_compute_variance: bool = False, cost_type: classiq.interface.executor.optimizer_preferences.CostType = , alpha_cvar: float = 1.0, initial_point: Optional[List[float]] = None)

Source code in classiq/applications/combinatorial_optimization/combinatorial_optimization_config.py
@dataclass
class OptimizerConfig:
    opt_type: OptimizerType = OptimizerType.COBYLA
    max_iteration: Optional[int] = None
    tolerance: float = 0.0
    step_size: float = 0.0
    skip_compute_variance: bool = False
    cost_type: CostType = CostType.CVAR
    alpha_cvar: float = 1.0
    initial_point: Optional[List[float]] = dataclasses.field(default=None)
QAOAConfig dataclass

QAOAConfig(num_layers: int = 2, penalty_energy: float = 2.0)

Source code in classiq/applications/combinatorial_optimization/combinatorial_optimization_config.py
@dataclass
class QAOAConfig:
    num_layers: int = 2
    penalty_energy: float = 2.0

qnn special

datasets special

datasets_utils
all_bits_to_one(n)

Return an integer of length n bits, where all the bits are 1

Source code in classiq/applications/qnn/datasets/datasets_utils.py
def all_bits_to_one(n: int) -> int:
    """
    Return an integer of length `n` bits, where all the bits are `1`
    """
    return (2**n) - 1
all_bits_to_zero(n)

Return an integer of length n bits, where all the bits are 0

Source code in classiq/applications/qnn/datasets/datasets_utils.py
def all_bits_to_zero(n: int) -> int:
    """
    Return an integer of length `n` bits, where all the bits are `0`
    """
    return 0
state_to_label(pure_state)

input: a Tensor of binary numbers (0 or 1) - the return value of a measurement output: probability (from that measurement) of measuring 0 (in other words, |0> translates to 100% chance for measuring |0> ==> return value is 1.0 |1> translates to 0% chance for measuring |0> ==> return value is 0.0 )

Source code in classiq/applications/qnn/datasets/datasets_utils.py
def state_to_label(pure_state: Tensor) -> Tensor:
    """
    input: a `Tensor` of binary numbers (0 or 1) - the return value of a measurement
    output: probability (from that measurement) of measuring 0
    (in other words,
        |0> translates to 100% chance for measuring |0> ==> return value is 1.0
        |1> translates to   0% chance for measuring |0> ==> return value is 0.0
    )
    """
    # |0> means 100% chance to get |0> ==> 100% == 1.0
    # |1> means   0% chance to get |0> ==>   0% == 0.0

    # This line basically does `1 - bool(pure_state)`
    return 1 - pure_state.bool().int()
state_to_weights(pure_state)

input: a Tensor of binary numbers (0 or 1) output: the required angle of rotation for Rx (in other words, |0> translates to no rotation, and |1> translates to pi)

Source code in classiq/applications/qnn/datasets/datasets_utils.py
def state_to_weights(pure_state: Tensor) -> Tensor:
    """
    input: a `Tensor` of binary numbers (0 or 1)
    output: the required angle of rotation for `Rx`
    (in other words, |0> translates to no rotation, and |1> translates to `pi`)
    """
    # |0> requires a rotation by 0
    # |1> requires a rotation by pi
    return pure_state.bool().int() * np.pi

qlayer

QLayer (Module)
Source code in classiq/applications/qnn/qlayer.py
class QLayer(nn.Module):
    def __init__(
        self,
        quantum_program: SerializedQuantumProgram,
        execute: ExecuteFunction,
        post_process: PostProcessFunction,
        # Optional parameters:
        head_start: Union[float, Tensor, None] = None,
        # Experimental parameters:
        calc_num_out_features: CalcNumOutFeatures = calc_num_out_features_single_output,
    ) -> None:
        circuit = Circuit.parse_raw(quantum_program)
        validate_circuit(circuit)

        super().__init__()

        self._execute = execute
        self._post_process = post_process
        self._head_start = head_start

        self.quantum_program = quantum_program

        weights, _ = extract_parameters(circuit)
        self.in_features: int = len(weights)
        self.out_features: int = calc_num_out_features(quantum_program)

        self._initialize_parameters()

    def _initialize_parameters(self) -> None:
        shape: Tuple[int, ...] = (
            (self.out_features, self.in_features)
            if self.out_features > 1
            else (self.in_features,)
        )

        if self._head_start is None:
            value = torch.rand(shape)
        elif isinstance(self._head_start, (float, int)):
            value = torch.zeros(shape) + self._head_start
        elif isinstance(self._head_start, Tensor):
            value = self._head_start.clone()
        else:
            raise ClassiqQNNError(
                f"Unsupported feature - head_start of type {type(self._head_start)}"
            )

        self.weight = Parameter(value)

    def forward(self, x: Tensor) -> Tensor:
        return QLayerFunction.apply(  # type: ignore[no-untyped-call]
            x, self.weight, self.quantum_program, self._execute, self._post_process
        )
forward(self, x)

Define the computation performed at every call.

Should be overridden by all subclasses.

.. note:: Although the recipe for forward pass needs to be defined within this function, one should call the :class:Module instance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.

Source code in classiq/applications/qnn/qlayer.py
def forward(self, x: Tensor) -> Tensor:
    return QLayerFunction.apply(  # type: ignore[no-untyped-call]
        x, self.weight, self.quantum_program, self._execute, self._post_process
    )
QLayerFunction (Function)
Source code in classiq/applications/qnn/qlayer.py
class QLayerFunction(torch.autograd.Function):
    @staticmethod
    def forward(  # type: ignore[override]
        ctx: Any,
        inputs: Tensor,
        weights: Tensor,
        quantum_program: SerializedQuantumProgram,
        execute: ExecuteFunction,
        post_process: PostProcessFunction,
    ) -> Tensor:
        """
        This function receives:
            inputs: a 2D Tensor of floats - (batch_size, in_features)
            weights: a 2D Tensor of floats - (out_features, num_weights)
            circuit: a `GeneratedCircuit` object
            execute: a function taking a `GeneratedCircuit` and `MultipleArguments`
                and returning `MultipleExecutionDetails`
            post_process: a function taking a single `ExecutionDetails`
                and returning a `Tensor`

        """
        circuit = Circuit.parse_raw(quantum_program)
        validate_circuit(circuit)

        # save for backward
        ctx.save_for_backward(inputs, weights)
        ctx.quantum_program = quantum_program
        ctx.execute = execute
        ctx.post_process = post_process
        ctx.quantum_gradient = SimpleQuantumGradient(
            quantum_program, execute, post_process
        )

        ctx.batch_size, ctx.num_in_features = inputs.shape
        if is_single_layer_circuit(weights):
            ctx.num_weights = weights.shape
        else:
            ctx.num_out_features, ctx.num_weights = weights.shape

        # Todo: avoid computing `_get_extracted_parameters` on every `forward`
        extracted_parameters = extract_parameters(circuit)

        # Todo: avoid defining `convert_tensors_to_arguments` on every `forward`
        def convert_tensors_to_arguments(
            inputs_: Tensor, weights_: Tensor
        ) -> MultipleArguments:
            arguments = map_parameters(
                extracted_parameters,
                inputs_,
                weights_,
            )
            return (arguments,)

        return iter_inputs_weights(
            inputs,
            weights,
            convert_tensors_to_arguments,
            functools.partial(execute, quantum_program),
            post_process,
        )

    @staticmethod
    def backward(  # type: ignore[override]
        ctx: Any, grad_output: Tensor
    ) -> Tuple[Optional[Tensor], Optional[Tensor], None, None, None]:
        """
        grad_output: Tensor
            is of shape (ctx.batch_size, ctx.num_out_features)
        """
        inputs, weights = ctx.saved_tensors

        grad_weights = grad_inputs = None
        grad_circuit = grad_execute = grad_post_process = None
        is_single_layer = is_single_layer_circuit(weights)

        if ctx.needs_input_grad[1]:
            grad_weights = ctx.quantum_gradient.gradient_weights(inputs, weights)
            grad_weights = einsum_weigths(grad_output, grad_weights, is_single_layer)

        if ctx.needs_input_grad[0]:
            grad_inputs = ctx.quantum_gradient.gradient_inputs(inputs, weights)
            grad_inputs = einsum_inputs(grad_output, grad_inputs, is_single_layer)

        if any(ctx.needs_input_grad[i] for i in (2, 3, 4)):
            raise ClassiqTorchError(
                f"Grad required for unknown type: {ctx.needs_input_grad}"
            )

        return grad_inputs, grad_weights, grad_circuit, grad_execute, grad_post_process
backward(ctx, grad_output) staticmethod

Tensor

is of shape (ctx.batch_size, ctx.num_out_features)

Source code in classiq/applications/qnn/qlayer.py
@staticmethod
def backward(  # type: ignore[override]
    ctx: Any, grad_output: Tensor
) -> Tuple[Optional[Tensor], Optional[Tensor], None, None, None]:
    """
    grad_output: Tensor
        is of shape (ctx.batch_size, ctx.num_out_features)
    """
    inputs, weights = ctx.saved_tensors

    grad_weights = grad_inputs = None
    grad_circuit = grad_execute = grad_post_process = None
    is_single_layer = is_single_layer_circuit(weights)

    if ctx.needs_input_grad[1]:
        grad_weights = ctx.quantum_gradient.gradient_weights(inputs, weights)
        grad_weights = einsum_weigths(grad_output, grad_weights, is_single_layer)

    if ctx.needs_input_grad[0]:
        grad_inputs = ctx.quantum_gradient.gradient_inputs(inputs, weights)
        grad_inputs = einsum_inputs(grad_output, grad_inputs, is_single_layer)

    if any(ctx.needs_input_grad[i] for i in (2, 3, 4)):
        raise ClassiqTorchError(
            f"Grad required for unknown type: {ctx.needs_input_grad}"
        )

    return grad_inputs, grad_weights, grad_circuit, grad_execute, grad_post_process
forward(ctx, inputs, weights, quantum_program, execute, post_process) staticmethod

This function receives: inputs: a 2D Tensor of floats - (batch_size, in_features) weights: a 2D Tensor of floats - (out_features, num_weights) circuit: a GeneratedCircuit object !!! execute "a function taking a GeneratedCircuit and MultipleArguments" and returning MultipleExecutionDetails !!! post_process "a function taking a single ExecutionDetails" and returning a Tensor

Source code in classiq/applications/qnn/qlayer.py
@staticmethod
def forward(  # type: ignore[override]
    ctx: Any,
    inputs: Tensor,
    weights: Tensor,
    quantum_program: SerializedQuantumProgram,
    execute: ExecuteFunction,
    post_process: PostProcessFunction,
) -> Tensor:
    """
    This function receives:
        inputs: a 2D Tensor of floats - (batch_size, in_features)
        weights: a 2D Tensor of floats - (out_features, num_weights)
        circuit: a `GeneratedCircuit` object
        execute: a function taking a `GeneratedCircuit` and `MultipleArguments`
            and returning `MultipleExecutionDetails`
        post_process: a function taking a single `ExecutionDetails`
            and returning a `Tensor`

    """
    circuit = Circuit.parse_raw(quantum_program)
    validate_circuit(circuit)

    # save for backward
    ctx.save_for_backward(inputs, weights)
    ctx.quantum_program = quantum_program
    ctx.execute = execute
    ctx.post_process = post_process
    ctx.quantum_gradient = SimpleQuantumGradient(
        quantum_program, execute, post_process
    )

    ctx.batch_size, ctx.num_in_features = inputs.shape
    if is_single_layer_circuit(weights):
        ctx.num_weights = weights.shape
    else:
        ctx.num_out_features, ctx.num_weights = weights.shape

    # Todo: avoid computing `_get_extracted_parameters` on every `forward`
    extracted_parameters = extract_parameters(circuit)

    # Todo: avoid defining `convert_tensors_to_arguments` on every `forward`
    def convert_tensors_to_arguments(
        inputs_: Tensor, weights_: Tensor
    ) -> MultipleArguments:
        arguments = map_parameters(
            extracted_parameters,
            inputs_,
            weights_,
        )
        return (arguments,)

    return iter_inputs_weights(
        inputs,
        weights,
        convert_tensors_to_arguments,
        functools.partial(execute, quantum_program),
        post_process,
    )

execution special

all_hardware_devices

get_all_hardware_devices()

Returns a list of all hardware devices known to Classiq.

Source code in classiq/execution/all_hardware_devices.py
def get_all_hardware_devices() -> List[HardwareInformation]:
    """
    Returns a list of all hardware devices known to Classiq.
    """
    return async_utils.run(ApiWrapper.call_get_all_hardware_devices())

executor

Executor module, implementing facilities for executing quantum programs using Classiq platform.

interface special

analyzer special

analysis_params

AnalysisOptionalDevicesParams (HardwareListParams) pydantic-model
Source code in classiq/interface/analyzer/analysis_params.py
class AnalysisOptionalDevicesParams(HardwareListParams):
    qubit_count: int = pydantic.Field(
        default=..., description="number of qubits in the data"
    )
qubit_count: int pydantic-field required

number of qubits in the data

ChemistryGenerationParams (BaseModel) pydantic-model
Source code in classiq/interface/analyzer/analysis_params.py
class ChemistryGenerationParams(pydantic.BaseModel):
    class Config:
        title = "Chemistry"

    molecule: MoleculeProblem = pydantic.Field(
        title="Molecule",
        default=...,
        description="The molecule to generate the VQE ansatz for",
    )
    optimizer_preferences: OptimizerPreferences = pydantic.Field(
        default=..., description="Execution options for the classical Optimizer"
    )

    def initial_point(self) -> Optional[numpy.ndarray]:
        if self.optimizer_preferences.initial_point is not None:
            return numpy.ndarray(
                self.optimizer_preferences.initial_point  # type: ignore[arg-type]
            )
        else:
            return None
molecule: MoleculeProblem pydantic-field required

The molecule to generate the VQE ansatz for

optimizer_preferences: OptimizerPreferences pydantic-field required

Execution options for the classical Optimizer

HardwareListParams (BaseModel) pydantic-model
Source code in classiq/interface/analyzer/analysis_params.py
class HardwareListParams(pydantic.BaseModel):
    devices: Optional[List[PydanticNonEmptyString]] = pydantic.Field(
        default=None, description="Devices"
    )
    providers: List[Provider]
    from_ide: bool = Field(default=False)

    @pydantic.validator("providers", always=True)
    def set_default_providers(
        cls, providers: Optional[List[AnalyzerProviderVendor]]
    ) -> List[AnalyzerProviderVendor]:
        if providers is None:
            providers = list(AnalyzerProviderVendor)
        return providers
devices: List[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue] pydantic-field

Devices

HardwareParams (BaseModel) pydantic-model
Source code in classiq/interface/analyzer/analysis_params.py
class HardwareParams(pydantic.BaseModel):
    device: PydanticNonEmptyString = pydantic.Field(default=None, description="Devices")
    provider: AnalyzerProviderVendor
device: ConstrainedStrValue pydantic-field

Devices

cytoscape_graph

CytoScapeEdge (BaseModel) pydantic-model
Source code in classiq/interface/analyzer/cytoscape_graph.py
class CytoScapeEdge(pydantic.BaseModel):
    data: CytoScapeEdgeData = pydantic.Field(
        default=..., description="Edge's Data, mainly the source and target of the Edge"
    )
data: CytoScapeEdgeData pydantic-field required

Edge's Data, mainly the source and target of the Edge

CytoScapeEdgeData (BaseModel) pydantic-model
Source code in classiq/interface/analyzer/cytoscape_graph.py
class CytoScapeEdgeData(pydantic.BaseModel):
    source: str = pydantic.Field(
        default=..., description="the Id of the Node that is the Source of the edge"
    )
    target: str = pydantic.Field(
        default=..., description="the Id of the Node that is the Target the edge"
    )
source: str pydantic-field required

the Id of the Node that is the Source of the edge

target: str pydantic-field required

the Id of the Node that is the Target the edge

CytoScapeGraph (BaseModel) pydantic-model
Source code in classiq/interface/analyzer/cytoscape_graph.py
class CytoScapeGraph(pydantic.BaseModel):
    nodes: List[CytoScapeNode] = pydantic.Field(
        default_factory=list,
        description="Nodes of the Graph",
    )
    edges: List[CytoScapeEdge] = pydantic.Field(
        default_factory=list,
        description="Edges of the Graph",
    )
edges: List[classiq.interface.analyzer.cytoscape_graph.CytoScapeEdge] pydantic-field

Edges of the Graph

nodes: List[classiq.interface.analyzer.cytoscape_graph.CytoScapeNode] pydantic-field

Nodes of the Graph

CytoScapeNode (BaseModel) pydantic-model
Source code in classiq/interface/analyzer/cytoscape_graph.py
class CytoScapeNode(pydantic.BaseModel):
    data: Dict[str, Any] = pydantic.Field(
        default=...,
        description="Data of the Node, such as label, and color, can be of free form",
    )
    position: Optional[CytoScapePosition] = pydantic.Field(
        default=..., description="Position of the Node to be rendered in Cytocape"
    )
data: Dict[str, Any] pydantic-field required

Data of the Node, such as label, and color, can be of free form

position: CytoScapePosition pydantic-field required

Position of the Node to be rendered in Cytocape

CytoScapePosition (BaseModel) pydantic-model
Source code in classiq/interface/analyzer/cytoscape_graph.py
class CytoScapePosition(pydantic.BaseModel):
    x: int = pydantic.Field(
        default=..., description="X coordinate in the Cytoscape View"
    )
    y: int = pydantic.Field(
        default=..., description="Y coordinate in the Cytoscape View"
    )
x: int pydantic-field required

X coordinate in the Cytoscape View

y: int pydantic-field required

Y coordinate in the Cytoscape View

HardwareConnectivityGraphResult (VersionedModel) pydantic-model
Source code in classiq/interface/analyzer/cytoscape_graph.py
class HardwareConnectivityGraphResult(VersionedModel):
    graph: Optional[CytoScapeGraph] = pydantic.Field(
        default=...,
        description="The Cytoscape graph in the desired Structure for the FE",
    )
    error: ConnectivityErrors = pydantic.Field(
        default=ConnectivityErrors.EMPTY,
        description="Any errors encountered while generating the graph",
    )
error: ConnectivityErrors pydantic-field

Any errors encountered while generating the graph

graph: CytoScapeGraph pydantic-field required

The Cytoscape graph in the desired Structure for the FE

__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

result

Analysis (VersionedModel) pydantic-model
Source code in classiq/interface/analyzer/result.py
class Analysis(VersionedModel):
    input_properties: QuantumCircuitProperties = pydantic.Field(
        default=..., description="Input circuit properties"
    )
    native_properties: NativeQuantumCircuitProperties = pydantic.Field(
        default=..., description="Transpiled circuit properties"
    )
input_properties: QuantumCircuitProperties pydantic-field required

Input circuit properties

native_properties: NativeQuantumCircuitProperties pydantic-field required

Transpiled circuit properties

__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

AvailableHardware (BaseModel) pydantic-model
Source code in classiq/interface/analyzer/result.py
class AvailableHardware(pydantic.BaseModel):
    ibm_quantum: Optional[Dict[PydanticNonEmptyString, bool]] = pydantic.Field(
        default=None,
        description="available IBM Quantum devices with boolean indicates if a given device has enough qubits.",
    )
    azure_quantum: Optional[Dict[PydanticNonEmptyString, bool]] = pydantic.Field(
        default=None,
        description="available Azure Quantum devices with boolean indicates if a given device has enough qubits.",
    )
    amazon_braket: Optional[Dict[PydanticNonEmptyString, bool]] = pydantic.Field(
        default=None,
        description="available Amazon Braket devices with boolean indicates if a given device has enough qubits.",
    )
amazon_braket: Dict[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue, bool] pydantic-field

available Amazon Braket devices with boolean indicates if a given device has enough qubits.

azure_quantum: Dict[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue, bool] pydantic-field

available Azure Quantum devices with boolean indicates if a given device has enough qubits.

ibm_quantum: Dict[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue, bool] pydantic-field

available IBM Quantum devices with boolean indicates if a given device has enough qubits.

DevicesResult (VersionedModel) pydantic-model
Source code in classiq/interface/analyzer/result.py
class DevicesResult(VersionedModel):
    devices: AvailableHardware
    status: GraphStatus
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

GraphResult (VersionedModel) pydantic-model
Source code in classiq/interface/analyzer/result.py
class GraphResult(VersionedModel):
    kind: Literal["graph"] = Field(default="graph")
    details: str
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

HardwareComparisonData (VersionedModel) pydantic-model
Source code in classiq/interface/analyzer/result.py
class HardwareComparisonData(VersionedModel):
    kind: Literal["hardware_comparison"] = Field(default="hardware_comparison")
    data: List[SingleHardwareInformation]
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

HardwareComparisonInformation (BaseModel) pydantic-model
Source code in classiq/interface/analyzer/result.py
class HardwareComparisonInformation(pydantic.BaseModel):
    devices: List[str] = pydantic.Field(
        default=..., description="Device which is used for the transpilation."
    )
    providers: List[str] = pydantic.Field(
        default=..., description="Provider cloud of the device."
    )
    depth: List[pydantic.NonNegativeInt] = pydantic.Field(
        default=..., description="Circuit depth."
    )
    multi_qubit_gate_count: List[pydantic.NonNegativeInt] = pydantic.Field(
        default=..., description="Number of multi qubit gates."
    )
    total_gate_count: List[pydantic.NonNegativeInt] = pydantic.Field(
        default=..., description="Number of total gates."
    )

    @pydantic.root_validator
    def validate_equal_length(cls, values: Dict[str, list]) -> Dict[str, list]:
        lengths = list(map(len, values.values()))
        if len(set(lengths)) != 1:
            raise ClassiqValueError("All lists should have the same length")
        return values
depth: List[pydantic.types.NonNegativeInt] pydantic-field required

Circuit depth.

devices: List[str] pydantic-field required

Device which is used for the transpilation.

multi_qubit_gate_count: List[pydantic.types.NonNegativeInt] pydantic-field required

Number of multi qubit gates.

providers: List[str] pydantic-field required

Provider cloud of the device.

total_gate_count: List[pydantic.types.NonNegativeInt] pydantic-field required

Number of total gates.

NativeQuantumCircuitProperties (QuantumCircuitProperties) pydantic-model
Source code in classiq/interface/analyzer/result.py
class NativeQuantumCircuitProperties(QuantumCircuitProperties):
    native_gates: Set[BasisGates] = pydantic.Field(
        default=..., description="Native gates used for decomposition"
    )
native_gates: Set[classiq.interface.analyzer.result.BasisGates] pydantic-field required

Native gates used for decomposition

QuantumCircuitProperties (BaseModel) pydantic-model
Source code in classiq/interface/analyzer/result.py
class QuantumCircuitProperties(pydantic.BaseModel):
    depth: pydantic.NonNegativeInt = pydantic.Field(
        default=..., description="Circuit depth"
    )
    auxiliary_qubits: pydantic.NonNegativeInt = pydantic.Field(
        default=..., description="Number of Auxiliary qubits"
    )
    classical_bits: pydantic.NonNegativeInt = pydantic.Field(
        default=..., description="Number of classical bits"
    )
    gates_count: pydantic.NonNegativeInt = pydantic.Field(
        default=..., description="Total number of gates in the circuit"
    )
    multi_qubit_gates_count: pydantic.NonNegativeInt = pydantic.Field(
        default=..., description="Number of multi-qubit gates in circuit"
    )
    non_entangled_subcircuits_count: pydantic.NonNegativeInt = pydantic.Field(
        default=..., description="Number of non-entangled sub-circuit "
    )
auxiliary_qubits: NonNegativeInt pydantic-field required

Number of Auxiliary qubits

classical_bits: NonNegativeInt pydantic-field required

Number of classical bits

depth: NonNegativeInt pydantic-field required

Circuit depth

gates_count: NonNegativeInt pydantic-field required

Total number of gates in the circuit

multi_qubit_gates_count: NonNegativeInt pydantic-field required

Number of multi-qubit gates in circuit

non_entangled_subcircuits_count: NonNegativeInt pydantic-field required

Number of non-entangled sub-circuit

RbResults (VersionedModel) pydantic-model
Source code in classiq/interface/analyzer/result.py
class RbResults(VersionedModel):
    mean_fidelity: float
    average_error: float
    A: float
    B: float
    success_probability: List[float]
    parameters_error: Tuple[float, ...]
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

SingleHardwareInformation (BaseModel) pydantic-model
Source code in classiq/interface/analyzer/result.py
class SingleHardwareInformation(pydantic.BaseModel):
    devices: str = pydantic.Field(
        default=..., description="Device which is used for the transpilation."
    )
    providers: str = pydantic.Field(
        default=..., description="Provider cloud of the device."
    )
    depth: pydantic.NonNegativeInt = pydantic.Field(
        default=..., description="Circuit depth."
    )
    multi_qubit_gate_count: pydantic.NonNegativeInt = pydantic.Field(
        default=..., description="Number of multi qubit gates."
    )
    total_gate_count: pydantic.NonNegativeInt = pydantic.Field(
        default=..., description="Number of total gates."
    )
depth: NonNegativeInt pydantic-field required

Circuit depth.

devices: str pydantic-field required

Device which is used for the transpilation.

multi_qubit_gate_count: NonNegativeInt pydantic-field required

Number of multi qubit gates.

providers: str pydantic-field required

Provider cloud of the device.

total_gate_count: NonNegativeInt pydantic-field required

Number of total gates.

applications special

qsvm

QSVMData (VersionedModel) pydantic-model
Source code in classiq/interface/applications/qsvm.py
class QSVMData(VersionedModel):
    data: DataList
    labels: Optional[LabelsInt] = None
    internal_state: Optional[QSVMInternalState] = None
    preferences: QSVMPreferences

    class Config:
        smart_union = True
        extra = "forbid"

    @pydantic.validator("data", pre=True)
    def set_data(cls, data: Union[IterableType, ArrayLike]) -> list:
        return listify(data)

    @pydantic.validator("labels", pre=True)
    def set_labels(
        cls, labels: Optional[Union[IterableType, ArrayLike]]
    ) -> Optional[list]:
        if labels is None:
            return None
        else:
            return listify(labels)
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

QSVMInternalState (VersionedModel) pydantic-model
Source code in classiq/interface/applications/qsvm.py
class QSVMInternalState(VersionedModel):
    underscore_sparse: bool
    class_weight: list
    classes: list
    underscore_gamma: float
    underscore_base_fit: list
    support: list
    support_vectors: list
    underscore_n_support: list
    dual_coef_2: list
    intercept: list
    underscore_p_a: list
    underscore_p_b: list
    fit_status: int
    shape_fit: Shape
    underscore_intercept: list
    dual_coef: list

    class_weight__shape: Shape
    classes__shape: Shape
    underscore_base_fit__shape: Shape
    support__shape: Shape
    support_vectors__shape: Shape
    underscore_n_support__shape: Shape
    dual_coef_2__shape: Shape
    intercept__shape: Shape
    underscore_p_a__shape: Shape
    underscore_p_b__shape: Shape
    underscore_intercept__shape: Shape
    dual_coef__shape: Shape

    set_class_weight = validate_array_to_list("class_weight")
    set_classes = validate_array_to_list("classes")
    set_underscore_base_fit = validate_array_to_list("underscore_base_fit")
    set_support = validate_array_to_list("support")
    set_support_vectors = validate_array_to_list("support_vectors")
    set_underscore_n_support = validate_array_to_list("underscore_n_support")
    set_dual_coef_2 = validate_array_to_list("dual_coef_2")
    set_intercept = validate_array_to_list("intercept")
    set_underscore_p_a = validate_array_to_list("underscore_p_a")
    set_underscore_p_b = validate_array_to_list("underscore_p_b")
    set_underscore_intercept = validate_array_to_list("underscore_intercept")
    set_dual_coef = validate_array_to_list("dual_coef")
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

QSVMPredictResult (VersionedModel) pydantic-model
Source code in classiq/interface/applications/qsvm.py
class QSVMPredictResult(VersionedModel):
    data: list  # serialized np.array
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

QSVMTestResult (VersionedModel) pydantic-model
Source code in classiq/interface/applications/qsvm.py
class QSVMTestResult(VersionedModel):
    data: float  # between 0 to 1
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

backend special

backend_preferences

AliceBobBackendPreferences (BackendPreferences) pydantic-model
Source code in classiq/interface/backend/backend_preferences.py
class AliceBobBackendPreferences(BackendPreferences):
    backend_service_provider: ProviderTypeVendor.ALICE_BOB
    api_key: pydantic_backend.PydanticAliceBobApiKeyType = pydantic.Field(
        ..., description="AliceBob API key"
    )

    @pydantic.root_validator(pre=True)
    def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        return values_with_discriminator(
            values, "backend_service_provider", ProviderVendor.ALICE_AND_BOB
        )
api_key: ConstrainedStrValue pydantic-field required

AliceBob API key

AwsBackendPreferences (BackendPreferences) pydantic-model
Source code in classiq/interface/backend/backend_preferences.py
class AwsBackendPreferences(BackendPreferences):
    backend_service_provider: ProviderTypeVendor.AMAZON_BRAKET
    aws_role_arn: pydantic_backend.PydanticAwsRoleArn = pydantic.Field(
        description="ARN of the role to be assumed for execution on your Braket account."
    )
    s3_bucket_name: str = pydantic.Field(description="S3 Bucket Name")
    s3_folder: pydantic_backend.PydanticS3BucketKey = pydantic.Field(
        description="S3 Folder Path Within The S3 Bucket"
    )
    job_timeout: pydantic_backend.PydanticExecutionTimeout = pydantic.Field(
        description="Timeout for Jobs sent for execution in seconds.",
        default=AWS_DEFAULT_JOB_TIMEOUT_SECONDS,
    )

    @validator("s3_bucket_name")
    def _validate_s3_bucket_name(
        cls, s3_bucket_name: str, values: Dict[str, Any]
    ) -> str:
        s3_bucket_name = s3_bucket_name.strip()
        if not s3_bucket_name.startswith("amazon-braket-"):
            raise ClassiqValueError('S3 bucket name should start with "amazon-braket-"')
        return s3_bucket_name

    @pydantic.root_validator(pre=True)
    def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        return values_with_discriminator(
            values, "backend_service_provider", ProviderVendor.AMAZON_BRAKET
        )
aws_role_arn: ConstrainedStrValue pydantic-field required

ARN of the role to be assumed for execution on your Braket account.

job_timeout: ConstrainedIntValue pydantic-field

Timeout for Jobs sent for execution in seconds.

s3_bucket_name: str pydantic-field required

S3 Bucket Name

s3_folder: ConstrainedStrValue pydantic-field required

S3 Folder Path Within The S3 Bucket

AzureBackendPreferences (BackendPreferences) pydantic-model
Source code in classiq/interface/backend/backend_preferences.py
class AzureBackendPreferences(BackendPreferences):
    backend_service_provider: ProviderTypeVendor.AZURE_QUANTUM

    location: str = pydantic.Field(
        default="East US", description="Azure personal resource region"
    )

    credentials: Optional[AzureCredential] = pydantic.Field(
        default=None,
        description="The service principal credential to access personal quantum workspace",
    )

    @property
    def run_through_classiq(self) -> bool:
        return self.credentials is None

    @pydantic.root_validator(pre=True)
    def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        return values_with_discriminator(
            values, "backend_service_provider", ProviderVendor.AZURE_QUANTUM
        )
credentials: AzureCredential pydantic-field

The service principal credential to access personal quantum workspace

location: str pydantic-field

Azure personal resource region

AzureCredential (BaseSettings) pydantic-model
Source code in classiq/interface/backend/backend_preferences.py
class AzureCredential(pydantic.BaseSettings):
    tenant_id: str = pydantic.Field(description="Azure Tenant ID")
    client_id: str = pydantic.Field(description="Azure Client ID")
    client_secret: str = pydantic.Field(description="Azure Client Secret")
    resource_id: pydantic_backend.PydanticAzureResourceIDType = pydantic.Field(
        description="Azure Resource ID (including Azure subscription ID, resource "
        "group and workspace), for personal resource",
    )

    class Config:
        title = "Azure Service Principal Credential"
        env_prefix = "AZURE_"
        case_sensitive = False
client_id: str pydantic-field required

Azure Client ID

client_secret: str pydantic-field required

Azure Client Secret

resource_id: ConstrainedStrValue pydantic-field required

Azure Resource ID (including Azure subscription ID, resource group and workspace), for personal resource

tenant_id: str pydantic-field required

Azure Tenant ID

BackendPreferences (BaseModel) pydantic-model
Source code in classiq/interface/backend/backend_preferences.py
class BackendPreferences(BaseModel):
    # Due to the way the field is currently implemented, i.e. it redefined with different types
    # in the subclass, it shouldn't be dumped with exclude_unset. This causes this field not to appear.
    # For example: don't use obj.dict(exclude_unset=True).
    backend_service_provider: str = pydantic.Field(
        ..., description="Provider company or cloud for the requested backend."
    )
    backend_name: str = pydantic.Field(
        ..., description="Name of the requested backend or target."
    )

    @property
    def hw_provider(self) -> Provider:
        return Provider(self.backend_service_provider)

    @pydantic.validator("backend_service_provider", pre=True)
    def validate_backend_service_provider(
        cls, backend_service_provider: Any
    ) -> Provider:
        return validate_backend_service_provider(backend_service_provider)

    @classmethod
    def batch_preferences(
        cls, *, backend_names: Iterable[str], **kwargs: Any
    ) -> List[BackendPreferences]:
        return [cls(backend_name=name, **kwargs) for name in backend_names]

    def is_nvidia_backend(self) -> bool:
        return False
backend_name: str pydantic-field required

Name of the requested backend or target.

backend_service_provider: str pydantic-field required

Provider company or cloud for the requested backend.

IBMBackendPreferences (BackendPreferences) pydantic-model
Source code in classiq/interface/backend/backend_preferences.py
class IBMBackendPreferences(BackendPreferences):
    backend_service_provider: ProviderTypeVendor.IBM_QUANTUM
    access_token: Optional[str] = pydantic.Field(
        default=None,
        description="IBM Quantum access token to be used"
        " with IBM Quantum hosted backends",
    )
    provider: IBMBackendProvider = pydantic.Field(
        default_factory=IBMBackendProvider,
        description="Provider specs. for identifying a single IBM Quantum provider.",
    )

    @pydantic.root_validator(pre=True)
    def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        return values_with_discriminator(
            values, "backend_service_provider", ProviderVendor.IBM_QUANTUM
        )
access_token: str pydantic-field

IBM Quantum access token to be used with IBM Quantum hosted backends

provider: IBMBackendProvider pydantic-field

Provider specs. for identifying a single IBM Quantum provider.

IonqBackendPreferences (BackendPreferences) pydantic-model
Source code in classiq/interface/backend/backend_preferences.py
class IonqBackendPreferences(BackendPreferences):
    backend_service_provider: ProviderTypeVendor.IONQ
    api_key: pydantic_backend.PydanticIonQApiKeyType = pydantic.Field(
        ..., description="IonQ API key"
    )

    @pydantic.root_validator(pre=True)
    def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        return values_with_discriminator(
            values, "backend_service_provider", ProviderVendor.IONQ
        )
api_key: ConstrainedStrValue pydantic-field required

IonQ API key

OQCBackendPreferences (BackendPreferences) pydantic-model
Source code in classiq/interface/backend/backend_preferences.py
class OQCBackendPreferences(BackendPreferences):
    backend_service_provider: ProviderTypeVendor.OQC
    username: str = pydantic.Field(description="OQC username")
    password: str = pydantic.Field(description="OQC password")

    @pydantic.root_validator(pre=True)
    def _set_backend_service_provider(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        return values_with_discriminator(
            values, "backend_service_provider", ProviderVendor.OQC
        )
password: str pydantic-field required

OQC password

username: str pydantic-field required

OQC username

chemistry special

fermionic_operator

FermionicOperator (HashablePydanticBaseModel) pydantic-model

Specification of a Fermionic operator. Input: List of ladder operators, each ladder operator is described by a tuple of its index and a character indicating if it's a creation ('+') or annihilation operator ('-').

Source code in classiq/interface/chemistry/fermionic_operator.py
class FermionicOperator(HashablePydanticBaseModel):
    """
    Specification of a Fermionic operator.
    Input:
    List of ladder operators, each ladder operator is described by a tuple of its
    index and a character indicating if it's a creation ('+') or annihilation operator ('-').
    """

    op_list: list = pydantic.Field(
        description="A list of tuples each containing an index and a character; for example [('+', 0), ('-', 1)].",
    )

    @staticmethod
    def _validate_single_op(op: tuple) -> LadderOperator:
        if not isinstance(op, tuple):
            try:  # type: ignore[unreachable] # it is reachable...
                op = tuple(op)
            except Exception as exc:
                raise ClassiqValueError("Ladder operator should be a tuple.") from exc
        if len(op) != 2:
            raise ClassiqValueError(
                "Ladder operator tuple should be of length two; for example (1, '+')."
            )

        if op[0] not in ("+", "-"):
            raise ClassiqValueError(
                "The first term in a ladder operator tuple indicates if its a raising ('+')"
                f" or lowering ('-') operator. Allowed input is: '+' or '-', received {op[0]}"
            )
        if not isinstance(op[1], int):
            raise ClassiqValueError(
                "The second term in a ladder operator tuple indicates its index and should be of type int"
            )

        return op  # type: ignore[return-value] # mypy thinks that it is `Tuple[Any, ...]`, though the asserts here tell otherwise..

    @pydantic.validator("op_list")
    def _validate_op_list(cls, op_list: list) -> list:
        return list(map(cls._validate_single_op, op_list))

    def __mul__(self, coeff: Union[float, int]) -> SummedFermionicOperator:
        if isinstance(coeff, (float, int)):
            return SummedFermionicOperator(op_list=[(self, float(coeff))])
        raise ClassiqValueError(
            "The coefficient multiplying Fermionic Operator should be of type float"
        )

    __rmul__ = __mul__

    def __add__(
        self, other: Union[SummedFermionicOperator, FermionicOperator]
    ) -> SummedFermionicOperator:
        if isinstance(other, SummedFermionicOperator):
            return SummedFermionicOperator(op_list=[(self, 1.0)] + other.op_list)
        elif isinstance(other, FermionicOperator):
            return SummedFermionicOperator(op_list=[(self, 1.0)] + [(other, 1.0)])
        raise ClassiqValueError(
            "FermionicOperator can be summed together only with type FermionicOperator or SummedFermionicOperator"
        )

    class Config:
        frozen = True

    @staticmethod
    def _to_ladder_op(char: str) -> str:
        return "a" + _SUPERSCRIPT_PLUS if char == "+" else "a"

    @staticmethod
    def _to_subscript(num: int) -> str:
        return "".join(_SUBSCRIPT_UNICODE_CHARS[digit] for digit in str(num))

    def __str__(self) -> str:
        return "".join(
            f"{self._to_ladder_op(char)}{self._to_subscript(index)}"
            for (char, index) in self.op_list
        )

    @property
    def all_indices(self) -> Set[int]:
        return {op[1] for op in self.op_list}
op_list: list pydantic-field required

A list of tuples each containing an index and a character; for example [('+', 0), ('-', 1)].

__str__(self) special

Return str(self).

Source code in classiq/interface/chemistry/fermionic_operator.py
def __str__(self) -> str:
    return "".join(
        f"{self._to_ladder_op(char)}{self._to_subscript(index)}"
        for (char, index) in self.op_list
    )
SummedFermionicOperator (HashablePydanticBaseModel) pydantic-model

Specification of a summed Fermionic operator. Input: List of fermionic operators tuples, The first term in the tuple is the FermionicOperator and the second term is its coefficient. For example: op1 = FermionicOperator(op_list=[('+', 0), ('-', 1)]) op2 = FermionicOperator(op_list=[('-', 0), ('-', 1)]) summed_operator = SummedFermionicOperator(op_list=[(op1, 0.2), (op2, 6.7)])

Source code in classiq/interface/chemistry/fermionic_operator.py
class SummedFermionicOperator(HashablePydanticBaseModel):
    """
    Specification of a summed Fermionic operator.
    Input:
    List of fermionic operators tuples, The first term in the tuple is the FermionicOperator and the second term is its coefficient.
    For example:
    op1 = FermionicOperator(op_list=[('+', 0), ('-', 1)])
    op2 = FermionicOperator(op_list=[('-', 0), ('-', 1)])
    summed_operator = SummedFermionicOperator(op_list=[(op1, 0.2), (op2, 6.7)])
    """

    op_list: list = pydantic.Field(
        description="A list of tuples each containing a FermionicOperator and a coefficient.",
    )

    class Config:
        frozen = True

    @staticmethod
    def _validate_single_op(op: tuple) -> FermionicOperatorTuple:
        # is it tuple - if not, convert to tuple
        if not isinstance(op, tuple):
            try:  # type: ignore[unreachable] # it is reachable...
                op = tuple(op)
            except Exception as exc:
                raise ClassiqValueError("Operator should be a tuple.") from exc
        if len(op) != 2:
            raise ClassiqValueError("Operator tuple should be of length two.")

        # is it FermionicOperator - if not, convert to FermionicOperator
        if not isinstance(op[0], FermionicOperator):
            try:
                op = (FermionicOperator(**op[0]), op[1])
            except Exception as exc:
                raise ClassiqValueError(
                    "The first term in the operator tuple should be an instance of the FermionicOperator class"
                ) from exc

        if not isinstance(op[1], float):
            raise ClassiqValueError(
                "The second term in the operator tuple indicates its coefficient and should be of type float"
            )

        return op  # type: ignore[return-value] # mypy thinks that it is `Tuple[Any, ...]`, though the asserts here tell otherwise..

    @pydantic.validator("op_list")
    def _validate_op_list(cls, op_list: list) -> list:
        return list(map(cls._validate_single_op, op_list))

    def __add__(
        self, other: Union[SummedFermionicOperator, FermionicOperator]
    ) -> SummedFermionicOperator:
        if isinstance(other, SummedFermionicOperator):
            return SummedFermionicOperator(op_list=self.op_list + other.op_list)
        elif isinstance(other, FermionicOperator):
            return SummedFermionicOperator(op_list=self.op_list + [(other, 1.0)])
        raise ClassiqValueError(
            "FermionicOperator can be summed together only with type FermionicOperator or SummedFermionicOperator"
        )

    def is_close(self, other: SummedFermionicOperator) -> bool:
        if not isinstance(other, SummedFermionicOperator):
            return False  # type: ignore[unreachable]

        if len(self.op_list) != len(other.op_list):
            return False

        for (op1, coeff1), (op2, coeff2) in zip(self.op_list, other.op_list):
            if op1 != op2 or not np.isclose(coeff1, coeff2):
                return False

        return True

    @property
    def _all_indices(self) -> Set[int]:
        return set(
            itertools.chain.from_iterable(op.all_indices for op, _ in self.op_list)
        )

    @property
    def num_qubits(self) -> int:
        return len(self._all_indices)

    def __str__(self) -> str:
        return " + \n".join(str(op[1]) + " * " + str(op[0]) for op in self.op_list)
op_list: list pydantic-field required

A list of tuples each containing a FermionicOperator and a coefficient.

__str__(self) special

Return str(self).

Source code in classiq/interface/chemistry/fermionic_operator.py
def __str__(self) -> str:
    return " + \n".join(str(op[1]) + " * " + str(op[0]) for op in self.op_list)

ground_state_problem

GroundStateProblem (HashablePydanticBaseModel) pydantic-model
Source code in classiq/interface/chemistry/ground_state_problem.py
class GroundStateProblem(HashablePydanticBaseModel):
    kind: str

    mapping: FermionMapping = pydantic.Field(
        default=FermionMapping.JORDAN_WIGNER,
        description="Fermionic mapping type",
        title="Fermion Mapping",
    )
    z2_symmetries: bool = pydantic.Field(
        default=False,
        description="whether to perform z2 symmetries reduction",
    )
    num_qubits: Optional[int] = pydantic.Field(default=None)

    @pydantic.validator("z2_symmetries")
    def _validate_z2_symmetries(
        cls, z2_symmetries: bool, values: Dict[str, Any]
    ) -> bool:
        if z2_symmetries and values.get("mapping") == FermionMapping.FAST_BRAVYI_KITAEV:
            raise ClassiqValueError(
                "z2 symmetries reduction can not be used for fast_bravyi_kitaev mapping"
            )
        return z2_symmetries

    class Config:
        frozen = True
mapping: FermionMapping pydantic-field

Fermionic mapping type

z2_symmetries: bool pydantic-field

whether to perform z2 symmetries reduction

HamiltonianProblem (GroundStateProblem) pydantic-model
Source code in classiq/interface/chemistry/ground_state_problem.py
class HamiltonianProblem(GroundStateProblem):
    kind: Literal["hamiltonian"] = pydantic.Field(default="hamiltonian")

    hamiltonian: SummedFermionicOperator = pydantic.Field(
        description="Hamiltonian as a fermionic operator"
    )
    num_particles: List[pydantic.PositiveInt] = pydantic.Field(
        description="Tuple containing the numbers of alpha particles and beta particles"
    )

    @pydantic.validator("num_particles")
    def _validate_num_particles(cls, num_particles: List[int]) -> List[int]:
        assert isinstance(num_particles, list)
        assert len(num_particles) == 2

        # This probably will never happen, since pydantic automatically converts
        #   floats to ints
        assert isinstance(num_particles[0], int)
        assert num_particles[0] >= 1

        assert isinstance(num_particles[1], int)
        assert num_particles[1] >= 1

        return num_particles
hamiltonian: SummedFermionicOperator pydantic-field required

Hamiltonian as a fermionic operator

num_particles: List[pydantic.types.PositiveInt] pydantic-field required

Tuple containing the numbers of alpha particles and beta particles

MoleculeProblem (GroundStateProblem) pydantic-model
Source code in classiq/interface/chemistry/ground_state_problem.py
class MoleculeProblem(GroundStateProblem):
    kind: Literal["molecule"] = pydantic.Field(default="molecule")

    molecule: Molecule
    basis: str = pydantic.Field(default="sto3g", description="Molecular basis set")
    freeze_core: bool = pydantic.Field(default=False)
    remove_orbitals: List[int] = pydantic.Field(
        default_factory=list, description="list of orbitals to remove"
    )
basis: str pydantic-field

Molecular basis set

remove_orbitals: List[int] pydantic-field

list of orbitals to remove

molecule

Atom (HashablePydanticBaseModel) pydantic-model
Source code in classiq/interface/chemistry/molecule.py
class Atom(HashablePydanticBaseModel):
    symbol: Literal[tuple(ELEMENTS)] = pydantic.Field(description="The atom symbol")  # type: ignore[valid-type]
    x: float = pydantic.Field(description="The x coordinate of the atom")
    y: float = pydantic.Field(description="The y coordinate of the atom")
    z: float = pydantic.Field(description="The z coordinate of the atom")
symbol: Literal['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', 'Rf', 'Db', 'Sg', 'Bh', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Nh', 'Fl', 'Mc', 'Lv', 'Ts', 'Og'] pydantic-field required

The atom symbol

x: float pydantic-field required

The x coordinate of the atom

y: float pydantic-field required

The y coordinate of the atom

z: float pydantic-field required

The z coordinate of the atom

Molecule (HashablePydanticBaseModel) pydantic-model
Source code in classiq/interface/chemistry/molecule.py
class Molecule(HashablePydanticBaseModel):
    atoms: List[Atom] = pydantic.Field(
        description="A list of atoms each containing the atoms symbol and  its (x,y,z) location",
        min_items=1,
    )
    spin: pydantic.NonNegativeInt = pydantic.Field(
        default=1, description="spin of the molecule"
    )
    charge: pydantic.NonNegativeInt = pydantic.Field(
        default=0, description="charge of the molecule"
    )

    @property
    def atoms_type(self) -> List[AtomType]:
        return [(atom.symbol, [atom.x, atom.y, atom.z]) for atom in self.atoms]

    @pydantic.validator("atoms", each_item=True, pre=True)
    def _validate_atoms(cls, atom: Union[AtomType, Atom]) -> Atom:
        if isinstance(atom, (list, tuple)):
            return cls._validate_old_atoms_type(atom)
        return atom

    @staticmethod
    def _validate_old_atoms_type(atom: AtomType) -> Atom:
        if len(atom) != 2:
            raise ClassiqValueError(
                "each atom should be a list of two entries: 1) name pf the elemnt (str) 2) list of its (x,y,z) location"
            )
        if not isinstance(atom[0], str):
            raise ClassiqValueError(
                f"atom name should be a string. unknown element: {atom[0]}."
            )
        if len(atom[1]) != 3:
            raise ClassiqValueError(
                f"location of the atom is of length three, representing the (x,y,z) coordinates of the atom, error value: {atom[1]}"
            )
        for idx in atom[1]:
            if not isinstance(idx, (float, int)):
                raise ClassiqValueError(
                    f"coordinates of the atom should be of type float. error value: {idx}"
                )
        symbol, coordinate = atom

        return Atom(symbol=symbol, x=coordinate[0], y=coordinate[1], z=coordinate[2])

    class Config:
        frozen = True
atoms: ConstrainedListValue pydantic-field required

A list of atoms each containing the atoms symbol and its (x,y,z) location

charge: NonNegativeInt pydantic-field

charge of the molecule

spin: NonNegativeInt pydantic-field

spin of the molecule

operator

PauliOperator (HashablePydanticBaseModel, VersionedModel) pydantic-model

Specification of a Pauli sum operator.

Source code in classiq/interface/chemistry/operator.py
class PauliOperator(HashablePydanticBaseModel, VersionedModel):
    """
    Specification of a Pauli sum operator.
    """

    pauli_list: PydanticPauliList = pydantic.Field(
        description="A list of tuples each containing a pauli string comprised of I,X,Y,Z characters and a complex coefficient; for example [('IZ', 0.1), ('XY', 0.2)].",
    )
    is_hermitian: bool = pydantic.Field(default=False)
    has_complex_coefficients: bool = pydantic.Field(default=True)

    def show(self) -> str:
        if self.is_hermitian:
            # If the operator is hermitian then the coefficients must be numeric
            return "\n".join(
                f"{summand[1].real:+.3f} * {summand[0]}" for summand in self.pauli_list  # type: ignore[union-attr]
            )
        return "\n".join(
            f"+({summand[1]:+.3f}) * {summand[0]}" for summand in self.pauli_list
        )

    @pydantic.validator("pauli_list", each_item=True, pre=True)
    def _validate_pauli_monomials(
        cls, monomial: Tuple[PydanticPauliMonomialStr, ParameterComplexType]
    ) -> Tuple[PydanticPauliMonomialStr, ParameterComplexType]:
        _PauliMonomialLengthValidator(  # type: ignore[call-arg]
            monomial=monomial
        )  # Validate the length of the monomial.
        coeff = cls._validate_monomial_coefficient(monomial[1])
        parsed_monomial = _PauliMonomialParser(string=monomial[0], coeff=coeff)  # type: ignore[call-arg]
        return (parsed_monomial.string, parsed_monomial.coeff)

    @staticmethod
    def _validate_monomial_coefficient(
        coeff: Union[sympy.Expr, ParameterComplexType]
    ) -> ParameterComplexType:
        if isinstance(coeff, str):
            validate_expression_str(coeff)
        elif isinstance(coeff, sympy.Expr):
            coeff = str(coeff)
        return coeff

    @pydantic.validator("pauli_list")
    def _validate_pauli_list(cls, pauli_list: PydanticPauliList) -> PydanticPauliList:
        if not all_equal(len(summand[0]) for summand in pauli_list):
            raise ClassiqValueError("Pauli strings have incompatible lengths.")
        return pauli_list

    @pydantic.root_validator
    def _validate_hermitianity(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        pauli_list = values.get("pauli_list", [])
        if all(isinstance(summand[1], complex) for summand in pauli_list):
            values["is_hermitian"] = all(
                np.isclose(complex(summand[1]).real, summand[1])
                for summand in pauli_list
            )
        if values.get("is_hermitian", False):
            values["has_complex_coefficients"] = False
            values["pauli_list"] = [
                (summand[0], complex(summand[1].real)) for summand in pauli_list
            ]
        else:
            values["has_complex_coefficients"] = not all(
                np.isclose(complex(summand[1]).real, summand[1])
                for summand in pauli_list
                if isinstance(summand[1], complex)
            )
        return values

    def __mul__(self, coefficient: complex) -> "PauliOperator":
        multiplied_ising = [
            (monomial[0], self._multiply_monomial_coefficient(monomial[1], coefficient))
            for monomial in self.pauli_list
        ]
        return self.__class__(pauli_list=multiplied_ising)

    @staticmethod
    def _multiply_monomial_coefficient(
        monomial_coefficient: ParameterComplexType, coefficient: complex
    ) -> ParameterComplexType:
        if isinstance(monomial_coefficient, ParameterType):
            return str(sympy.sympify(monomial_coefficient) * coefficient)
        return monomial_coefficient * coefficient

    @property
    def is_commutative(self) -> bool:
        return all(
            self._is_sub_pauli_commutative(
                [summand[0][qubit_num] for summand in self.pauli_list]
            )
            for qubit_num in range(self.num_qubits)
        )

    @staticmethod
    def _is_sub_pauli_commutative(qubit_pauli_string: Union[List[str], str]) -> bool:
        unique_paulis = set(qubit_pauli_string) - {"I"}
        return len(unique_paulis) <= 1

    @property
    def num_qubits(self) -> int:
        return len(self.pauli_list[0][0])

    def to_matrix(self) -> np.ndarray:
        if not all(isinstance(summand[1], complex) for summand in self.pauli_list):
            raise ClassiqValueError(
                "Supporting only Hamiltonian with numeric coefficients."
            )
        return sum(
            cast(complex, summand[1]) * to_pauli_matrix(summand[0])
            for summand in self.pauli_list
        )  # type: ignore[return-value]

    @staticmethod
    def _extend_pauli_string(
        pauli_string: PydanticPauliMonomialStr, num_extra_qubits: int
    ) -> PydanticPauliMonomialStr:
        return "I" * num_extra_qubits + pauli_string

    def extend(self, num_extra_qubits: int) -> "PauliOperator":
        new_pauli_list = [
            (self._extend_pauli_string(pauli_string, num_extra_qubits), coeff)
            for (pauli_string, coeff) in self.pauli_list
        ]
        return self.copy(update={"pauli_list": new_pauli_list}, deep=True)

    @staticmethod
    def _reorder_pauli_string(
        pauli_string: PydanticPauliMonomialStr,
        order: Collection[int],
        new_num_qubits: int,
    ) -> PydanticPauliMonomialStr:
        reversed_pauli_string = pauli_string[::-1]
        reversed_new_pauli_string = ["I"] * new_num_qubits

        for logical_pos, actual_pos in enumerate(order):
            reversed_new_pauli_string[actual_pos] = reversed_pauli_string[logical_pos]

        return "".join(reversed(reversed_new_pauli_string))

    @staticmethod
    def _validate_reorder(
        order: Collection[int],
        num_qubits: int,
        num_extra_qubits: int,
    ) -> None:
        if num_extra_qubits < 0:
            raise ClassiqValueError("Number of extra qubits cannot be negative")

        if len(order) != num_qubits:
            raise ClassiqValueError("The qubits order doesn't match the Pauli operator")

        if len(order) != len(set(order)):
            raise ClassiqValueError("The qubits order is not one-to-one")

        if not all(pos < num_qubits + num_extra_qubits for pos in order):
            raise ClassiqValueError(
                "The qubits order contains qubits which do no exist"
            )

    @classmethod
    def reorder(
        cls,
        operator: "PauliOperator",
        order: Collection[int],
        num_extra_qubits: int = 0,
    ) -> "PauliOperator":
        cls._validate_reorder(order, operator.num_qubits, num_extra_qubits)

        new_num_qubits = operator.num_qubits + num_extra_qubits
        new_pauli_list = [
            (cls._reorder_pauli_string(pauli_string, order, new_num_qubits), coeff)
            for pauli_string, coeff in operator.pauli_list
        ]
        return cls(pauli_list=new_pauli_list)

    @classmethod
    def from_unzipped_lists(
        cls,
        operators: List[List[Pauli]],
        coefficients: Optional[List[complex]] = None,
    ) -> "PauliOperator":
        if coefficients is None:
            coefficients = [1] * len(operators)

        if len(operators) != len(coefficients):
            raise ClassiqValueError(
                f"The number of coefficients ({len(coefficients)}) must be equal to the number of pauli operators ({len(operators)})"
            )

        return cls(
            pauli_list=[
                (pauli_integers_to_str(op), coeff)
                for op, coeff in zip(operators, coefficients)
            ]
        )

    class Config:
        frozen = True
pauli_list: ConstrainedListValue pydantic-field required

A list of tuples each containing a pauli string comprised of I,X,Y,Z characters and a complex coefficient; for example [('IZ', 0.1), ('XY', 0.2)].

__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

PauliOperatorV1 (HashablePydanticBaseModel) pydantic-model

Specification of a Pauli sum operator.

Source code in classiq/interface/chemistry/operator.py
class PauliOperatorV1(HashablePydanticBaseModel):
    """
    Specification of a Pauli sum operator.
    """

    pauli_list: PydanticPauliList = pydantic.Field(
        description="A list of tuples each containing a pauli string comprised of I,X,Y,Z characters and a complex coefficient; for example [('IZ', 0.1), ('XY', 0.2)].",
    )
    is_hermitian: bool = pydantic.Field(default=False)
    has_complex_coefficients: bool = pydantic.Field(default=True)

    def show(self) -> str:
        if self.is_hermitian:
            # If the operator is hermitian then the coefficients must be numeric
            return "\n".join(
                f"{summand[1].real:+.3f} * {summand[0]}" for summand in self.pauli_list  # type: ignore[union-attr]
            )
        return "\n".join(
            f"+({summand[1]:+.3f}) * {summand[0]}" for summand in self.pauli_list
        )

    @pydantic.validator("pauli_list", each_item=True, pre=True)
    def _validate_pauli_monomials(
        cls, monomial: Tuple[PydanticPauliMonomialStr, ParameterComplexType]
    ) -> Tuple[PydanticPauliMonomialStr, ParameterComplexType]:
        _PauliMonomialLengthValidator(  # type: ignore[call-arg]
            monomial=monomial
        )  # Validate the length of the monomial.
        coeff = cls._validate_monomial_coefficient(monomial[1])
        parsed_monomial = _PauliMonomialParser(string=monomial[0], coeff=coeff)  # type: ignore[call-arg]
        return (parsed_monomial.string, parsed_monomial.coeff)

    @staticmethod
    def _validate_monomial_coefficient(
        coeff: Union[sympy.Expr, ParameterComplexType]
    ) -> ParameterComplexType:
        if isinstance(coeff, str):
            validate_expression_str(coeff)
        elif isinstance(coeff, sympy.Expr):
            coeff = str(coeff)
        return coeff

    @pydantic.validator("pauli_list")
    def _validate_pauli_list(cls, pauli_list: PydanticPauliList) -> PydanticPauliList:
        if not all_equal(len(summand[0]) for summand in pauli_list):
            raise ClassiqValueError("Pauli strings have incompatible lengths.")
        return pauli_list

    @pydantic.root_validator
    def _validate_hermitianity(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        pauli_list = values.get("pauli_list", [])
        if all(isinstance(summand[1], complex) for summand in pauli_list):
            values["is_hermitian"] = all(
                np.isclose(complex(summand[1]).real, summand[1])
                for summand in pauli_list
            )
        if values.get("is_hermitian", False):
            values["has_complex_coefficients"] = False
            values["pauli_list"] = [
                (summand[0], complex(summand[1].real)) for summand in pauli_list
            ]
        else:
            values["has_complex_coefficients"] = not all(
                np.isclose(complex(summand[1]).real, summand[1])
                for summand in pauli_list
                if isinstance(summand[1], complex)
            )
        return values

    def __mul__(self, coefficient: complex) -> "PauliOperatorV1":
        multiplied_ising = [
            (monomial[0], self._multiply_monomial_coefficient(monomial[1], coefficient))
            for monomial in self.pauli_list
        ]
        return self.__class__(pauli_list=multiplied_ising)

    @staticmethod
    def _multiply_monomial_coefficient(
        monomial_coefficient: ParameterComplexType, coefficient: complex
    ) -> ParameterComplexType:
        if isinstance(monomial_coefficient, ParameterType):
            return str(sympy.sympify(monomial_coefficient) * coefficient)
        return monomial_coefficient * coefficient

    @property
    def is_commutative(self) -> bool:
        return all(
            self._is_sub_pauli_commutative(
                [summand[0][qubit_num] for summand in self.pauli_list]
            )
            for qubit_num in range(self.num_qubits)
        )

    @staticmethod
    def _is_sub_pauli_commutative(qubit_pauli_string: Union[List[str], str]) -> bool:
        unique_paulis = set(qubit_pauli_string) - {"I"}
        return len(unique_paulis) <= 1

    @property
    def num_qubits(self) -> int:
        return len(self.pauli_list[0][0])

    def to_matrix(self) -> np.ndarray:
        if not all(isinstance(summand[1], complex) for summand in self.pauli_list):
            raise ClassiqValueError(
                "Supporting only Hamiltonian with numeric coefficients."
            )
        return sum(
            cast(complex, summand[1]) * to_pauli_matrix(summand[0])
            for summand in self.pauli_list
        )  # type: ignore[return-value]

    @staticmethod
    def _extend_pauli_string(
        pauli_string: PydanticPauliMonomialStr, num_extra_qubits: int
    ) -> PydanticPauliMonomialStr:
        return "I" * num_extra_qubits + pauli_string

    def extend(self, num_extra_qubits: int) -> "PauliOperatorV1":
        new_pauli_list = [
            (self._extend_pauli_string(pauli_string, num_extra_qubits), coeff)
            for (pauli_string, coeff) in self.pauli_list
        ]
        return self.copy(update={"pauli_list": new_pauli_list}, deep=True)

    @staticmethod
    def _reorder_pauli_string(
        pauli_string: PydanticPauliMonomialStr,
        order: Collection[int],
        new_num_qubits: int,
    ) -> PydanticPauliMonomialStr:
        reversed_pauli_string = pauli_string[::-1]
        reversed_new_pauli_string = ["I"] * new_num_qubits

        for logical_pos, actual_pos in enumerate(order):
            reversed_new_pauli_string[actual_pos] = reversed_pauli_string[logical_pos]

        return "".join(reversed(reversed_new_pauli_string))

    @staticmethod
    def _validate_reorder(
        order: Collection[int],
        num_qubits: int,
        num_extra_qubits: int,
    ) -> None:
        if num_extra_qubits < 0:
            raise ClassiqValueError("Number of extra qubits cannot be negative")

        if len(order) != num_qubits:
            raise ClassiqValueError("The qubits order doesn't match the Pauli operator")

        if len(order) != len(set(order)):
            raise ClassiqValueError("The qubits order is not one-to-one")

        if not all(pos < num_qubits + num_extra_qubits for pos in order):
            raise ClassiqValueError(
                "The qubits order contains qubits which do no exist"
            )

    @classmethod
    def reorder(
        cls,
        operator: "PauliOperatorV1",
        order: Collection[int],
        num_extra_qubits: int = 0,
    ) -> "PauliOperatorV1":
        cls._validate_reorder(order, operator.num_qubits, num_extra_qubits)

        new_num_qubits = operator.num_qubits + num_extra_qubits
        new_pauli_list = [
            (cls._reorder_pauli_string(pauli_string, order, new_num_qubits), coeff)
            for pauli_string, coeff in operator.pauli_list
        ]
        return cls(pauli_list=new_pauli_list)

    @classmethod
    def from_unzipped_lists(
        cls,
        operators: List[List[Pauli]],
        coefficients: Optional[List[complex]] = None,
    ) -> "PauliOperatorV1":
        if coefficients is None:
            coefficients = [1] * len(operators)

        if len(operators) != len(coefficients):
            raise ClassiqValueError(
                f"The number of coefficients ({len(coefficients)}) must be equal to the number of pauli operators ({len(operators)})"
            )

        return cls(
            pauli_list=[
                (pauli_integers_to_str(op), coeff)
                for op, coeff in zip(operators, coefficients)
            ]
        )

    class Config:
        frozen = True
pauli_list: ConstrainedListValue pydantic-field required

A list of tuples each containing a pauli string comprised of I,X,Y,Z characters and a complex coefficient; for example [('IZ', 0.1), ('XY', 0.2)].

PauliOperators (VersionedModel) pydantic-model
Source code in classiq/interface/chemistry/operator.py
class PauliOperators(VersionedModel):
    operators: List[PauliOperator]
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

combinatorial_optimization special

mht_qaoa_input

MhtQaoaInput (BaseModel) pydantic-model
Source code in classiq/interface/combinatorial_optimization/mht_qaoa_input.py
class MhtQaoaInput(BaseModel):
    reps: pydantic.PositiveInt = pydantic.Field(
        default=3, description="Number of QAOA layers."
    )
    plot_list: List[PlotData] = pydantic.Field(
        description="The list of (x,y,t) plots of the MHT problem."
    )
    misdetection_maximum_time_steps: pydantic.NonNegativeInt = pydantic.Field(
        default=0,
        description="The maximum number of time steps a target might be misdetected.",
    )
    penalty_energy: float = pydantic.Field(
        default=2,
        description="Penalty energy for invalid solutions. The value affects "
        "the converges rate. Small positive values are preferred",
    )
    three_local_coeff: float = pydantic.Field(
        default=0,
        description="Coefficient for the 3-local terms in the Hamiltonian. It is related to the angular acceleration.",
    )
    one_local_coeff: float = pydantic.Field(
        default=0, description="Coefficient for the 1-local terms in the Hamiltonian."
    )
    is_penalty: bool = pydantic.Field(
        default=True, description="Build Pubo using penalty terms"
    )
    max_velocity: float = pydantic.Field(
        default=0, description="Max allowed velocity for a segment"
    )

    def is_valid_cost(self, cost: float) -> bool:
        return True

    @pydantic.validator("plot_list")
    def round_plot_list_times_and_validate(
        cls, plot_list: List[PlotData]
    ) -> List[PlotData]:
        MhtQaoaInput._check_all_ids_are_distinct(plot_list)
        MhtQaoaInput._round_to_tolerance_decimals(plot_list)

        time_stamps = sorted({plot.t for plot in plot_list})
        time_diff_set = {
            np.round(time_stamps[i] - time_stamps[i - 1], decimals=_TOLERANCE_DECIMALS)
            for i in range(1, len(time_stamps))
        }

        if len(time_diff_set) != 1:
            raise ClassiqValueError(
                "The time difference between each time stamp is not equal"
            )

        return plot_list

    @staticmethod
    def _round_to_tolerance_decimals(plot_list: List[PlotData]) -> None:
        for plot in plot_list:
            plot.t = np.round(plot.t, decimals=_TOLERANCE_DECIMALS)

    @staticmethod
    def _check_all_ids_are_distinct(plot_list: List[PlotData]) -> None:
        if not more_itertools.all_unique(plot.plot_id for plot in plot_list):
            raise ClassiqValueError("Plot IDs should be unique.")
is_penalty: bool pydantic-field

Build Pubo using penalty terms

max_velocity: float pydantic-field

Max allowed velocity for a segment

misdetection_maximum_time_steps: NonNegativeInt pydantic-field

The maximum number of time steps a target might be misdetected.

one_local_coeff: float pydantic-field

Coefficient for the 1-local terms in the Hamiltonian.

penalty_energy: float pydantic-field

Penalty energy for invalid solutions. The value affects the converges rate. Small positive values are preferred

plot_list: List[classiq.interface.combinatorial_optimization.mht_qaoa_input.PlotData] pydantic-field required

The list of (x,y,t) plots of the MHT problem.

reps: PositiveInt pydantic-field

Number of QAOA layers.

three_local_coeff: float pydantic-field

Coefficient for the 3-local terms in the Hamiltonian. It is related to the angular acceleration.

PlotData (BaseModel) pydantic-model
Source code in classiq/interface/combinatorial_optimization/mht_qaoa_input.py
class PlotData(BaseModel):
    # We are currently ignoring units. This might need to be handled in the future
    x: float = pydantic.Field(description="The X coordinate of this plot")
    y: float = pydantic.Field(description="The Y coordinate of this plot")
    t: float = pydantic.Field(description="The time stamp of this plot")
    plot_id: pydantic.NonNegativeInt = pydantic.Field(
        description="The plot ID of this plot"
    )
plot_id: NonNegativeInt pydantic-field required

The plot ID of this plot

t: float pydantic-field required

The time stamp of this plot

x: float pydantic-field required

The X coordinate of this plot

y: float pydantic-field required

The Y coordinate of this plot

optimization_problem

MaxCutProblem (BaseModel) pydantic-model
Source code in classiq/interface/combinatorial_optimization/optimization_problem.py
class MaxCutProblem(BaseModel):
    qaoa_reps: pydantic.PositiveInt = pydantic.Field(
        default=1, description="Number of layers in qaoa ansatz."
    )
    optimizer_preferences: CombinatorialOptimizer = pydantic.Field(
        default_factory=CombinatorialOptimizer,
        description="preferences for the VQE execution",
    )
    serialized_graph: Dict[str, Any]
optimizer_preferences: CombinatorialOptimizer pydantic-field

preferences for the VQE execution

qaoa_reps: PositiveInt pydantic-field

Number of layers in qaoa ansatz.

result

AnglesResult (VersionedModel) pydantic-model
Source code in classiq/interface/combinatorial_optimization/result.py
class AnglesResult(VersionedModel):
    initial_point: List[float]
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

PyomoObjectResult (VersionedModel) pydantic-model
Source code in classiq/interface/combinatorial_optimization/result.py
class PyomoObjectResult(VersionedModel):
    details: str
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

execution special

result

ResourceEstimatorResult (VersionedModel) pydantic-model
Source code in classiq/interface/execution/result.py
class ResourceEstimatorResult(VersionedModel):
    report_json: str
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

executor special

aws_execution_cost

ExecutionCostForTimePeriod (BaseModel) pydantic-model
Source code in classiq/interface/executor/aws_execution_cost.py
class ExecutionCostForTimePeriod(pydantic.BaseModel):
    start: date = pydantic.Field(
        description="The beginning of the time period for tasks usage and cost ("
        "inclusive).",
    )
    end: date = pydantic.Field(
        description="The end of the time period for tasks usage and cost (exclusive).",
    )
    granularity: Granularity = pydantic.Field(
        description="Either MONTHLY or DAILY, or HOURLY.", default=Granularity.daily
    )
    cost_scope: CostScope = pydantic.Field(
        description="Either user or organization", default=CostScope.user
    )

    class Config:
        json_encoders = {date: lambda v: v.strftime("%Y-%m-%d")}

    @validator("end")
    def date_order(cls, v: date, values: Dict[str, Any], **kwargs: Any) -> date:
        if "start" in values and v <= values["start"]:
            raise ClassiqValueError('"end" date should be after "start" date')
        return v
cost_scope: CostScope pydantic-field

Either user or organization

end: date pydantic-field required

The end of the time period for tasks usage and cost (exclusive).

granularity: Granularity pydantic-field

Either MONTHLY or DAILY, or HOURLY.

start: date pydantic-field required

The beginning of the time period for tasks usage and cost (inclusive).

__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

estimation

OperatorsEstimation (BaseModel) pydantic-model

Estimate the expectation value of a list of Pauli operators on a quantum state given by a quantum program.

Source code in classiq/interface/executor/estimation.py
class OperatorsEstimation(pydantic.BaseModel):
    """
    Estimate the expectation value of a list of Pauli operators on a quantum state given
    by a quantum program.
    """

    quantum_program: QuantumCode
    operators: PauliOperators

execution_preferences

ExecutionPreferences (BaseModel) pydantic-model
Source code in classiq/interface/executor/execution_preferences.py
class ExecutionPreferences(pydantic.BaseModel):
    timeout_sec: Optional[pydantic.PositiveInt] = pydantic.Field(
        default=None,
        description="If set, limits the execution runtime. Value is in seconds. "
        "Not supported on all platforms.",
    )
    optimizer_preferences: Optional[OptimizerPreferences] = pydantic.Field(
        default_factory=None,
        description="Settings related to VQE execution.",
    )
    noise_properties: Optional[NoiseProperties] = pydantic.Field(
        default=None, description="Properties of the noise in the circuit"
    )
    random_seed: int = pydantic.Field(
        default=None,
        description="The random seed used for the execution",
    )
    backend_preferences: BackendPreferencesTypes = backend_preferences_field(
        backend_name=ClassiqSimulatorBackendNames.SIMULATOR
    )
    num_shots: Optional[pydantic.PositiveInt] = pydantic.Field(default=None)
    transpile_to_hardware: TranspilationOption = pydantic.Field(
        default=TranspilationOption.DECOMPOSE,
        description="Transpile the circuit to the hardware basis gates before execution",
        title="Transpilation Option",
    )
    job_name: Optional[str] = pydantic.Field(
        min_length=1,
        description="The job name",
    )

    def __init__(self, **kwargs: Any) -> None:
        super().__init__(**kwargs)

    @pydantic.validator("num_shots", always=True)
    def validate_num_shots(
        cls, original_num_shots: Optional[pydantic.PositiveInt], values: Dict[str, Any]
    ) -> Optional[pydantic.PositiveInt]:
        return _choose_original_or_optimizer_attribute(
            original_num_shots, "num_shots", None, values
        )

    @pydantic.validator("backend_preferences", always=True)
    def validate_timeout_for_aws(
        cls, backend_preferences: BackendPreferencesTypes, values: Dict[str, Any]
    ) -> BackendPreferencesTypes:
        timeout = values.get("timeout_sec", None)
        if (
            not isinstance(backend_preferences, AwsBackendPreferences)
            or timeout is None
        ):
            return backend_preferences
        if (
            timeout != backend_preferences.job_timeout
            and backend_preferences.job_timeout != AWS_DEFAULT_JOB_TIMEOUT_SECONDS
        ):
            raise ClassiqValueError(DIFFERENT_TIMEOUT_MSG)
        if timeout > MAX_EXECUTION_TIMEOUT_SECONDS:
            raise ClassiqValueError(TIMEOUT_LARGE_FOR_AWS_MSG)

        backend_preferences.job_timeout = timeout
        return backend_preferences

    @pydantic.validator("random_seed", always=True)
    def validate_random_seed(
        cls, original_random_seed: Optional[int], values: Dict[str, Any]
    ) -> int:
        return _choose_original_or_optimizer_attribute(
            original_random_seed, "random_seed", create_random_seed(), values
        )
backend_preferences: Union[classiq.interface.backend.backend_preferences.AzureBackendPreferences, classiq.interface.backend.backend_preferences.ClassiqBackendPreferences, classiq.interface.backend.backend_preferences.IBMBackendPreferences, classiq.interface.backend.backend_preferences.AwsBackendPreferences, classiq.interface.backend.backend_preferences.IonqBackendPreferences, classiq.interface.backend.backend_preferences.GCPBackendPreferences, classiq.interface.backend.backend_preferences.AliceBobBackendPreferences, classiq.interface.backend.backend_preferences.OQCBackendPreferences] pydantic-field

Preferences for the requested backend to run the quantum circuit.

job_name: ConstrainedStrValue pydantic-field

The job name

noise_properties: NoiseProperties pydantic-field

Properties of the noise in the circuit

optimizer_preferences: OptimizerPreferences pydantic-field

Settings related to VQE execution.

random_seed: int pydantic-field

The random seed used for the execution

timeout_sec: PositiveInt pydantic-field

If set, limits the execution runtime. Value is in seconds. Not supported on all platforms.

transpile_to_hardware: TranspilationOption pydantic-field

Transpile the circuit to the hardware basis gates before execution

execution_request

ExecutionJobDetails (VersionedModel) pydantic-model
Source code in classiq/interface/executor/execution_request.py
class ExecutionJobDetails(VersionedModel):
    id: str

    name: Optional[str]
    start_time: datetime
    end_time: Optional[datetime]

    provider: Optional[str]
    backend_name: Optional[str]

    status: JobStatus

    num_shots: Optional[int]
    program_id: Optional[str]

    error: Optional[str]
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

ExecutionJobsQueryResults (VersionedModel) pydantic-model
Source code in classiq/interface/executor/execution_request.py
class ExecutionJobsQueryResults(VersionedModel):
    results: List[ExecutionJobDetails]
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

ExecutionRequest (BaseModel) pydantic-model
Source code in classiq/interface/executor/execution_request.py
class ExecutionRequest(BaseModel, json_encoders=CUSTOM_ENCODERS):
    execution_payload: ExecutionPayloads
    preferences: ExecutionPreferences = pydantic.Field(
        default_factory=ExecutionPreferences,
        description="preferences for the execution",
    )
preferences: ExecutionPreferences pydantic-field

preferences for the execution

__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

QuantumProgramExecution (QuantumProgram) pydantic-model
Source code in classiq/interface/executor/execution_request.py
class QuantumProgramExecution(QuantumProgram):
    execution_type: Literal["quantum_program2"] = "quantum_program2"
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

QuantumProgramExecutionRequest (ExecutionRequest) pydantic-model
Source code in classiq/interface/executor/execution_request.py
class QuantumProgramExecutionRequest(ExecutionRequest):
    execution_payload: QuantumCodeExecution
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

execution_result

ExecuteGeneratedCircuitResults (VersionedModel) pydantic-model
Source code in classiq/interface/executor/execution_result.py
class ExecuteGeneratedCircuitResults(VersionedModel):
    results: ResultsCollection
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

iqae_result

IQAEResult (VersionedModel, QmodPyObject) pydantic-model
Source code in classiq/interface/executor/iqae_result.py
class IQAEResult(VersionedModel, QmodPyObject):
    estimation: float
    confidence_interval: Tuple[float, float]
    iterations_data: List[IQAEIterationData]
    warnings: List[str]
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

optimizer_preferences

CombinatorialOptimizer (OptimizerPreferences) pydantic-model
Source code in classiq/interface/executor/optimizer_preferences.py
class CombinatorialOptimizer(OptimizerPreferences):
    cost_type: CostType = pydantic.Field(
        default=CostType.CVAR,
        description="Summarizing method of the measured bit strings",
    )
    alpha_cvar: Optional[PydanticAlphaParamCVAR] = pydantic.Field(
        default=None, description="Parameter for the CVAR summarizing method"
    )
    is_maximization: bool = pydantic.Field(
        default=False,
        description="Whether the optimization goal is to maximize",
    )
    should_check_valid_solutions: bool = pydantic.Field(
        default=False,
        description="Whether to check if all the solutions satisfy the constraints",
    )

    @pydantic.validator("alpha_cvar", pre=True, always=True)
    def check_alpha_cvar(
        cls, alpha_cvar: Optional[PydanticAlphaParamCVAR], values: Dict[str, Any]
    ) -> Optional[PydanticAlphaParamCVAR]:
        cost_type = values.get("cost_type")
        if alpha_cvar is not None and cost_type != CostType.CVAR:
            raise ClassiqValueError("Use CVAR params only for CostType.CVAR.")

        if alpha_cvar is None and cost_type == CostType.CVAR:
            alpha_cvar = PydanticAlphaParamCVAR(0.2)

        return alpha_cvar
alpha_cvar: PydanticAlphaParamCVAR pydantic-field

Parameter for the CVAR summarizing method

cost_type: CostType pydantic-field

Summarizing method of the measured bit strings

is_maximization: bool pydantic-field

Whether the optimization goal is to maximize

should_check_valid_solutions: bool pydantic-field

Whether to check if all the solutions satisfy the constraints

OptimizerPreferences (BaseModel) pydantic-model
Source code in classiq/interface/executor/optimizer_preferences.py
class OptimizerPreferences(BaseModel):
    name: OptimizerType = pydantic.Field(
        default=OptimizerType.COBYLA, description="Classical optimization algorithm."
    )
    num_shots: Optional[pydantic.PositiveInt] = pydantic.Field(
        default=None,
        description="Number of repetitions of the quantum ansatz.",
    )
    max_iteration: pydantic.PositiveInt = pydantic.Field(
        default=100, description="Maximal number of optimizer iterations"
    )
    tolerance: Optional[pydantic.PositiveFloat] = pydantic.Field(
        default=None, description="Final accuracy in the optimization"
    )
    step_size: Optional[pydantic.PositiveFloat] = pydantic.Field(
        default=None,
        description="step size for numerically " "calculating the gradient",
    )
    random_seed: Optional[int] = pydantic.Field(
        default=None,
        description="The random seed used for the generation",
    )
    initial_point: Optional[List[float]] = pydantic.Field(
        default=None,
        description="Initial values for the ansatz parameters",
    )
    skip_compute_variance: bool = pydantic.Field(
        default=False,
        description="If True, the optimizer will not compute the variance of the ansatz.",
    )

    @pydantic.validator("tolerance", pre=True, always=True)
    def check_tolerance(
        cls, tolerance: Optional[pydantic.PositiveFloat], values: Dict[str, Any]
    ) -> Optional[pydantic.PositiveFloat]:
        optimizer_type = values.get("type")
        if tolerance is not None and optimizer_type == OptimizerType.SPSA:
            raise ClassiqValueError("No tolerance param for SPSA optimizer")

        if tolerance is None and optimizer_type != OptimizerType.SPSA:
            tolerance = pydantic.PositiveFloat(0.001)

        return tolerance

    @pydantic.validator("step_size", pre=True, always=True)
    def check_step_size(
        cls, step_size: Optional[pydantic.PositiveFloat], values: Dict[str, Any]
    ) -> Optional[pydantic.PositiveFloat]:
        optimizer_type = values.get("name")
        if step_size is not None and optimizer_type not in (
            OptimizerType.L_BFGS_B,
            OptimizerType.ADAM,
        ):
            raise ClassiqValueError(
                "Use step_size only for L_BFGS_B or ADAM optimizers."
            )

        if step_size is None and optimizer_type in (
            OptimizerType.L_BFGS_B,
            OptimizerType.ADAM,
        ):
            step_size = pydantic.PositiveFloat(0.05)

        return step_size
initial_point: List[float] pydantic-field

Initial values for the ansatz parameters

max_iteration: PositiveInt pydantic-field

Maximal number of optimizer iterations

name: OptimizerType pydantic-field

Classical optimization algorithm.

num_shots: PositiveInt pydantic-field

Number of repetitions of the quantum ansatz.

random_seed: int pydantic-field

The random seed used for the generation

skip_compute_variance: bool pydantic-field

If True, the optimizer will not compute the variance of the ansatz.

step_size: PositiveFloat pydantic-field

step size for numerically calculating the gradient

tolerance: PositiveFloat pydantic-field

Final accuracy in the optimization

quantum_code

QuantumBaseCode (BaseModel) pydantic-model
Source code in classiq/interface/executor/quantum_code.py
class QuantumBaseCode(BaseModel):
    syntax: QuantumInstructionSet = pydantic.Field(
        default=QuantumInstructionSet.QASM, description="The syntax of the program."
    )
    code: CodeType = pydantic.Field(
        ..., description="The textual representation of the program"
    )

    @pydantic.validator("code")
    def load_quantum_program(
        cls, code: Union[CodeType, IonqQuantumCircuit], values: Dict[str, Any]
    ) -> CodeType:
        syntax = values.get("syntax")
        if isinstance(code, IonqQuantumCircuit):
            if syntax != QuantumInstructionSet.IONQ:
                raise ClassiqValueError(
                    f"Invalid code type {type(code)} for syntax: {syntax}"
                )
            return code.json()

        return code
code: str pydantic-field required

The textual representation of the program

syntax: QuantumInstructionSet pydantic-field

The syntax of the program.

QuantumCode (QuantumBaseCode) pydantic-model
Source code in classiq/interface/executor/quantum_code.py
class QuantumCode(QuantumBaseCode):
    arguments: MultipleArguments = pydantic.Field(
        default=(),
        description="The parameters dictionary for a parametrized quantum program.",
    )
    output_qubits_map: OutputQubitsMap = pydantic.Field(
        default_factory=dict,
        description="The map of outputs to their qubits in the circuit.",
    )
    registers_initialization: Optional[RegistersInitialization] = pydantic.Field(
        default_factory=None,
        description="Initial conditions for the different registers in the circuit.",
    )
    synthesis_execution_data: Optional[ExecutionData] = pydantic.Field(default=None)
    synthesis_execution_arguments: Arguments = pydantic.Field(default_factory=dict)

    class Config:
        validate_assignment = True

    @pydantic.validator("arguments")
    def validate_arguments(
        cls, arguments: MultipleArguments, values: Dict[str, Any]
    ) -> MultipleArguments:
        if arguments and values.get("syntax") not in (
            QuantumInstructionSet.QSHARP,
            QuantumInstructionSet.QASM,
        ):
            raise ClassiqValueError("Only QASM or Q# programs support arguments")

        if values.get("syntax") == QuantumInstructionSet.QSHARP and len(arguments) > 1:
            raise ClassiqValueError(
                f"Q# programs supports only one group of arguments. {len(arguments)} given"
            )

        return arguments

    @pydantic.validator("synthesis_execution_data")
    def validate_synthesis_execution_data(
        cls,
        synthesis_execution_data: Optional[ExecutionData],
        values: Dict[str, Any],
    ) -> Optional[ExecutionData]:
        if (
            synthesis_execution_data is not None
            and values.get("syntax") is not QuantumInstructionSet.QASM
        ):
            raise ClassiqValueError("Only QASM supports the requested configuration")

        return synthesis_execution_data

    @staticmethod
    def from_file(
        file_path: Union[str, Path],
        syntax: Optional[Union[str, QuantumInstructionSet]] = None,
        arguments: MultipleArguments = (),
    ) -> QuantumCode:
        path = Path(file_path)
        code = path.read_text()
        if syntax is None:
            syntax = QuantumInstructionSet.from_suffix(path.suffix.lstrip("."))
        return QuantumCode(syntax=syntax, code=code, arguments=arguments)
arguments: Tuple[Dict[classiq.interface.backend.pydantic_backend.ConstrainedStrValue, Any], ...] pydantic-field

The parameters dictionary for a parametrized quantum program.

output_qubits_map: Dict[str, Tuple[int, ...]] pydantic-field

The map of outputs to their qubits in the circuit.

registers_initialization: Dict[str, classiq.interface.executor.register_initialization.RegisterInitialization] pydantic-field

Initial conditions for the different registers in the circuit.

result

EstimationResult (BaseModel, QmodPyObject) pydantic-model
Source code in classiq/interface/executor/result.py
class EstimationResult(BaseModel, QmodPyObject):
    value: Complex = pydantic.Field(..., description="Estimation for the operator")
    variance: Complex = pydantic.Field(..., description="Variance of the estimation")
    metadata: EstimationMetadata = pydantic.Field(
        ..., description="Metadata for the estimation"
    )
metadata: EstimationMetadata pydantic-field required

Metadata for the estimation

value: Complex pydantic-field required

Estimation for the operator

variance: Complex pydantic-field required

Variance of the estimation

EstimationResults (VersionedModel) pydantic-model
Source code in classiq/interface/executor/result.py
class EstimationResults(VersionedModel):
    results: List[EstimationResult]

    def __len__(self) -> int:
        return len(self.results)

    def __iter__(self) -> Iterator[EstimationResult]:  # type: ignore[override]
        # TODO This is a bug waiting to happen. We change the meaning of
        # __iter__ in a derived class.
        return iter(self.results)

    def __getitem__(self, index: int) -> EstimationResult:
        return self.results[index]
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

ExecutionDetails (BaseModel, QmodPyObject) pydantic-model
Source code in classiq/interface/executor/result.py
class ExecutionDetails(BaseModel, QmodPyObject):
    vendor_format_result: Dict[str, Any] = pydantic.Field(
        ..., description="Result in proprietary vendor format"
    )
    counts: Counts = pydantic.Field(
        default_factory=dict, description="Number of counts per state"
    )
    counts_lsb_right: bool = pydantic.Field(
        True,
        description="Is the qubit order of counts field such that the LSB is right?",
    )
    parsed_states: ParsedStates = pydantic.Field(
        default_factory=dict,
        description="A mapping between the raw states of counts (bitstrings) to their parsed states (registers' values)",
    )
    histogram: Optional[Dict[State, pydantic.NonNegativeFloat]] = pydantic.Field(
        None,
        description="Histogram of probability per state (an alternative to counts)",
    )
    output_qubits_map: OutputQubitsMap = pydantic.Field(
        default_factory=dict,
        description="The map of outputs (measured registers) to their qubits in the circuit.",
    )
    state_vector: StateVector = pydantic.Field(
        default=None,
        description="The state vector when executed on a simulator, with LSB right qubit order",
    )
    parsed_state_vector_states: ParsedStates = pydantic.Field(
        default=None,
        description="A mapping between the raw states of the state vector (bitstrings) to their parsed states (registers' values)",
    )
    physical_qubits_map: Optional[OutputQubitsMap] = pydantic.Field(
        default=None,
        description="The map of all registers (also non measured) to their qubits in the circuit. Used for state_vector which represent also the non-measured qubits.",
    )
    num_shots: Optional[pydantic.NonNegativeInt] = pydantic.Field(
        default=None, description="The total number of shots the circuit was executed"
    )

    @pydantic.validator("counts", pre=True)
    def _clean_spaces_from_counts_keys(cls, v: Counts) -> Counts:
        if not v or " " not in list(v.keys())[0]:
            return v
        return {state.replace(" ", ""): v[state] for state in v}

    @pydantic.validator("num_shots", always=True)
    def _validate_num_shots(
        cls, num_shots: Optional[int], values: Dict[str, Any]
    ) -> Optional[int]:
        if num_shots is not None:
            return num_shots
        counts = values.get("counts")
        if not counts:
            return None
        return sum(shots for _, shots in counts.items())

    @property
    def parsed_counts(self) -> ParsedCounts:
        return get_parsed_counts(self.counts, self.parsed_states)

    @property
    def parsed_state_vector(self) -> Optional[ParsedStateVector]:
        if not self.state_vector:
            return None
        parsed_state_vector = [
            SimulatedState(
                state=self.parsed_state_vector_states[bitstring],
                bitstring=bitstring,
                amplitude=complex(amplitude_str),
            )
            for bitstring, amplitude_str in self.state_vector.items()
        ]
        return sorted(parsed_state_vector, key=lambda k: abs(k.amplitude), reverse=True)

    def flip_execution_counts_bitstring(self) -> None:
        """Backends should return result count bitstring in right to left form"""
        self.counts = flip_counts_qubit_order(self.counts)
        self.counts_lsb_right = not self.counts_lsb_right

    def counts_by_qubit_order(self, lsb_right: bool) -> Counts:
        if self.counts_lsb_right != lsb_right:
            return flip_counts_qubit_order(self.counts)
        else:
            return self.counts

    def counts_of_qubits(self, *qubits: int) -> Counts:
        _validate_qubit_indices(self.counts, qubits)

        reduced_counts: DefaultDict[State, int] = defaultdict(int)
        for state_str, state_count in self.counts_by_qubit_order(
            lsb_right=False
        ).items():
            reduced_counts[_slice_str(state_str, qubits)] += state_count

        return dict(reduced_counts)

    def counts_of_output(self, output_name: Name) -> Counts:
        if output_name not in self.output_qubits_map:
            raise ClassiqError(_UNAVAILABLE_OUTPUT_ERROR_MSG)

        return self.counts_of_qubits(*self.output_qubits_map[output_name])

    def counts_of_multiple_outputs(
        self, output_names: Tuple[Name, ...]
    ) -> Dict[Tuple[State, ...], pydantic.NonNegativeInt]:
        if any(name not in self.output_qubits_map for name in output_names):
            raise ClassiqError(_UNAVAILABLE_OUTPUT_ERROR_MSG)

        output_regs: Tuple[Qubits, ...] = tuple(
            self.output_qubits_map[name] for name in output_names
        )
        reduced_counts: DefaultDict[Tuple[State, ...], int] = defaultdict(int)
        for state_str, state_count in self.counts_by_qubit_order(
            lsb_right=False
        ).items():
            reduced_strs = tuple(_slice_str(state_str, reg) for reg in output_regs)
            reduced_counts[reduced_strs] += state_count
        return dict(reduced_counts)

    def parsed_counts_of_outputs(
        self, output_names: Union[Name, Tuple[Name, ...]]
    ) -> ParsedCounts:
        if isinstance(output_names, Name):
            output_names = (output_names,)
        if any(name not in self.output_qubits_map for name in output_names):
            raise ClassiqError(_UNAVAILABLE_OUTPUT_ERROR_MSG)

        reduced_parsed_states = reduce_parsed_states(self.parsed_states, output_names)
        return get_parsed_counts(self.counts, reduced_parsed_states)

    def register_output_from_qubits(self, qubits: Tuple[int, ...]) -> Dict[float, int]:
        register_output: Dict[float, int] = {}
        value_from_str_bin = functools.partial(
            self._get_register_value_from_binary_string_results, register_qubits=qubits
        )
        for results_binary_key, counts in self.counts_by_qubit_order(
            lsb_right=False
        ).items():
            value = value_from_str_bin(binary_string=results_binary_key)
            register_output[value] = register_output.get(value, 0) + counts

        return register_output

    @staticmethod
    def _get_register_value_from_binary_string_results(
        binary_string: str, register_qubits: List[int]
    ) -> RegisterValue:
        register_binary_string = "".join(
            operator.itemgetter(*register_qubits)(binary_string)
        )[::-1]
        return number_utils.binary_to_float_or_int(bin_rep=register_binary_string)
counts: Dict[str, pydantic.types.NonNegativeInt] pydantic-field

Number of counts per state

counts_lsb_right: bool pydantic-field

Is the qubit order of counts field such that the LSB is right?

histogram: Dict[str, pydantic.types.NonNegativeFloat] pydantic-field

Histogram of probability per state (an alternative to counts)

num_shots: NonNegativeInt pydantic-field

The total number of shots the circuit was executed

output_qubits_map: Dict[str, Tuple[int, ...]] pydantic-field

The map of outputs (measured registers) to their qubits in the circuit.

parsed_state_vector_states: Mapping[str, Mapping[str, Union[float, int]]] pydantic-field

A mapping between the raw states of the state vector (bitstrings) to their parsed states (registers' values)

parsed_states: Mapping[str, Mapping[str, Union[float, int]]] pydantic-field

A mapping between the raw states of counts (bitstrings) to their parsed states (registers' values)

physical_qubits_map: Dict[str, Tuple[int, ...]] pydantic-field

The map of all registers (also non measured) to their qubits in the circuit. Used for state_vector which represent also the non-measured qubits.

state_vector: Dict[str, Any] pydantic-field

The state vector when executed on a simulator, with LSB right qubit order

vendor_format_result: Dict[str, Any] pydantic-field required

Result in proprietary vendor format

flip_execution_counts_bitstring(self)

Backends should return result count bitstring in right to left form

Source code in classiq/interface/executor/result.py
def flip_execution_counts_bitstring(self) -> None:
    """Backends should return result count bitstring in right to left form"""
    self.counts = flip_counts_qubit_order(self.counts)
    self.counts_lsb_right = not self.counts_lsb_right
GroverSimulationResults (VersionedModel) pydantic-model
Source code in classiq/interface/executor/result.py
class GroverSimulationResults(VersionedModel):
    result: Dict[str, Any]
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

MultipleExecutionDetails (VersionedModel) pydantic-model
Source code in classiq/interface/executor/result.py
class MultipleExecutionDetails(VersionedModel):
    details: List[ExecutionDetails]

    def __getitem__(self, index: int) -> ExecutionDetails:
        return self.details[index]
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

SampledState (BaseModel) pydantic-model
Source code in classiq/interface/executor/result.py
class SampledState(BaseModel):
    state: ParsedState
    shots: MeasuredShots

    def __repr__(self) -> str:
        return f"{self.state}: {self.shots}"
__repr__(self) special

Return repr(self).

Source code in classiq/interface/executor/result.py
def __repr__(self) -> str:
    return f"{self.state}: {self.shots}"

vqe_result

VQEIntermediateData (BaseModel) pydantic-model
Source code in classiq/interface/executor/vqe_result.py
class VQEIntermediateData(BaseModel):
    utc_time: datetime = pydantic.Field(description="Time when the iteration finished")
    iteration_number: pydantic.PositiveInt = pydantic.Field(
        description="The iteration's number (evaluation count)"
    )
    parameters: List[float] = pydantic.Field(
        description="The optimizer parameters for the variational form"
    )
    mean_all_solutions: Optional[float] = pydantic.Field(
        default=None, description="The mean score of all solutions in this iteration"
    )
    solutions: List[SolutionData] = pydantic.Field(
        description="Solutions found in this iteration, their score and"
        "number of repetitions"
    )
    standard_deviation: float = pydantic.Field(
        description="The evaluated standard deviation"
    )
iteration_number: PositiveInt pydantic-field required

The iteration's number (evaluation count)

mean_all_solutions: float pydantic-field

The mean score of all solutions in this iteration

parameters: List[float] pydantic-field required

The optimizer parameters for the variational form

solutions: List[classiq.interface.executor.vqe_result.SolutionData] pydantic-field required

Solutions found in this iteration, their score andnumber of repetitions

standard_deviation: float pydantic-field required

The evaluated standard deviation

utc_time: datetime pydantic-field required

Time when the iteration finished

finance special

finance_modelling_params

FinanceModellingParams (BaseModel) pydantic-model
Source code in classiq/interface/finance/finance_modelling_params.py
class FinanceModellingParams(BaseModel):
    finance_model: Finance = pydantic.Field(
        description="The model parameter for the finance problem."
    )
    phase_port_size: int = pydantic.Field(description="Width of the phase port.")
finance_model: Finance pydantic-field required

The model parameter for the finance problem.

phase_port_size: int pydantic-field required

Width of the phase port.

function_input

FinanceFunctionInput (BaseModel) pydantic-model
Source code in classiq/interface/finance/function_input.py
class FinanceFunctionInput(pydantic.BaseModel):
    f: FinanceFunctionType = pydantic.Field(
        description="An enumeration of the wanted financial function: VaR, expected "
        "shortfall, European call options or x^2"
    )
    variable: str = pydantic.Field(
        default="x", description="Variable/s of the function"
    )
    condition: FunctionCondition = pydantic.Field(
        description="The condition for the function"
    )
    polynomial_degree: Optional[int] = pydantic.Field(
        default=None,
        description="The polynomial degree of approximation, uses linear approximation by default",
    )
    use_chebyshev_polynomial_approximation: bool = pydantic.Field(
        default=False,
        description="Flag if to use chebyshev polynomial approximation for target function",
    )

    tail_probability: Optional[PydanticNonZeroProbabilityFloat] = pydantic.Field(
        default=None,
        description="The required probability on the tail of the distribution (1 - percentile)",
    )

    @pydantic.validator("f", pre=True)
    def _convert_f_if_str(cls, f: Any) -> FinanceFunctionType:
        # Keep this for backwards-compatible string support
        if f in FINANCE_FUNCTION_STRING:
            return FINANCE_FUNCTION_STRING[f]
        return f

    @pydantic.validator("use_chebyshev_polynomial_approximation")
    def _validate_polynomial_flag(
        cls, use_chebyshev_flag: bool, values: Dict[str, Any]
    ) -> bool:
        if use_chebyshev_flag ^ (values.get("polynomial_degree") is None):
            return use_chebyshev_flag
        raise ClassiqValueError(
            "Degree must be positive and use_chebyshev_polynomial_approximation set to True"
        )

    @pydantic.validator("f")
    def _validate_finance_function(
        cls, f: Union[int, str, FinanceFunctionType]
    ) -> FinanceFunctionType:
        if isinstance(f, FinanceFunctionType):
            return f
        if isinstance(f, int):
            return FinanceFunctionType(f)
        return FinanceFunctionType.from_string(f)

    @pydantic.validator("tail_probability", always=True)
    def _validate_tail_probability_assignment_for_shortfall(
        cls,
        tail_probability: Optional[PydanticNonZeroProbabilityFloat],
        values: Dict[str, Any],
    ) -> Optional[PydanticNonZeroProbabilityFloat]:
        if values.get("f") == FinanceFunctionType.SHORTFALL and not tail_probability:
            raise ClassiqValueError(
                "Tail probability must be set for expected shortfall"
            )
        return tail_probability

    class Config:
        frozen = True
condition: FunctionCondition pydantic-field required

The condition for the function

f: FinanceFunctionType pydantic-field required

An enumeration of the wanted financial function: VaR, expected shortfall, European call options or x^2

polynomial_degree: int pydantic-field

The polynomial degree of approximation, uses linear approximation by default

tail_probability: PydanticNonZeroProbabilityFloat pydantic-field

The required probability on the tail of the distribution (1 - percentile)

use_chebyshev_polynomial_approximation: bool pydantic-field

Flag if to use chebyshev polynomial approximation for target function

variable: str pydantic-field

Variable/s of the function

FunctionCondition (BaseModel) pydantic-model
Source code in classiq/interface/finance/function_input.py
class FunctionCondition(pydantic.BaseModel):
    threshold: float
    larger: bool = pydantic.Field(
        default=False,
        description="When true, function is set when input is larger to threshold and otherwise 0. Default is False.",
    )

    class Config:
        frozen = True
larger: bool pydantic-field

When true, function is set when input is larger to threshold and otherwise 0. Default is False.

gaussian_model_input

GaussianModelInput (FinanceModelInput) pydantic-model
Source code in classiq/interface/finance/gaussian_model_input.py
class GaussianModelInput(FinanceModelInput):
    kind: Literal["gaussian"] = pydantic.Field(default="gaussian")

    num_qubits: pydantic.PositiveInt = pydantic.Field(
        description="The number of qubits represent"
        "the latent normal random variable Z (Resolution of "
        "the random variable Z)."
    )
    normal_max_value: float = pydantic.Field(
        description="Min/max value to truncate the " "latent normal random variable Z"
    )
    default_probabilities: List[PydanticProbabilityFloat] = pydantic.Field(
        description="default probabilities for each asset"
    )

    rhos: List[pydantic.PositiveFloat] = pydantic.Field(
        description="Sensitivities of default probability of assets "
        "with respect to Z (1/sigma(Z))"
    )
    loss: List[int] = pydantic.Field(
        description="List of ints signifying loss per asset"
    )
    min_loss: Optional[int] = pydantic.Field(
        description="Minimum possible loss for the model "
    )

    @property
    def num_model_qubits(self) -> int:
        return len(self.rhos)

    @property
    def distribution_range(self) -> Tuple[float, float]:
        return 0, sum(self.loss)

    @property
    def num_output_qubits(self) -> int:
        return int(math.log2(sum(self.loss))) + 1

    @property
    def num_bernoulli_qubits(self) -> int:
        return self.num_qubits + self.num_model_qubits
default_probabilities: List[classiq.interface.helpers.custom_pydantic_types.PydanticProbabilityFloat] pydantic-field required

default probabilities for each asset

loss: List[int] pydantic-field required

List of ints signifying loss per asset

min_loss: int pydantic-field

Minimum possible loss for the model

normal_max_value: float pydantic-field required

Min/max value to truncate the latent normal random variable Z

num_qubits: PositiveInt pydantic-field required

The number of qubits representthe latent normal random variable Z (Resolution of the random variable Z).

rhos: List[pydantic.types.PositiveFloat] pydantic-field required

Sensitivities of default probability of assets with respect to Z (1/sigma(Z))

log_normal_model_input

LogNormalModelInput (FinanceModelInput) pydantic-model
Source code in classiq/interface/finance/log_normal_model_input.py
class LogNormalModelInput(FinanceModelInput):
    kind: Literal["log_normal"] = pydantic.Field(default="log_normal")

    num_qubits: pydantic.PositiveInt = pydantic.Field(
        description="Number of qubits to represent the probability."
    )
    mu: pydantic.NonNegativeFloat = pydantic.Field(
        description="Mean of the Normal distribution variable X s.t. ln(X) ~ log-normal."
    )
    sigma: pydantic.PositiveFloat = pydantic.Field(
        description="Std of the Normal distribution variable X s.t. ln(X) ~ log-normal."
    )

    @property
    def distribution_range(self) -> Tuple[float, float]:
        mean = np.exp(self.mu + self.sigma**2 / 2)
        variance = (np.exp(self.sigma**2) - 1) * np.exp(2 * self.mu + self.sigma**2)
        stddev = np.sqrt(variance)
        low = np.maximum(0, mean - 3 * stddev)
        high = mean + 3 * stddev
        return low, high

    @property
    def num_model_qubits(self) -> int:
        return self.num_qubits

    @property
    def num_output_qubits(self) -> int:
        return self.num_qubits

    class Config:
        frozen = True
mu: NonNegativeFloat pydantic-field required

Mean of the Normal distribution variable X s.t. ln(X) ~ log-normal.

num_qubits: PositiveInt pydantic-field required

Number of qubits to represent the probability.

sigma: PositiveFloat pydantic-field required

Std of the Normal distribution variable X s.t. ln(X) ~ log-normal.

generator special

amplitude_estimation

AmplitudeEstimation (FunctionParams) pydantic-model

Creates a quantum circuit for amplitude estimation Provide the state preparation and oracle within the GroverOperator parameter Choose estimation accuracy with the estimation_register_size parameter

Source code in classiq/interface/generator/amplitude_estimation.py
class AmplitudeEstimation(FunctionParams):
    """
    Creates a quantum circuit for amplitude estimation
    Provide the state preparation and oracle within the GroverOperator parameter
    Choose estimation accuracy with the estimation_register_size parameter
    """

    grover_operator: GroverOperator = pydantic.Field(
        description="The Grover Operator used in the algorithm. "
        "Composed of the oracle and the state preparation operator."
    )

    estimation_register_size: pydantic.PositiveInt = pydantic.Field(
        description="The number of qubits used to estimate the amplitude. "
        "Bigger register provides a better estimate of the good states' amplitude."
    )

    def _create_ios(self) -> None:
        self._inputs = dict()
        self._outputs = {
            ESTIMATED_AMPLITUDE_OUTPUT_NAME: RegisterArithmeticInfo(
                size=self.estimation_register_size
            ),
            **self.grover_operator.outputs,
        }
estimation_register_size: PositiveInt pydantic-field required

The number of qubits used to estimate the amplitude. Bigger register provides a better estimate of the good states' amplitude.

grover_operator: GroverOperator pydantic-field required

The Grover Operator used in the algorithm. Composed of the oracle and the state preparation operator.

amplitude_loading

AmplitudeLoading (FunctionParams) pydantic-model
Source code in classiq/interface/generator/amplitude_loading.py
class AmplitudeLoading(FunctionParams):
    size: pydantic.PositiveInt = pydantic.Field(
        description="The number of qubits of the amplitude input."
    )
    expression: PydanticExpressionStr = pydantic.Field(
        description="The mathematical expression of the amplitude loading function."
    )
    implementation: AmplitudeLoadingImplementation = pydantic.Field(
        default=AmplitudeLoadingImplementation.EXPERIMENTAL,
        description="Implementation options.",
    )

    @pydantic.validator("expression", pre=True)
    def validate_coefficient(cls, expression: str) -> str:
        if isinstance(expression, str):
            # We validate the given value is legal and does not contain code that will be executed in our BE.
            validate_expression(
                expression,
                supported_nodes=get_args(GenerationExpressionSupportedNodeTypes),
            )
            # We only check that this method does not raise any exception to see that it can be converted to sympy
            sympy.parse_expr(expression)

        if isinstance(expression, sympy.Expr):
            return str(expression)
        return expression

    @pydantic.root_validator()
    def check_all_variable_are_defined(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        expression = values.get("expression", "")
        literals = set(re.findall(SUPPORTED_VAR_NAMES_REG, expression))

        not_allowed = literals.intersection(FORBIDDEN_LITERALS)
        variables = literals.difference(SUPPORTED_FUNC_NAMES)
        if not_allowed:
            raise ClassiqValueError(
                f"The following names: {not_allowed} are not allowed"
            )

        if len(variables) != 1:
            raise ClassiqValueError(f"{variables} must contain exactly single variable")
        return values

    def _create_ios(self) -> None:
        self._inputs = {
            TARGET_OUTPUT_NAME: RegisterUserInput(name=TARGET_OUTPUT_NAME, size=1),
            AMPLITUDE_IO_NAME: RegisterUserInput(
                name=AMPLITUDE_IO_NAME, size=self.size
            ),
        }
        self._outputs = {
            TARGET_OUTPUT_NAME: RegisterUserInput(name=TARGET_OUTPUT_NAME, size=1),
            **self._inputs,
        }

    @property
    def variable(self) -> str:
        literals = set(re.findall(SUPPORTED_VAR_NAMES_REG, self.expression))
        return list(literals.difference(SUPPORTED_FUNC_NAMES))[0]
expression: ConstrainedStrValue pydantic-field required

The mathematical expression of the amplitude loading function.

implementation: AmplitudeLoadingImplementation pydantic-field

Implementation options.

size: PositiveInt pydantic-field required

The number of qubits of the amplitude input.

arith special

arithmetic_expression_validator
ExpressionValidator (NodeVisitor)
Source code in classiq/interface/generator/arith/arithmetic_expression_validator.py
class ExpressionValidator(ast.NodeVisitor):
    def __init__(
        self,
        supported_nodes: Tuple[Type[AST], ...],
        expression_type: str = DEFAULT_EXPRESSION_TYPE,
        supported_functions: Optional[Set[str]] = None,
        supported_attr_values: Optional[Set[str]] = None,
        mode: str = "eval",
    ) -> None:
        super().__init__()
        self.supported_nodes = supported_nodes
        self._expression_type = expression_type
        self._supported_functions = supported_functions or DEFAULT_SUPPORTED_FUNC_NAMES
        self._supported_attr_values = supported_attr_values or set()
        self._mode = mode
        self._ast_obj: Optional[ast.AST] = None

    def validate(self, expression: str) -> None:
        try:
            adjusted_expression = self._get_adjusted_expression(expression)
            ast_expr = ast.parse(adjusted_expression, filename="", mode=self._mode)
        except SyntaxError as e:
            raise ClassiqValueError(f"Failed to parse expression {expression!r}") from e
        try:
            self._ast_obj = self.rewrite_ast(ast_expr)
            self.visit(self._ast_obj)
        except RecursionError as e:
            raise ClassiqValueError(
                f"Failed to parse expression since it is too long: {expression}"
            ) from e

    @staticmethod
    def _get_adjusted_expression(expression: str) -> str:
        # This works around the simplification of the trivial expressions such as a + 0, 1 * a, etc.
        if IDENITIFIER_REGEX.fullmatch(expression):
            return f"0 + {expression}"
        return expression

    @property
    def ast_obj(self) -> ast.AST:
        if not self._ast_obj:
            raise ClassiqArithmeticError("Must call `validate` before getting ast_obj")
        return self._ast_obj

    @staticmethod
    def _check_repeated_variables(variables: Tuple[Any, Any]) -> None:
        if (
            all(isinstance(var, ast.Name) for var in variables)
            and variables[0].id == variables[1].id
        ):
            raise ClassiqValueError(_REPEATED_VARIABLES_ERROR_MESSAGE)

    @staticmethod
    def _check_multiple_comparators(node: ast.Compare) -> None:
        if len(node.comparators) > 1:
            raise ClassiqValueError(
                "Arithmetic expression with more than 1 comparator is not supported"
            )

    def generic_visit(self, node: ast.AST) -> None:
        self._validate_node_type(node)
        return super().generic_visit(node)

    def _validate_node_type(self, node: ast.AST) -> None:
        if isinstance(node, self.supported_nodes):
            return
        raise ClassiqValueError(
            f"Invalid {self._expression_type} expression: "
            f"{type(node).__name__} is not supported"
        )

    def validate_Compare(self, node: ast.Compare) -> None:  # noqa: N802
        self._check_repeated_variables((node.left, node.comparators[0]))
        self._check_multiple_comparators(node)

    def visit_Compare(self, node: ast.Compare) -> None:
        self.validate_Compare(node)
        self.generic_visit(node)

    def validate_BinOp(self, node: ast.BinOp) -> None:  # noqa: N802
        self._check_repeated_variables((node.left, node.right))

    def visit_BinOp(self, node: ast.BinOp) -> None:
        self.validate_BinOp(node)
        self.generic_visit(node)

    def validate_Call(self, node: ast.Call) -> None:  # noqa: N802
        if len(node.args) >= 2:
            self._check_repeated_variables((node.args[0], node.args[1]))
        node_id = AstNodeRewrite().extract_node_id(node)
        if node_id not in self._supported_functions:
            raise ClassiqValueError(f"{node_id} not in supported functions")

        if node_id in ("CLShift", "CRShift") and (
            len(node.args) != 2 or not isinstance(node.args[1], ast.Constant)
        ):
            raise ClassiqValueError("Cyclic Shift expects 2 arguments (exp, int)")

    def visit_Call(self, node: ast.Call) -> None:
        self.validate_Call(node)
        self.generic_visit(node)

    def validate_Constant(self, node: ast.Constant) -> None:  # noqa: N802
        if not isinstance(node.value, (int, float, complex, str)):
            raise ClassiqValueError(
                f"{type(node.value).__name__} literals are not valid in {self._expression_type} expressions"
            )

    def visit_Constant(self, node: ast.Constant) -> None:
        self.validate_Constant(node)
        self.generic_visit(node)

    def validate_Attribute(self, node: ast.Attribute) -> None:  # noqa: N802
        if not (
            isinstance(node.value, ast.Name)
            and node.value.id in self._supported_attr_values
            or node.attr in CLASSICAL_ATTRIBUTES.keys()
        ):
            raise ClassiqValueError(
                f"Attribute is not supported for value {node.value}"
            )

    def visit_Attribute(self, node: ast.Attribute) -> None:
        self.validate_Attribute(node)
        self.generic_visit(node)

    def visit_FunctionDef(self, node: ast.FunctionDef) -> Any:
        if self._mode == "exec":
            if hasattr(builtins, node.name):
                raise ClassiqValueError(
                    f"Defining a function named {node.name} is forbidden"
                )
            self._supported_functions.add(node.name)
        self.generic_visit(node)

    @classmethod
    def rewrite_ast(cls, expression_ast: AST) -> AST:
        return expression_ast
generic_visit(self, node)

Called if no explicit visitor function exists for a node.

Source code in classiq/interface/generator/arith/arithmetic_expression_validator.py
def generic_visit(self, node: ast.AST) -> None:
    self._validate_node_type(node)
    return super().generic_visit(node)
ast_node_rewrite
AstNodeRewrite (NodeTransformer)
Source code in classiq/interface/generator/arith/ast_node_rewrite.py
class AstNodeRewrite(ast.NodeTransformer):
    def __init__(self) -> None:
        super().__init__()
        self.count_str_gen = _count_str_gen()

    def visit(self, node: ast.AST) -> ast.AST:
        new_node = ast.NodeTransformer.visit(self, node=node)
        new_node.id = self.extract_node_id(new_node)
        return new_node

    def extract_node_id(self, node: ast.AST) -> Optional[Union[str, float]]:
        if hasattr(node, "id"):
            return node.id
        elif hasattr(node, "op"):
            return type(node.op).__name__ + next(self.count_str_gen)
        elif hasattr(node, "func"):
            return self.extract_node_id(node.func)
        elif hasattr(node, "value"):
            return node.value
        elif hasattr(node, "ops"):
            return type(node.ops[0]).__name__ + next(self.count_str_gen)
        return None

    def visit_UnaryOp(self, node: ast.UnaryOp) -> Any:
        if hasattr(node, OUTPUT_SIZE):
            node.operand.output_size = node.output_size  # type: ignore[attr-defined]

        node = cast(ast.UnaryOp, self.generic_visit(node))
        if isinstance(node.op, ast.UAdd):
            return node.operand
        elif isinstance(node.op, ast.USub) and isinstance(node.operand, ast.Constant):
            return self.visit(ast.Constant(value=-node.operand.value))
        return node

    def visit_BinOp(self, node: ast.BinOp) -> Any:
        if hasattr(node, OUTPUT_SIZE):
            node.left.output_size = node.output_size  # type: ignore[attr-defined]
            node.right.output_size = node.output_size  # type: ignore[attr-defined]

        node = cast(ast.BinOp, self.generic_visit(node))
        if isinstance(node.op, ast.Mod):
            if not isinstance(node.right, ast.Constant) or isinstance(
                node.left, ast.Constant
            ):
                raise ClassiqArithmeticError(
                    "Modulo must be between a variable and a constant"
                )
            value = node.right.value
            is_power_2 = value > 0 and (value & (value - 1) == 0)
            if not is_power_2:
                raise ClassiqArithmeticError(NOT_POWER_OF_TWO_ERROR_MSG)
            if not isinstance(node.left, ast.Name):
                node.left.output_size = node.right.value.bit_length() - 1  # type: ignore[attr-defined]
                return node.left
        return node
visit(self, node)

Visit a node.

Source code in classiq/interface/generator/arith/ast_node_rewrite.py
def visit(self, node: ast.AST) -> ast.AST:
    new_node = ast.NodeTransformer.visit(self, node=node)
    new_node.id = self.extract_node_id(new_node)
    return new_node
number_utils
signed_int_to_unsigned(number)

Return the integer value of a signed int if it would we read as un-signed in binary representation

Source code in classiq/interface/generator/arith/number_utils.py
def signed_int_to_unsigned(number: int) -> int:
    """Return the integer value of a signed int if it would we read as un-signed in binary representation"""
    if number >= 0:
        return number

    not_power2 = abs(number) & (abs(number) - 1) != 0
    return number + 2 ** (number.bit_length() + 1 * not_power2)

chemistry_function_params

ChemistryFunctionParams (FunctionParams) pydantic-model
Source code in classiq/interface/generator/chemistry_function_params.py
class ChemistryFunctionParams(FunctionParams):
    gs_problem: CHEMISTRY_PROBLEMS_TYPE

    @pydantic.validator("gs_problem")
    def validate_gs_problem_contains_num_qubits(
        cls, gs_problem: CHEMISTRY_PROBLEMS_TYPE
    ) -> CHEMISTRY_PROBLEMS_TYPE:
        if not gs_problem.num_qubits:
            raise ClassiqValueError(
                "Ground state problem doesn't contain num_qubits. "
                "Use update_problem method."
            )

        return gs_problem

    @property
    def num_qubits(self) -> int:
        assert isinstance(
            self.gs_problem, GroundStateProblem
        ), "self.gs_problem is not from GroundStateProblem class"
        assert isinstance(self.gs_problem.num_qubits, int)
        return self.gs_problem.num_qubits

    def _create_ios(self) -> None:
        self._inputs = {
            DEFAULT_INPUT_NAME: RegisterUserInput(
                name=DEFAULT_INPUT_NAME, size=self.num_qubits
            )
        }
        self._outputs = {
            DEFAULT_OUTPUT_NAME: RegisterUserInput(
                name=DEFAULT_OUTPUT_NAME, size=self.num_qubits
            )
        }
gs_problem: Annotated[Union[classiq.interface.chemistry.ground_state_problem.MoleculeProblem, classiq.interface.chemistry.ground_state_problem.HamiltonianProblem], FieldInfo(default=PydanticUndefined, description='Ground state problem object describing the system.', discriminator='kind', extra={})] pydantic-field required

Ground state problem object describing the system.

commuting_pauli_exponentiation

CommutingPauliExponentiation (FunctionParams) pydantic-model

Exponentiation of a Hermitian Pauli sum operator with commuting pauli strings.

Source code in classiq/interface/generator/commuting_pauli_exponentiation.py
class CommutingPauliExponentiation(FunctionParams):
    """
    Exponentiation of a Hermitian Pauli sum operator with commuting pauli strings.
    """

    pauli_operator: PauliOperator = pydantic.Field(
        description="A weighted sum of Pauli strings."
    )
    evolution_coefficient: ParameterFloatType = pydantic.Field(
        default=1.0,
        description="A global coefficient multiplying the operator.",
        is_exec_param=True,
    )

    @pydantic.validator("pauli_operator")
    def _validate_is_hermitian(cls, pauli_operator: PauliOperator) -> PauliOperator:
        return operator.validate_operator_is_hermitian(pauli_operator)

    @pydantic.validator("pauli_operator")
    def _validate_paulis_commute(cls, pauli_operator: PauliOperator) -> PauliOperator:
        if not pauli_operator.is_commutative:
            raise ClassiqValueError("Pauli strings are not commutative")
        return pauli_operator

    def _create_ios(self) -> None:
        size = self.pauli_operator.num_qubits
        self._inputs = {
            DEFAULT_INPUT_NAME: RegisterUserInput(name=DEFAULT_INPUT_NAME, size=size)
        }
        self._outputs = {
            DEFAULT_OUTPUT_NAME: RegisterUserInput(name=DEFAULT_OUTPUT_NAME, size=size)
        }
evolution_coefficient: Union[float, str] pydantic-field

A global coefficient multiplying the operator.

pauli_operator: PauliOperator pydantic-field required

A weighted sum of Pauli strings.

control_state

ControlState (BaseModel) pydantic-model
Source code in classiq/interface/generator/control_state.py
class ControlState(BaseModel):
    num_ctrl_qubits: pydantic.PositiveInt = pydantic.Field(
        default=_DEFAULT_NUM_CONTROL_QUBITS, description="Number of control qubits"
    )
    ctrl_state: str = pydantic.Field(
        default=_INVALID_CONTROL_STATE, description="Control state string"
    )
    name: str = pydantic.Field(default=None, description="Control name")

    @pydantic.root_validator()
    def _validate_control(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        num_ctrl_qubits: int = values.get(
            "num_ctrl_qubits", _DEFAULT_NUM_CONTROL_QUBITS
        )
        ctrl_state: str = values.get("ctrl_state", _INVALID_CONTROL_STATE)

        if ctrl_state == _INVALID_CONTROL_STATE:
            ctrl_state = "1" * num_ctrl_qubits
            values["ctrl_state"] = ctrl_state

        cls.validate_control_string(ctrl_state)

        if num_ctrl_qubits == _DEFAULT_NUM_CONTROL_QUBITS:
            num_ctrl_qubits = len(ctrl_state)
            values["num_ctrl_qubits"] = num_ctrl_qubits

        if len(ctrl_state) != num_ctrl_qubits:
            raise ClassiqValueError(
                "Control state length should be equal to the number of control qubits"
            )

        if values.get("name") is None:
            values["name"] = f"{_DEFAULT_CONTROL_NAME}_{ctrl_state}"

        return values

    @staticmethod
    def validate_control_string(ctrl_state: str) -> None:
        if not set(ctrl_state) <= {"1", "0"}:
            raise ClassiqValueError(
                f"Control state can only be constructed from 0 and 1, received: {ctrl_state}"
            )
        if not ctrl_state:
            raise ClassiqValueError("Control state cannot be empty")

    def __str__(self) -> str:
        return self.ctrl_state

    def __len__(self) -> int:
        return self.num_ctrl_qubits

    @property
    def control_register(self) -> RegisterUserInput:
        return RegisterUserInput(name=self.name, size=self.num_ctrl_qubits)

    def rename(self, name: str) -> ControlState:
        return ControlState(ctrl_state=self.ctrl_state, name=name)

    class Config:
        frozen = True
ctrl_state: str pydantic-field

Control state string

name: str pydantic-field

Control name

num_ctrl_qubits: PositiveInt pydantic-field

Number of control qubits

__str__(self) special

Return str(self).

Source code in classiq/interface/generator/control_state.py
def __str__(self) -> str:
    return self.ctrl_state

credit_risk_example special

linear_gci
LinearGCI (FunctionParams) pydantic-model

A circuit composed of a series of Y rotations to perform a linear approximation to the Gaussian Conditional Independence model. The model consists of a Bernoulli probability, which itself is a function of a latent random variable x: p(x) = F( (F_inv(p_zero) + x*sqrt(rho))/sqrt(1-rho) ) with F being the Gaussian CDF, p_zero is p(x=0) when rho=0, and rho reflects the sensitivity.

The circuit takes a state register |x> and zero-input target qubits. Each target qubit undergoes the following transformation: |x>|0> -> cos((slopex + offset)/2)|x>|0> + sin((slopex + offset)/2)|x>|1> Where the slope and the offset are determined by the linear approximation of the inverse sine of p(x).

Source code in classiq/interface/generator/credit_risk_example/linear_gci.py
class LinearGCI(function_params.FunctionParams):
    """
    A circuit composed of a series of Y rotations to perform a linear approximation to the Gaussian Conditional
    Independence model.
    The model consists of a Bernoulli probability, which itself is a function of a latent random variable x:
    p(x) = F( (F_inv(p_zero) + x*sqrt(rho))/sqrt(1-rho) )
    with F being the Gaussian CDF, p_zero is p(x=0) when rho=0, and rho reflects the sensitivity.

    The circuit takes a state register |x> and zero-input target qubits.
    Each target qubit undergoes the following transformation:
    |x>|0> -> cos((slope*x + offset)/2)|x>|0> + sin((slope*x + offset)/2)|x>|1>
    Where the slope and the offset are determined by the linear approximation of the inverse sine of p(x).
    """

    num_state_qubits: pydantic.PositiveInt = pydantic.Field(
        description="The number of input qubits"
    )
    truncation_value: float = pydantic.Field(
        description="The truncation value of the latent normal distribution"
    )
    p_zeros: List[PydanticProbabilityFloat] = pydantic.Field(
        description="The probability when the latent normal variable equals zero"
    )
    rhos: List[PydanticNonOneProbabilityFloat] = pydantic.Field(
        description="The sensitivity of the probability to changes in the latent normal variable values"
    )

    @pydantic.validator("rhos")
    def validate_rhos(
        cls, rhos: List[PydanticNonOneProbabilityFloat], values: Dict[str, Any]
    ) -> List[PydanticNonOneProbabilityFloat]:
        p_zeros = values.get("p_zeros")
        if p_zeros is None:
            raise ClassiqValueError("Cannot validate rhos, p_zeros is missing")

        if len(p_zeros) != len(rhos):
            raise ClassiqValueError(RHOS_PZEROS_LENGTH_ERROR_MSG)
        return rhos

    @property
    def linear_pauli_rotations(self) -> linear_pauli_rotations.LinearPauliRotations:
        offsets, slopes = get_gci_values(
            qubit_count_state=self.num_state_qubits,
            truncation_value=self.truncation_value,
            rhos=self.rhos,
            p_zeros=self.p_zeros,
        )
        return linear_pauli_rotations.LinearPauliRotations(
            num_state_qubits=self.num_state_qubits,
            bases=["Y"] * len(self.rhos),
            offsets=offsets,
            slopes=slopes,
        )

    def _create_ios(self) -> None:
        state_name = linear_pauli_rotations.STATE
        target_name = linear_pauli_rotations.TARGET
        self._inputs = {
            state_name: RegisterUserInput(name=state_name, size=self.num_state_qubits),
            target_name: RegisterUserInput(name=target_name, size=len(self.rhos)),
        }
        self._outputs = {**self.inputs}
num_state_qubits: PositiveInt pydantic-field required

The number of input qubits

p_zeros: List[classiq.interface.helpers.custom_pydantic_types.PydanticProbabilityFloat] pydantic-field required

The probability when the latent normal variable equals zero

rhos: List[classiq.interface.helpers.custom_pydantic_types.PydanticNonOneProbabilityFloat] pydantic-field required

The sensitivity of the probability to changes in the latent normal variable values

truncation_value: float pydantic-field required

The truncation value of the latent normal distribution

weighted_adder
WeightedAdder (FunctionParams) pydantic-model

Creates a circuit implementing a scalar product between an n-qubit state |q1,q2,...,qn> and an n-length non-negative integer vector (w1,w2,...wn), such that the result of the output register is |q1w1+q2w2+...qn*wn>. If no weights are provided, they are default to 1 for every qubit.

Source code in classiq/interface/generator/credit_risk_example/weighted_adder.py
class WeightedAdder(function_params.FunctionParams):
    """
    Creates a circuit implementing a scalar product between an n-qubit state |q1,q2,...,qn> and an n-length non-negative
    integer vector (w1,w2,...wn), such that the result of the output register is |q1*w1+q2*w2+...qn*wn>.
    If no weights are provided, they are default to 1 for every qubit.
    """

    num_state_qubits: pydantic.PositiveInt = pydantic.Field(
        description="The number of input qubits"
    )
    weights: List[PydanticStrictNonNegativeInteger] = pydantic.Field(
        default=None,
        description="List of non-negative integers corresponding to the weight of each qubit",
    )

    @pydantic.validator("weights", always=True, pre=True)
    def validate_weights(
        cls,
        weights: Optional[List[PydanticStrictNonNegativeInteger]],
        values: Dict[str, Any],
    ) -> List[PydanticStrictNonNegativeInteger]:
        num_state_qubits = values.get("num_state_qubits")
        if num_state_qubits is None:
            raise ClassiqValueError(
                "Missing num_state_qubits and weights, either must be provided"
            )
        if weights is None:
            return [PydanticStrictNonNegativeInteger(1)] * num_state_qubits
        if len(weights) != num_state_qubits:
            raise ClassiqValueError(LENGTH_ERROR_MESSAGE)
        return weights

    def num_sum_qubits(self) -> int:
        sum_weights = np.sum(self.weights)
        if sum_weights > 0:
            return 1 + int(np.floor(np.log2(sum_weights)))
        return 1

    def _create_ios(self) -> None:
        self._inputs = {
            STATE: RegisterUserInput(name=STATE, size=self.num_state_qubits)
        }
        zero_input_name = get_zero_input_name(SUM)
        self._create_zero_input_registers({zero_input_name: self.num_sum_qubits()})
        self._outputs = {
            **self._inputs,
            SUM: RegisterUserInput(name=SUM, size=self.num_sum_qubits()),
        }
num_state_qubits: PositiveInt pydantic-field required

The number of input qubits

weights: List[classiq.interface.generator.credit_risk_example.weighted_adder.PydanticStrictNonNegativeInteger] pydantic-field

List of non-negative integers corresponding to the weight of each qubit

entangler_params

Entangler (FunctionParams) pydantic-model

A Father class for all entangler classes

Source code in classiq/interface/generator/entangler_params.py
class Entangler(FunctionParams):
    """
    A Father class for all entangler classes
    """

    qubit_count: pydantic.PositiveInt = pydantic.Field(
        description="The number of qubits for the entangler."
    )
    schmidt_rank: pydantic.NonNegativeInt = pydantic.Field(
        default=0, description="The required schmidt rank (log of schmidt number)."
    )

    def _create_ios(self) -> None:
        self._inputs = {IN_NAME: RegisterUserInput(name=IN_NAME, size=self.qubit_count)}
        self._outputs = {
            OUT_NAME: RegisterUserInput(name=OUT_NAME, size=self.qubit_count)
        }
qubit_count: PositiveInt pydantic-field required

The number of qubits for the entangler.

schmidt_rank: NonNegativeInt pydantic-field

The required schmidt rank (log of schmidt number).

GridEntangler (Entangler) pydantic-model

creates a graph state in the form of multi-dimensional grid according to the specified number of qubits and Schmidt rank. If possible the grid will include the exact Schmidt rank if not a smaller grid with a lower schmidt rank is constructed - as close as possible to the specified parameters. if the specified Schmidt rank is too high a 'long' grid with the maximal possible Schmidt rank width is constructed (that still obeys the condition that the largest dimension minus 1 is larger then the sum of the (d_i - 1) -- d_i including all other dimensions)

Source code in classiq/interface/generator/entangler_params.py
class GridEntangler(Entangler):
    """
    creates a graph state in the form of multi-dimensional grid according to the specified number of qubits and Schmidt
    rank. If possible the grid will include the exact Schmidt rank if not a smaller grid with a lower schmidt rank is
    constructed - as close as possible to the specified parameters. if the specified Schmidt rank is too high a 'long'
    grid with the maximal possible Schmidt rank width is constructed (that still obeys the condition that the largest
    dimension minus 1 is larger then the sum of the (d_i - 1) -- d_i including all other dimensions)
    """

    grid_randomization: bool = pydantic.Field(
        default=True,
        description="Boolean determining whether the grid structure is randomly selected out of all grids which provide"
        "the same Schmidt rank width. If False the grid with maximal number of dimensions is selected.",
    )

    filling_factor: PydanticProbabilityFloat = pydantic.Field(
        default=1,
        description="float determining the fraction of cz gates that are included in a circuit for a given grid "
        "structure. For example, for filling_factor=0.5 half of the cz gates required for the full grid structure are "
        "included in the output circuit. The cz gates included in the circuit are chosen randomaly.",
    )
filling_factor: PydanticProbabilityFloat pydantic-field

float determining the fraction of cz gates that are included in a circuit for a given grid structure. For example, for filling_factor=0.5 half of the cz gates required for the full grid structure are included in the output circuit. The cz gates included in the circuit are chosen randomaly.

grid_randomization: bool pydantic-field

Boolean determining whether the grid structure is randomly selected out of all grids which providethe same Schmidt rank width. If False the grid with maximal number of dimensions is selected.

HypercubeEntangler (Entangler) pydantic-model

Creates a cluster/graph state in the form of a hypercube with the specified number of qubits. The hypercube is constructed by building cubes of growing dimension therefore if the number of qubits is not a a power of 2 (n=2^k) the last cube will not be completed. for example if n = 11 = 2^3 + 3 a three dimensional cube is constructed connected to additional 3 qubits in the natural order (that is, these qubits will be: 1000, 1001, 1010)

Source code in classiq/interface/generator/entangler_params.py
class HypercubeEntangler(Entangler):
    """
    Creates a cluster/graph state in the form of a hypercube with the specified number of qubits. The hypercube is
    constructed by building cubes of growing dimension therefore if the number of qubits is not a a power of 2 (n=2^k)
    the last cube will not be completed. for example if n = 11 = 2^3 + 3 a three dimensional cube is constructed
    connected to additional 3 qubits in the natural order
    (that is, these qubits will be: 1000, 1001, 1010)
    """

    pass
TwoDimensionalEntangler (Entangler) pydantic-model

Creates a two dimensional cluster state with the specified number of qubits and schmidt rank (log of schmidt number). When the desired schmidt rank is too high, a rectangular grid with schmidt rank floor(sqrt(qubit_count))-1 is generated.

Source code in classiq/interface/generator/entangler_params.py
class TwoDimensionalEntangler(Entangler):
    """
    Creates a two dimensional cluster state with the specified number of qubits and schmidt rank
    (log of schmidt number). When the desired schmidt rank is too high, a rectangular grid with schmidt rank
    floor(sqrt(qubit_count))-1 is generated.
    """

    pass

expressions special

evaluated_expression
EvaluatedExpression dataclass

EvaluatedExpression(value: Union[int, float, list, bool, classiq.interface.generator.expressions.qmod_struct_instance.QmodStructInstance, classiq.interface.generator.expressions.qmod_sized_proxy.QmodSizedProxy, classiq.interface.generator.expressions.type_proxy.TypeProxy, classiq.interface.generator.expressions.handle_identifier.HandleIdentifier, sympy.core.expr.Expr, sympy.logic.boolalg.Boolean])

Source code in classiq/interface/generator/expressions/evaluated_expression.py
@dataclass(frozen=True)
class EvaluatedExpression:
    value: ExpressionValue

    def is_constant(self, constant_type: Optional[Type] = None) -> bool:
        if self.value is None:
            return False

        return isinstance(
            self.value,
            get_args(RuntimeConstant) if constant_type is None else constant_type,
        )

    def as_constant_type(self, constant_type: Type) -> Any:
        if not self.is_constant():
            raise ClassiqValueError(
                f"Invalid access to expression {self.value!r} as {constant_type}"
            )

        return constant_type(self.value)

    def to_int_value(self) -> int:
        return self.as_constant_type(int)

    def to_bool_value(self) -> bool:
        return self.as_constant_type(bool)

    def to_float_value(self) -> float:
        return self.as_constant_type(float)

    def to_list(self) -> list:
        return self.as_constant_type(list)

    def to_handle(self) -> HandleIdentifier:
        if not isinstance(self.value, HandleIdentifier):
            raise ClassiqValueError(
                f"Invalid access to expression {self.value} as HandleIdentifier"
            )

        return self.value

    def to_struct_dict(self) -> Mapping[str, Any]:
        if not isinstance(self.value, QmodStructInstance):
            raise ClassiqValueError(
                f"Invalid access to expression {self.value} as SympyStructInstance"
            )

        return self.value.fields

    def as_expression(self) -> str:
        if self.value is None:
            raise ClassiqValueError("Invalid access to unevaluated expression")

        return str(self.value)

    def is_identifier(self) -> bool:
        return (
            isinstance(self.value, Expr)
            and re.fullmatch(EXECUTION_PARAMETER_PATTERN, str(self.value)) is not None
        )
expression
Expression (HashableASTNode) pydantic-model
Source code in classiq/interface/generator/expressions/expression.py
class Expression(HashableASTNode):
    expr: str
    _evaluated_expr: Optional[EvaluatedExpression] = PrivateAttr(default=None)

    def __init__(self, **kwargs: Any) -> None:
        super().__init__(**kwargs)

        self._try_to_immediate_evaluate()

    @pydantic.validator("expr")
    def validate_expression(cls, expr: str) -> str:
        supported_functions = (
            SUPPORTED_ATOMIC_EXPRESSION_FUNCTIONS
            | set(SYMPY_SUPPORTED_EXPRESSIONS)
            | set(DEFAULT_SUPPORTED_FUNC_NAMES)
        )
        validate_expression_str(expr, supported_functions=supported_functions)
        return expr

    def is_evaluated(self) -> bool:
        return self._evaluated_expr is not None

    def as_constant(self, constant_type: Type) -> Any:
        return self.value.as_constant_type(constant_type)

    def to_int_value(self) -> int:
        return self.as_constant(int)

    def to_bool_value(self) -> bool:
        return self.as_constant(bool)

    def to_float_value(self) -> float:
        return self.as_constant(float)

    def to_struct_dict(self) -> Mapping[str, Any]:
        return self.value.to_struct_dict()

    def to_list(self) -> list:
        return self.as_constant(list)

    def _try_to_immediate_evaluate(self) -> None:
        try:
            result = ast.literal_eval(self.expr)
            if isinstance(result, (int, float, bool)):
                self._evaluated_expr = EvaluatedExpression(value=result)
        except Exception:  # noqa: S110
            pass

    @property
    def value(self) -> EvaluatedExpression:
        if self._evaluated_expr is None:
            raise ClassiqError(f"Trying to access unevaluated value {self.expr}")

        return self._evaluated_expr

    def as_expression(self) -> str:
        return self.value.as_expression()

    def is_constant(self) -> bool:
        return self.value.is_constant()

    class Config:
        frozen = True

    def __str__(self) -> str:
        return self.expr
__str__(self) special

Return str(self).

Source code in classiq/interface/generator/expressions/expression.py
def __str__(self) -> str:
    return self.expr
handle_identifier
HandleIdentifier dataclass

HandleIdentifier(id: int)

Source code in classiq/interface/generator/expressions/handle_identifier.py
@dataclasses.dataclass(frozen=True)
class HandleIdentifier:
    id: int
qmod_qscalar_proxy
QmodQScalarProxy (Symbol, QmodSizedProxy)
Source code in classiq/interface/generator/expressions/qmod_qscalar_proxy.py
class QmodQScalarProxy(Symbol, QmodSizedProxy):
    def __new__(cls, name: str, **assumptions: bool) -> "QmodQScalarProxy":
        return super().__new__(cls, name, **assumptions)

    def __init__(self, name: str, size: int) -> None:
        super().__init__(size)
        self.name = name

    @property
    def handle(self) -> HandleBinding:
        return HandleBinding(name=self.name)
__new__(cls, name, **assumptions) special staticmethod

Symbols are identified by name and assumptions::

from sympy import Symbol Symbol("x") == Symbol("x") True Symbol("x", real=True) == Symbol("x", real=False) False

Source code in classiq/interface/generator/expressions/qmod_qscalar_proxy.py
def __new__(cls, name: str, **assumptions: bool) -> "QmodQScalarProxy":
    return super().__new__(cls, name, **assumptions)

finance

Finance (FunctionParams) pydantic-model
Source code in classiq/interface/generator/finance.py
class Finance(function_params.FunctionParams):
    model: Union[GaussianModelInput, LogNormalModelInput] = pydantic.Field(
        description="Load a financial model", discriminator="kind"
    )
    finance_function: FinanceFunctionInput = pydantic.Field(
        description="The finance function to solve the model"
    )

    def _create_ios(self) -> None:
        finance_model = FinanceModels(model=self.model)
        # 1 for the objective qubit
        function_size = sum(
            reg.size for reg in finance_model._outputs.values() if reg is not None
        )
        self._inputs = {
            FUNCTION_INPUT_NAME: RegisterUserInput(
                name=FUNCTION_INPUT_NAME, size=function_size
            ),
            OBJECTIVE_INPUT_NAME: RegisterUserInput(name=OBJECTIVE_INPUT_NAME, size=1),
        }
        self._outputs = {
            FUNCTION_OUTPUT_NAME: RegisterUserInput(
                name=FUNCTION_OUTPUT_NAME, size=function_size
            ),
            OBJECTIVE_OUTPUT_NAME: RegisterUserInput(
                name=OBJECTIVE_OUTPUT_NAME, size=1
            ),
        }
finance_function: FinanceFunctionInput pydantic-field required

The finance function to solve the model

model: Union[classiq.interface.finance.gaussian_model_input.GaussianModelInput, classiq.interface.finance.log_normal_model_input.LogNormalModelInput] pydantic-field required

Load a financial model

FinanceModels (FunctionParams) pydantic-model
Source code in classiq/interface/generator/finance.py
class FinanceModels(function_params.FunctionParams):
    model: Union[GaussianModelInput, LogNormalModelInput] = pydantic.Field(
        description="Load a financial model"
    )

    def _create_ios(self) -> None:
        self._outputs = {
            DEFAULT_OUTPUT_NAME: RegisterUserInput(
                name=DEFAULT_OUTPUT_NAME, size=self.model.num_output_qubits
            )
        }
        if isinstance(self.model, GaussianModelInput):
            self._inputs = {
                DEFAULT_INPUT_NAME: RegisterUserInput(
                    name=DEFAULT_INPUT_NAME, size=self.model.num_bernoulli_qubits
                )
            }
            self._create_zero_input_registers(
                {DEFAULT_ZERO_NAME: self.model.num_output_qubits}
            )
            self._outputs[DEFAULT_BERNOULLI_OUTPUT_NAME] = RegisterUserInput(
                name=DEFAULT_BERNOULLI_OUTPUT_NAME,
                size=self.model.num_bernoulli_qubits,
            )
        elif isinstance(self.model, LogNormalModelInput):
            self._inputs = {
                DEFAULT_INPUT_NAME: RegisterUserInput(
                    name=DEFAULT_INPUT_NAME, size=self.model.num_model_qubits
                )
            }
model: Union[classiq.interface.finance.gaussian_model_input.GaussianModelInput, classiq.interface.finance.log_normal_model_input.LogNormalModelInput] pydantic-field required

Load a financial model

FinancePayoff (FunctionParams) pydantic-model
Source code in classiq/interface/generator/finance.py
class FinancePayoff(function_params.FunctionParams):
    finance_function: FinanceFunctionInput = pydantic.Field(
        description="The finance function to solve the model"
    )
    num_qubits: pydantic.PositiveInt
    distribution_range: Tuple[float, float]

    def _create_ios(self) -> None:
        self._inputs = {
            DEFAULT_INPUT_NAME: RegisterUserInput(
                name=DEFAULT_INPUT_NAME, size=self.num_qubits
            )
        }
        self._create_zero_input_registers({DEFAULT_ZERO_NAME: 1})
        self._outputs = {
            DEFAULT_OUTPUT_NAME: RegisterUserInput(name=DEFAULT_OUTPUT_NAME, size=1),
            DEFAULT_POST_INPUT_NAME: RegisterUserInput(
                name=DEFAULT_INPUT_NAME, size=self.num_qubits
            ),
        }
finance_function: FinanceFunctionInput pydantic-field required

The finance function to solve the model

functions special

classical_function_declaration
ClassicalFunctionDeclaration (FunctionDeclaration) pydantic-model

Facilitates the creation of a common classical function interface object.

Source code in classiq/interface/generator/functions/classical_function_declaration.py
class ClassicalFunctionDeclaration(FunctionDeclaration):
    """
    Facilitates the creation of a common classical function interface object.
    """

    return_type: Optional[ConcreteClassicalType] = pydantic.Field(
        description="The type of the classical value that is returned by the function (for classical functions)",
        default=None,
    )

    BUILTIN_FUNCTION_DECLARATIONS: ClassVar[
        Dict[str, "ClassicalFunctionDeclaration"]
    ] = {}

    FOREIGN_FUNCTION_DECLARATIONS: ClassVar[
        Dict[str, "ClassicalFunctionDeclaration"]
    ] = {}

    def update_logic_flow(
        self, function_dict: Mapping[str, "ClassicalFunctionDeclaration"]
    ) -> None:
        pass
return_type: Annotated[Union[classiq.interface.generator.functions.classical_type.Integer, classiq.interface.generator.functions.classical_type.Real, classiq.interface.generator.functions.classical_type.Bool, classiq.interface.generator.functions.classical_type.ClassicalList, classiq.interface.generator.functions.classical_type.Pauli, classiq.interface.generator.functions.classical_type.StructMetaType, classiq.interface.generator.functions.classical_type.Struct, classiq.interface.generator.functions.classical_type.ClassicalArray, classiq.interface.generator.functions.classical_type.VQEResult, classiq.interface.generator.functions.classical_type.Histogram, classiq.interface.generator.functions.classical_type.Estimation, classiq.interface.generator.functions.classical_type.LadderOperator, classiq.interface.generator.functions.classical_type.IQAERes], FieldInfo(default=PydanticUndefined, discriminator='kind', extra={})] pydantic-field

The type of the classical value that is returned by the function (for classical functions)

classical_type
Struct (ClassicalType) pydantic-model
Source code in classiq/interface/generator/functions/classical_type.py
class Struct(ClassicalType):
    kind: Literal["struct_instance"]
    name: str = pydantic.Field(description="The struct type of the instance")

    @property
    def default_value(self) -> Any:
        return super().default_value

    @pydantic.root_validator(pre=True)
    def _set_kind(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        return values_with_discriminator(values, "kind", "struct_instance")

    @property
    def qmod_type(self) -> type:
        return type(self.name, (CStructBase,), dict())
name: str pydantic-field required

The struct type of the instance

foreign_function_definition
SynthesisForeignFunctionDefinition (SynthesisQuantumFunctionDeclaration) pydantic-model

Facilitates the creation of a user-defined elementary function

This class sets extra to forbid so that it can be used in a Union and not "steal" objects from other classes.

Source code in classiq/interface/generator/functions/foreign_function_definition.py
class SynthesisForeignFunctionDefinition(SynthesisQuantumFunctionDeclaration):
    """
    Facilitates the creation of a user-defined elementary function

    This class sets extra to forbid so that it can be used in a Union and not "steal"
    objects from other classes.
    """

    register_mapping: RegisterMappingData = pydantic.Field(
        default_factory=RegisterMappingData,
        description="The PortDirection data that is common to all implementations of the function",
    )
    implementations: Optional[ImplementationsType] = pydantic.Field(
        description="The implementations of the custom function",
    )

    @pydantic.validator("register_mapping")
    def _validate_register_mapping(
        cls, register_mapping: RegisterMappingData
    ) -> RegisterMappingData:
        if not register_mapping.output_registers:
            raise ClassiqValueError(
                "The outputs of a custom function must be non-empty"
            )
        return register_mapping

    @pydantic.validator("implementations", pre=True)
    def _parse_implementations(
        cls,
        implementations: Optional[Union[ImplementationsType, FunctionImplementation]],
    ) -> Optional[ImplementationsType]:
        if isinstance(implementations, FunctionImplementation):
            return (implementations,)

        return implementations

    @pydantic.validator("implementations")
    def _validate_implementations(
        cls,
        implementations: Optional[ImplementationsType],
        values: Dict[str, Any],
    ) -> Optional[ImplementationsType]:
        if not implementations:
            raise ClassiqValueError(
                "The implementations of a custom function must be non-empty."
            )

        register_mapping = values.get("register_mapping")
        assert isinstance(register_mapping, RegisterMappingData)
        for impl in implementations:
            impl.validate_ranges_of_all_registers(register_mapping=register_mapping)

        return implementations

    @property
    def inputs(self) -> ArithmeticIODict:
        return _map_reg_user_input(self.register_mapping.input_registers)

    @property
    def outputs(self) -> ArithmeticIODict:
        return _map_reg_user_input(self.register_mapping.output_registers)

    def renamed(self, new_name: str) -> SynthesisForeignFunctionDefinition:
        return SynthesisForeignFunctionDefinition(
            name=new_name,
            implementations=self.implementations,
            register_mapping=self.register_mapping,
        )

    @property
    def port_declarations(self) -> Dict[IOName, SynthesisPortDeclaration]:
        raise ClassiqValueError(
            "Bad usage of foreign function definition: port_declarations"
        )

    @port_declarations.setter
    def port_declarations(self, value: Any) -> NoReturn:
        raise ClassiqValueError(
            "Bad usage of foreign function definition: port_declarations"
        )
implementations: Tuple[classiq.interface.generator.functions.function_implementation.FunctionImplementation, ...] pydantic-field

The implementations of the custom function

register_mapping: RegisterMappingData pydantic-field

The PortDirection data that is common to all implementations of the function

function_declaration
FunctionDeclaration (ASTNode, ABC) pydantic-model

Facilitates the creation of a common function interface object.

Source code in classiq/interface/generator/functions/function_declaration.py
class FunctionDeclaration(ASTNode, abc.ABC):
    """
    Facilitates the creation of a common function interface object.
    """

    name: str = pydantic.Field(description="The name of the function")

    param_decls: Dict[str, ConcreteClassicalType] = pydantic.Field(
        description="The expected interface of the functions parameters",
        default_factory=dict,
    )

    class Config:
        extra = pydantic.Extra.forbid
name: str pydantic-field required

The name of the function

param_decls: Dict[str, Annotated[Union[classiq.interface.generator.functions.classical_type.Integer, classiq.interface.generator.functions.classical_type.Real, classiq.interface.generator.functions.classical_type.Bool, classiq.interface.generator.functions.classical_type.ClassicalList, classiq.interface.generator.functions.classical_type.Pauli, classiq.interface.generator.functions.classical_type.StructMetaType, classiq.interface.generator.functions.classical_type.Struct, classiq.interface.generator.functions.classical_type.ClassicalArray, classiq.interface.generator.functions.classical_type.VQEResult, classiq.interface.generator.functions.classical_type.Histogram, classiq.interface.generator.functions.classical_type.Estimation, classiq.interface.generator.functions.classical_type.LadderOperator, classiq.interface.generator.functions.classical_type.IQAERes], FieldInfo(default=PydanticUndefined, discriminator='kind', extra={})]] pydantic-field

The expected interface of the functions parameters

function_implementation
FunctionImplementation (BaseModel) pydantic-model

Facilitates the creation of a user-defined custom function implementation

Source code in classiq/interface/generator/functions/function_implementation.py
class FunctionImplementation(BaseModel):
    """
    Facilitates the creation of a user-defined custom function implementation
    """

    class Config:
        validate_all = True
        extra = "forbid"

    name: Optional[PydanticNonEmptyString] = pydantic.Field(
        default=None,
        description="The name of the custom implementation",
    )

    serialized_circuit: PydanticNonEmptyString = pydantic.Field(
        description="The QASM code of the custom function implementation",
    )

    auxiliary_registers: RegistersStrictType = pydantic.Field(
        default_factory=tuple,
        description="A tuple of auxiliary registers to the custom implementation",
    )

    def num_qubits_in_all_registers(self, register_mapping: RegisterMappingData) -> int:
        all_input_registers = (
            register_mapping.input_registers
            + register_mapping.zero_input_registers
            + list(self.auxiliary_registers)
        )
        input_qubits = set(
            chain.from_iterable(register.qubits for register in all_input_registers)
        )
        return len(input_qubits)

    @pydantic.validator(
        "auxiliary_registers",
        pre=True,
        always=True,
    )
    def validate_all_registers_are_tuples(
        cls,
        registers: RegistersType,
    ) -> RegistersStrictType:
        if isinstance(registers, Register):
            return (registers,)
        return registers

    def validate_ranges_of_all_registers(
        self, register_mapping: RegisterMappingData
    ) -> None:
        input_registers = register_mapping.input_registers
        output_registers = register_mapping.output_registers
        zero_input_registers = register_mapping.zero_input_registers
        auxiliary_registers = list(self.auxiliary_registers)

        all_input_registers = (
            input_registers + zero_input_registers + auxiliary_registers
        )
        input_qubits = set(
            chain.from_iterable(register.qubits for register in all_input_registers)
        )
        num_qubits = len(input_qubits)
        all_qubits = set(range(num_qubits))
        if num_qubits != sum(register.width for register in all_input_registers):
            raise ClassiqValueError("The input registers must not overlap.")
        if input_qubits != all_qubits:
            raise ClassiqValueError(
                "The set of qubits contained in all registers must be consecutive."
            )

        all_output_registers = output_registers + auxiliary_registers
        output_qubits = set(
            chain.from_iterable(register.qubits for register in all_output_registers)
        )
        if len(output_qubits) != sum(
            register.width for register in all_output_registers
        ):
            raise ClassiqValueError("The output registers must not overlap.")
        if not output_qubits == all_qubits:
            raise ClassiqValueError(
                "The input and output qubits must be mutually consistent."
            )
auxiliary_registers: Tuple[classiq.interface.generator.functions.register.Register, ...] pydantic-field

A tuple of auxiliary registers to the custom implementation

name: ConstrainedStrValue pydantic-field

The name of the custom implementation

serialized_circuit: ConstrainedStrValue pydantic-field required

The QASM code of the custom function implementation

native_function_definition
IOData (BaseModel) pydantic-model
Source code in classiq/interface/generator/functions/native_function_definition.py
class IOData(pydantic.BaseModel):
    wire: WireName = pydantic.Field(
        description="The name of the wire of the PortDirection data."
    )
    reg: RegisterUserInput = pydantic.Field(
        description="The register information about the PortDirection data."
    )

    class Config:
        frozen = True
reg: RegisterUserInput pydantic-field required

The register information about the PortDirection data.

wire: ConstrainedStrValue pydantic-field required

The name of the wire of the PortDirection data.

SynthesisNativeFunctionDefinition (SynthesisQuantumFunctionDeclaration) pydantic-model

Facilitates the creation of a user-defined composite function

This class sets extra to forbid so that it can be used in a Union and not "steal" objects from other classes.

Source code in classiq/interface/generator/functions/native_function_definition.py
class SynthesisNativeFunctionDefinition(SynthesisQuantumFunctionDeclaration):
    """
    Facilitates the creation of a user-defined composite function

    This class sets extra to forbid so that it can be used in a Union and not "steal"
    objects from other classes.
    """

    input_ports_wiring: Dict[IOName, WireName] = pydantic.Field(
        description="The mapping between the functions input ports, to inner wires",
        default_factory=dict,
    )

    output_ports_wiring: Dict[IOName, WireName] = pydantic.Field(
        description="The mapping between the functions output ports, to inner wires",
        default_factory=dict,
    )

    body: List[SynthesisQuantumFunctionCall] = pydantic.Field(
        default_factory=list, description="List of function calls to perform."
    )

    def validate_body(self) -> None:
        function_call_names = {call.name for call in self.body}
        if len(function_call_names) != len(self.body):
            raise ClassiqValueError(LOGIC_FLOW_DUPLICATE_NAME_ERROR_MSG)
        flow_graph.validate_legal_wiring(
            self.body,
            flow_input_names=list(self.input_ports_wiring.values()),
            flow_output_names=list(self.output_ports_wiring.values()),
        )
        flow_graph.validate_acyclic_logic_flow(
            self.body,
            flow_input_names=list(self.input_ports_wiring.values()),
            flow_output_names=list(self.output_ports_wiring.values()),
        )

    @classmethod
    def _validate_direction_ports(
        cls,
        port_declarations: Dict[IOName, SynthesisPortDeclaration],
        directions_external_port_wiring: WireDict,
        direction: PortDirection,
    ) -> None:
        for io_name in directions_external_port_wiring:
            if (
                io_name not in port_declarations
                or not port_declarations[io_name].direction == direction
            ):
                raise ClassiqValueError(
                    f"The wired {direction} port {io_name!r} is not declared."
                )

    @pydantic.root_validator
    def validate_ports(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        port_declarations: Optional[Dict[IOName, SynthesisPortDeclaration]] = (
            values.get("port_declarations")
        )
        if port_declarations is None:
            return values
        cls._validate_direction_ports(
            port_declarations,
            values.get("input_ports_wiring", dict()),
            PortDirection.Input,
        )
        cls._validate_direction_ports(
            port_declarations,
            values.get("output_ports_wiring", dict()),
            PortDirection.Output,
        )
        return values

    @pydantic.validator("input_ports_wiring", always=True)
    def _populate_input_ports_wiring(
        cls, input_ports_wiring: Dict[IOName, WireName], values: Dict[str, Any]
    ) -> Dict[IOName, WireName]:
        return _validate_ports_wiring_for_direction(
            input_ports_wiring, values, PortDirection.Input
        )

    @pydantic.validator("output_ports_wiring", always=True)
    def _populate_output_ports_wiring(
        cls, output_ports_wiring: Dict[IOName, WireName], values: Dict[str, Any]
    ) -> Dict[IOName, WireName]:
        return _validate_ports_wiring_for_direction(
            output_ports_wiring, values, PortDirection.Output
        )
body: List[classiq.interface.generator.quantum_function_call.SynthesisQuantumFunctionCall] pydantic-field

List of function calls to perform.

input_ports_wiring: Dict[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue, classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue] pydantic-field

The mapping between the functions input ports, to inner wires

output_ports_wiring: Dict[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue, classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue] pydantic-field

The mapping between the functions output ports, to inner wires

quantum_function_declaration
SynthesisQuantumFunctionDeclaration (BaseModel) pydantic-model

Facilitates the creation of a common quantum function interface object.

Source code in classiq/interface/generator/functions/quantum_function_declaration.py
class SynthesisQuantumFunctionDeclaration(BaseModel):
    """
    Facilitates the creation of a common quantum function interface object.
    """

    name: str = pydantic.Field(description="The name of the function")

    port_declarations: Dict[IOName, SynthesisPortDeclaration] = pydantic.Field(
        description="The input and output ports of the function.",
        default_factory=dict,
    )

    @property
    def input_set(self) -> Set[IOName]:
        return set(self.inputs.keys())

    @property
    def output_set(self) -> Set[IOName]:
        return set(self.outputs.keys())

    @property
    def inputs(self) -> ArithmeticIODict:
        return _ports_to_registers(self.port_declarations, PortDirection.Input)

    @property
    def outputs(self) -> ArithmeticIODict:
        return _ports_to_registers(self.port_declarations, PortDirection.Output)

    @pydantic.validator("port_declarations")
    def _validate_port_declarations_names(
        cls, port_declarations: Dict[IOName, SynthesisPortDeclaration]
    ) -> Dict[IOName, SynthesisPortDeclaration]:
        validate_nameables_mapping(port_declarations, "Port")
        return port_declarations

    class Config:
        extra = pydantic.Extra.forbid
name: str pydantic-field required

The name of the function

port_declarations: Dict[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue, classiq.interface.generator.functions.port_declaration.SynthesisPortDeclaration] pydantic-field

The input and output ports of the function.

register
Register (BaseModel) pydantic-model

A user-defined custom register.

Source code in classiq/interface/generator/functions/register.py
class Register(BaseModel):
    """
    A user-defined custom register.
    """

    name: PydanticNonEmptyString = pydantic.Field(
        description="The name of the custom register",
    )

    qubits: QubitsType = pydantic.Field(
        description="A tuple of qubits as integers as indexed within a custom function code",
    )

    @property
    def width(self) -> pydantic.PositiveInt:
        """The number of qubits of the custom register"""
        return len(self.qubits)

    @pydantic.validator("qubits")
    def validate_qubits(cls, qubits: QubitsType) -> QubitsType:
        if len(qubits) == 0:
            raise ClassiqValueError("qubits field must be non-empty.")
        if len(set(qubits)) != len(qubits):
            raise ClassiqValueError("All qubits of a register must be distinct.")
        return qubits
name: ConstrainedStrValue pydantic-field required

The name of the custom register

qubits: Tuple[pydantic.types.NonNegativeInt, ...] pydantic-field required

A tuple of qubits as integers as indexed within a custom function code

width: pydantic.PositiveInt property readonly

The number of qubits of the custom register

grover_diffuser

GroverDiffuser (FunctionParams) pydantic-model
Source code in classiq/interface/generator/grover_diffuser.py
class GroverDiffuser(FunctionParams):
    variables: List[RegisterUserInput]
    state_preparation: str = pydantic.Field(
        default="", description="State preparation function"
    )
    state_preparation_params: GroverStatePreparation = pydantic.Field(
        description="State preparation function parameters",
        default_factory=CustomFunction,
    )

    def _create_ios(self) -> None:
        self._inputs = {reg.name: reg for reg in self.variables}
        self._outputs = {reg.name: reg for reg in self.variables}

    @pydantic.root_validator(pre=True)
    def _validate_state_preparation_name(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        if isinstance(
            values.get("state_preparation_params"), CustomFunction
        ) and not values.get("state_preparation"):
            raise ClassiqValueError(
                "Must receive the function name from the `state_preparation` field for user defined functions"
            )
        return values

    @pydantic.root_validator(pre=True)
    def _parse_state_preparation(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        parse_function_params_values(
            values=values,
            params_key="state_preparation_params",
            discriminator_key="state_preparation",
            param_classes={StatePreparation, CustomFunction},
            default_parser_class=CustomFunction,
        )
        return values

    @pydantic.validator("variables")
    def _validate_variables(
        cls, variables: List[RegisterUserInput]
    ) -> List[RegisterUserInput]:
        names = {reg.name for reg in variables}
        assert len(variables) == len(names), "Repeating names not allowed"
        return variables

    @pydantic.validator("state_preparation_params")
    def _validate_state_preparation(
        cls, state_preparation_params: GroverStatePreparation, values: Dict[str, Any]
    ) -> GroverStatePreparation:
        variables = values.get("variables", list())
        sp_inputs = state_preparation_params.inputs_full(strict_zero_ios=False)
        sp_outputs = state_preparation_params.outputs
        if len(sp_inputs) == 1 and len(sp_outputs) == 1:
            var_size = sum(reg.size for reg in variables)
            assert (
                state_preparation_params.num_input_qubits(strict_zero_ios=False)
                == var_size
            )
            assert state_preparation_params.num_output_qubits == var_size
        else:
            variable_names_and_sizes = cls._names_and_sizes(
                {var.name: var for var in variables}
            )
            assert cls._names_and_sizes(sp_inputs) == variable_names_and_sizes
            assert cls._names_and_sizes(sp_outputs) == variable_names_and_sizes
        return state_preparation_params

    @staticmethod
    def _names_and_sizes(transputs: ArithmeticIODict) -> Set[Tuple[str, int]]:
        return {(name, reg.size) for name, reg in transputs.items()}
state_preparation: str pydantic-field

State preparation function

state_preparation_params: Union[classiq.interface.generator.state_preparation.state_preparation.StatePreparation, classiq.interface.generator.user_defined_function_params.CustomFunction] pydantic-field

State preparation function parameters

grover_operator

GroverOperator (FunctionParams) pydantic-model
Source code in classiq/interface/generator/grover_operator.py
class GroverOperator(FunctionParams):
    oracle: str = pydantic.Field(
        default=_DEFAULT_ORACLE_DISCRIMINATOR, description="Oracle function"
    )
    oracle_params: OracleABC = pydantic.Field(description="Oracle function parameters")
    state_preparation: str = pydantic.Field(
        default="", description="State preparation function"
    )
    state_preparation_params: GroverStatePreparation = pydantic.Field(
        default=None, description="State preparation function parameters"
    )

    def _create_ios(self) -> None:
        self._inputs = {**self.oracle_params.inputs}
        self._outputs = {**self.oracle_params.outputs}

    @pydantic.root_validator(pre=True)
    def _parse_oracle(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        oracle_params = values.get("oracle_params")
        if isinstance(oracle_params, dict):
            values["oracle_params"] = parse_function_params(
                params=oracle_params,
                discriminator=values.get("oracle", _DEFAULT_ORACLE_DISCRIMINATOR),
                param_classes=oracle_function_param_library.param_list,
                no_discriminator_error=ClassiqValueError("Invalid oracle name"),
                bad_function_error=ClassiqValueError("Invalid oracle params"),
            )
        elif isinstance(oracle_params, FunctionParams):
            values["oracle"] = oracle_params.discriminator()
        else:
            raise ClassiqValueError("Invalid oracle params")
        return values

    @pydantic.validator("state_preparation_params", always=True)
    def _validate_state_preparation(
        cls,
        state_preparation_params: Optional[GroverStatePreparation],
        values: Dict[str, Any],
    ) -> GroverStatePreparation:
        oracle = values.get("oracle_params")
        assert oracle is not None, "Must receive an oracle"
        state_preparation_params = (
            state_preparation_params
            or cls._default_state_preparation_params(
                num_qubits=oracle.num_input_qubits(strict_zero_ios=True)
            )
        )
        assert GroverDiffuser(
            state_preparation_params=state_preparation_params,
            state_preparation=values.get("state_preparation", ""),
            variables=oracle.variables(),
        ), "Cannot construct a GroverDiffuser"
        return state_preparation_params

    @staticmethod
    def _default_state_preparation_params(num_qubits: int) -> StatePreparation:
        num_states: int = 2**num_qubits
        return StatePreparation(
            probabilities=[1.0 / float(num_states)] * num_states,
            error_metric={
                Metrics.L2: NonNegativeFloatRange(lower_bound=0.0, upper_bound=0.0)
            },
        )

    def get_diffuser(self) -> GroverDiffuser:
        return GroverDiffuser(
            variables=self.oracle_params.variables(),
            state_preparation=self.state_preparation,
            state_preparation_params=self.state_preparation_params,
        )
oracle: str pydantic-field

Oracle function

oracle_params: OracleABC pydantic-field required

Oracle function parameters

state_preparation: str pydantic-field

State preparation function

state_preparation_params: Union[classiq.interface.generator.state_preparation.state_preparation.StatePreparation, classiq.interface.generator.user_defined_function_params.CustomFunction] pydantic-field

State preparation function parameters

hamiltonian_evolution special

exponentiation
Exponentiation (HamiltonianEvolution) pydantic-model

Exponentiation of a Hermitian Pauli sum operator.

Source code in classiq/interface/generator/hamiltonian_evolution/exponentiation.py
class Exponentiation(HamiltonianEvolution):
    """
    Exponentiation of a Hermitian Pauli sum operator.
    """

    evolution_coefficient: float = pydantic.Field(
        default=1.0, description="A global coefficient multiplying the operator."
    )
    constraints: ExponentiationConstraints = pydantic.Field(
        default_factory=ExponentiationConstraints,
        description="Constraints for the exponentiation.",
    )
    optimization: ExponentiationOptimization = pydantic.Field(
        default=ExponentiationOptimization.MINIMIZE_DEPTH,
        description="What attribute to optimize.",
    )

    @pydantic.validator("pauli_operator")
    def _validate_is_hermitian(cls, pauli_operator: PauliOperator) -> PauliOperator:
        return operator.validate_operator_is_hermitian(pauli_operator)
constraints: ExponentiationConstraints pydantic-field

Constraints for the exponentiation.

evolution_coefficient: float pydantic-field

A global coefficient multiplying the operator.

optimization: ExponentiationOptimization pydantic-field

What attribute to optimize.

ExponentiationConstraints (BaseModel) pydantic-model
Source code in classiq/interface/generator/hamiltonian_evolution/exponentiation.py
class ExponentiationConstraints(pydantic.BaseModel):
    max_depth: Optional[pydantic.PositiveInt] = pydantic.Field(
        default=None, description="Maximum depth of the exponentiation circuit."
    )
    max_error: Optional[pydantic.PositiveFloat] = pydantic.Field(
        default=None,
        description="Maximum approximation error of the exponentiation circuit.",
    )

    class Config:
        frozen = True
max_depth: PositiveInt pydantic-field

Maximum depth of the exponentiation circuit.

max_error: PositiveFloat pydantic-field

Maximum approximation error of the exponentiation circuit.

hamiltonian_evolution
HamiltonianEvolution (FunctionParams, ABC) pydantic-model

Suzuki trotterization of a Hermitian operator

Source code in classiq/interface/generator/hamiltonian_evolution/hamiltonian_evolution.py
class HamiltonianEvolution(FunctionParams, ABC):
    """
    Suzuki trotterization of a Hermitian operator
    """

    pauli_operator: PauliOperator = pydantic.Field(
        description="A weighted sum of Pauli strings."
    )
    use_naive_evolution: bool = pydantic.Field(
        default=False, description="Whether to evolve the operator naively."
    )

    def _create_ios(self) -> None:
        self._inputs = {
            DEFAULT_INPUT_NAME: RegisterArithmeticInfo(
                size=self.pauli_operator.num_qubits
            )
        }
        self._outputs = {
            DEFAULT_OUTPUT_NAME: RegisterArithmeticInfo(
                size=self.pauli_operator.num_qubits
            )
        }
pauli_operator: PauliOperator pydantic-field required

A weighted sum of Pauli strings.

use_naive_evolution: bool pydantic-field

Whether to evolve the operator naively.

qdrift
QDrift (HamiltonianEvolution) pydantic-model

qDrift trotterization of a Hermitian operator; see https://arxiv.org/abs/1811.08017

Source code in classiq/interface/generator/hamiltonian_evolution/qdrift.py
class QDrift(HamiltonianEvolution):
    """
    qDrift trotterization of a Hermitian operator; see https://arxiv.org/abs/1811.08017
    """

    evolution_coefficient: ParameterFloatType = pydantic.Field(
        default=1.0,
        description="A global coefficient multiplying the operator.",
        is_exec_param=True,
    )
    num_qdrift: pydantic.PositiveInt = pydantic.Field(
        description="The number of elements in the qDrift product.",
    )

    @pydantic.validator("pauli_operator")
    def _validate_is_hermitian(cls, pauli_operator: PauliOperator) -> PauliOperator:
        return operator.validate_operator_is_hermitian(pauli_operator)
evolution_coefficient: Union[float, str] pydantic-field

A global coefficient multiplying the operator.

num_qdrift: PositiveInt pydantic-field required

The number of elements in the qDrift product.

suzuki_trotter
SuzukiParameters (BaseModel) pydantic-model
Source code in classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py
class SuzukiParameters(pydantic.BaseModel):
    order: pydantic.PositiveInt = pydantic.Field(
        default=1,
        description="The order of the Suzuki-Trotter. Supports only order equals to 1 or an even number",
    )
    repetitions: pydantic.NonNegativeInt = pydantic.Field(
        default=1, description="The number of repetitions in the Suzuki-Trotter"
    )

    @pydantic.validator("order")
    def _validate_order(cls, order: int) -> int:
        if order != 1 and order % 2:
            raise ClassiqValueError(
                f"Odd order greater than 1 is not supported. Got {order}"
            )
        return order

    class Config:
        frozen = True
order: PositiveInt pydantic-field

The order of the Suzuki-Trotter. Supports only order equals to 1 or an even number

repetitions: NonNegativeInt pydantic-field

The number of repetitions in the Suzuki-Trotter

SuzukiTrotter (HamiltonianEvolution) pydantic-model

Suzuki trotterization of a Hermitian operator

Source code in classiq/interface/generator/hamiltonian_evolution/suzuki_trotter.py
class SuzukiTrotter(HamiltonianEvolution):
    """
    Suzuki trotterization of a Hermitian operator
    """

    evolution_coefficient: ParameterFloatType = pydantic.Field(
        default=1.0,
        description="A global coefficient multiplying the operator.",
        is_exec_param=True,
    )
    suzuki_parameters: SuzukiParameters = pydantic.Field(
        default_factory=SuzukiParameters, description="The Suziki parameters."
    )
    disable_scheduling: bool = pydantic.Field(
        default=False, description="Whether to disable the reordering of Pauli terms."
    )

    @pydantic.validator("pauli_operator")
    def _validate_no_complex_coefficients(
        cls, pauli_operator: PauliOperator
    ) -> PauliOperator:
        return operator.validate_operator_has_no_complex_coefficients(pauli_operator)
disable_scheduling: bool pydantic-field

Whether to disable the reordering of Pauli terms.

evolution_coefficient: Union[float, str] pydantic-field

A global coefficient multiplying the operator.

suzuki_parameters: SuzukiParameters pydantic-field

The Suziki parameters.

hardware special

hardware_data
HardwareData (BaseModel) pydantic-model
Source code in classiq/interface/generator/hardware/hardware_data.py
class HardwareData(pydantic.BaseModel):
    basis_gates: List[str] = pydantic.Field(
        default=list(),
        description="The basis gates of the hardware. "
        "This set will be used during the model optimization. "
        "If none given, use default values: "
        f"If no connectivity map is given or the connectivity map is symmetric - {sorted(DEFAULT_BASIS_GATES)}. "
        f"If a non-symmetric connectivity map is given - {sorted(DEFAULT_ROUTING_BASIS_GATES)}. ",
    )
    connectivity_map: Optional[ConnectivityMap] = pydantic.Field(
        default=None,
        description="Qubit connectivity map, in the form [ [q0, q1], [q1, q2],...]. "
        "If none given, assume the hardware is fully connected",
    )
    is_symmetric_connectivity: bool = pydantic.Field(
        default=True,
        description="Assumes that the coupling map forms an undirected graph, "
        "so for every qubit pair [q0, q1], both qubits can act as control and target. "
        "If false, the first / second qubit denotes the control / target, respectively",
    )

    @pydantic.validator("connectivity_map")
    def _validate_connectivity_map(
        cls, connectivity_map: Optional[ConnectivityMap]
    ) -> Optional[ConnectivityMap]:
        if connectivity_map is None:
            return connectivity_map
        if not connectivity_map:
            raise ClassiqValueError("Connectivity map cannot be empty")
        connectivity_map = _reindex_qubits(connectivity_map)
        return connectivity_map

    @pydantic.root_validator()
    def _symmetrize_connectivity_map(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        connectivity_map = values.get("connectivity_map")
        if connectivity_map is None:
            return values

        is_symmetric = values.get("is_symmetric_connectivity")
        if is_symmetric:
            connectivity_map = _symmetrize_connectivity_map(connectivity_map)
            values["connectivity_map"] = connectivity_map

        if not _is_connected_map(connectivity_map):
            raise ClassiqValueError(
                f"Connectivity map must be connected: {connectivity_map} is not connected."
            )
        return values

    @pydantic.root_validator()
    def _validate_basis_gates(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        connectivity_map = values.get("connectivity_map")
        specified_basis_gates = values.get("basis_gates", [])
        if connectivity_map is None:
            values["basis_gates"] = specified_basis_gates or list(DEFAULT_BASIS_GATES)
            return values

        is_symmetric_connectivity = values.get("is_symmetric")
        if is_symmetric_connectivity or _check_symmetry(connectivity_map):
            values["basis_gates"] = specified_basis_gates or list(DEFAULT_BASIS_GATES)
            return values

        values["basis_gates"] = specified_basis_gates or list(
            DEFAULT_ROUTING_BASIS_GATES
        )
        invalid_gates = [
            gate
            for gate in specified_basis_gates
            if gate in TWO_QUBIT_GATES and gate not in ROUTING_TWO_QUBIT_BASIS_GATES
        ]
        if invalid_gates:
            raise ClassiqValueError(
                "Connectivity-aware synthesis with non-symmetric coupling map "
                "is currently supported for the following two-qubit gates only: cx, ecr, rzx."
            )

        return values
basis_gates: List[str] pydantic-field

The basis gates of the hardware. This set will be used during the model optimization. If none given, use default values: If no connectivity map is given or the connectivity map is symmetric - ['cx', 'cy', 'cz', 'h', 'id', 'p', 'r', 'rx', 'ry', 'rz', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg', 'u', 'u1', 'u2', 'x', 'y', 'z']. If a non-symmetric connectivity map is given - ['cx', 'h', 'id', 'p', 'r', 'rx', 'ry', 'rz', 's', 'sdg', 'sx', 'sxdg', 't', 'tdg', 'u', 'u1', 'u2', 'x', 'y', 'z'].

connectivity_map: List[types.ConstrainedListValue] pydantic-field

Qubit connectivity map, in the form [ [q0, q1], [q1, q2],...]. If none given, assume the hardware is fully connected

is_symmetric_connectivity: bool pydantic-field

Assumes that the coupling map forms an undirected graph, so for every qubit pair [q0, q1], both qubits can act as control and target. If false, the first / second qubit denotes the control / target, respectively

hardware_efficient_ansatz

HardwareEfficientAnsatz (FunctionParams) pydantic-model
Source code in classiq/interface/generator/hardware_efficient_ansatz.py
class HardwareEfficientAnsatz(function_params.FunctionParams):
    connectivity_map: ConnectivityMapType = pydantic.Field(
        default=None,
        description="Hardware's connectivity map, in the form [ [x0, x1], [x1, x2],...]. "
        "If none specified - use connectivity map from the model hardware settings. "
        "If none specified as well, all qubit pairs will be connected.",
    )
    num_qubits: pydantic.PositiveInt = pydantic.Field(
        default=None,
        description="Number of qubits in the ansatz.",
    )
    reps: pydantic.PositiveInt = pydantic.Field(
        default=1, description="Number of layers in the Ansatz"
    )

    one_qubit_gates: Union[str, List[str]] = pydantic.Field(
        default=["x", "ry"],
        description='List of gates for the one qubit gates layer, e.g. ["x", "ry"]',
    )
    two_qubit_gates: Union[str, List[str]] = pydantic.Field(
        default=["cx"],
        description='List of gates for the two qubit gates entangling layer, e.g. ["cx", "cry"]',
    )
    parameter_prefix: str = pydantic.Field(
        default="param_",
        description="Prefix for the generated parameters",
    )

    @pydantic.validator("num_qubits", pre=True, always=True)
    def validate_num_qubits(
        cls, num_qubits: Optional[pydantic.PositiveInt], values: Dict[str, Any]
    ) -> pydantic.PositiveInt:
        connectivity_map = values.get("connectivity_map")
        conn_map_is_not_list = (
            isinstance(connectivity_map, SupportedConnectivityMaps)
            or connectivity_map is None
        )

        if num_qubits is None and conn_map_is_not_list:
            raise ClassiqValueError(_NUM_QUBITS_NOT_PROVIDED_ERROR)
        if num_qubits is None:
            if conn_map_is_not_list:
                raise ValueError(_NUM_QUBITS_NOT_PROVIDED_ERROR)

            if TYPE_CHECKING:
                assert connectivity_map is not None

            return len(set(itertools.chain.from_iterable(connectivity_map)))

        if conn_map_is_not_list:
            return num_qubits

        if TYPE_CHECKING:
            assert connectivity_map is not None

        invalid_qubits = {
            qubit
            for qubit in itertools.chain.from_iterable(connectivity_map)
            if qubit >= num_qubits
        }
        if invalid_qubits:
            raise ClassiqValueError(
                f"Invalid qubits: {invalid_qubits} "
                f"out of range specified by num_qubits: [0, {num_qubits - 1}]"
            )
        return num_qubits

    @pydantic.validator("one_qubit_gates")
    def validate_one_qubit_gates(
        cls, one_qubit_gates: Union[str, List[str]]
    ) -> Union[str, List[str]]:
        one_qubit_gates_list = (
            [one_qubit_gates] if isinstance(one_qubit_gates, str) else one_qubit_gates
        )
        for one_qubit_gate in one_qubit_gates_list:
            if one_qubit_gate not in SINGLE_QUBIT_GATES:
                raise ClassiqValueError(f"Invalid one qubit gate: {one_qubit_gate}")
        return one_qubit_gates

    @pydantic.validator("two_qubit_gates")
    def validate_two_qubit_gates(
        cls, two_qubit_gates: Union[str, List[str]]
    ) -> Union[str, List[str]]:
        two_qubit_gates_list = (
            [two_qubit_gates] if isinstance(two_qubit_gates, str) else two_qubit_gates
        )
        for two_qubit_gate in two_qubit_gates_list:
            if two_qubit_gate not in TWO_QUBIT_GATES:
                raise ClassiqValueError(f"Invalid two qubit gate: {two_qubit_gate}")
        return two_qubit_gates

    def _create_ios(self) -> None:
        self._inputs = {
            DEFAULT_INPUT_NAME: RegisterUserInput(
                name=DEFAULT_INPUT_NAME, size=self.num_qubits
            )
        }
        self._outputs = {
            DEFAULT_OUTPUT_NAME: RegisterUserInput(
                name=DEFAULT_OUTPUT_NAME, size=self.num_qubits
            )
        }
connectivity_map: Union[List[types.ConstrainedListValue], classiq.interface.generator.hardware_efficient_ansatz.SupportedConnectivityMaps] pydantic-field

Hardware's connectivity map, in the form [ [x0, x1], [x1, x2],...]. If none specified - use connectivity map from the model hardware settings. If none specified as well, all qubit pairs will be connected.

num_qubits: PositiveInt pydantic-field

Number of qubits in the ansatz.

one_qubit_gates: Union[str, List[str]] pydantic-field

List of gates for the one qubit gates layer, e.g. ["x", "ry"]

parameter_prefix: str pydantic-field

Prefix for the generated parameters

reps: PositiveInt pydantic-field

Number of layers in the Ansatz

two_qubit_gates: Union[str, List[str]] pydantic-field

List of gates for the two qubit gates entangling layer, e.g. ["cx", "cry"]

hva

HVA (ChemistryFunctionParams) pydantic-model

Hamiltonian Variational Ansatz

Source code in classiq/interface/generator/hva.py
class HVA(ChemistryFunctionParams):
    """
    Hamiltonian Variational Ansatz
    """

    reps: pydantic.PositiveInt = pydantic.Field(
        default=1, description="Number of layers in the Ansatz"
    )
    use_naive_evolution: bool = pydantic.Field(
        default=False, description="Whether to evolve the operator naively"
    )
    parameter_prefix: str = pydantic.Field(
        default="param_",
        description="Prefix for the generated parameters",
    )
parameter_prefix: str pydantic-field

Prefix for the generated parameters

reps: PositiveInt pydantic-field

Number of layers in the Ansatz

use_naive_evolution: bool pydantic-field

Whether to evolve the operator naively

identity

Identity (FunctionParams) pydantic-model
Source code in classiq/interface/generator/identity.py
class Identity(FunctionParams):
    arguments: NonEmptyRegisterUserInputList = pydantic.Field(
        description="registers describing the state (ordered)"
    )

    @pydantic.validator("arguments")
    def _validate_argument_names(
        cls, arguments: List[RegisterUserInput]
    ) -> List[RegisterUserInput]:
        return [
            arg if arg.name else arg.revalued(name=cls._get_default_arg_name(index))
            for index, arg in enumerate(arguments)
        ]

    def _create_ios(self) -> None:
        self._inputs = {arg.name: arg for arg in self.arguments}
        self._outputs = {arg.name: arg for arg in self.arguments}

    @staticmethod
    def _get_default_arg_name(index: int) -> str:
        return f"arg_{index}"

    def get_power_order(self) -> int:
        return 1
arguments: ConstrainedListValue pydantic-field required

registers describing the state (ordered)

inequality_mixer

InequalityMixer (FunctionParams) pydantic-model

Mixing a fixed point number variable below a given upper bound or above a given lower bound. i.e. after applying this function the variable will hold a superposition position of all the valid values.

Source code in classiq/interface/generator/inequality_mixer.py
class InequalityMixer(function_params.FunctionParams):
    """
    Mixing a fixed point number variable below a given upper bound or above a given
    lower bound. i.e. after applying this function the variable will hold a
    superposition position of all the valid values.
    """

    data_reg_input: RegisterArithmeticInfo = pydantic.Field(
        description="The input variable to mix."
    )

    bound_reg_input: RegisterOrConst = pydantic.Field(
        description="Fixed number or variable that define the upper or lower bound for"
        " the mixing operation. In case of a fixed number bound, the value"
        " must be positive."
    )

    mixer_parameter: ParameterFloatType = pydantic.Field(
        description="The parameter used for rotation gates in the mixer.",
        is_exec_param=True,
    )

    is_less_inequality: bool = pydantic.Field(
        default=True,
        description="Whether to mix below or above a certain bound."
        "Less inequality mixes between 0 and the given bound."
        "Greater inequality mixes between the bound and the maximal number allowed by"
        " the number of qubits (i.e 2^n - 1).",
    )

    def _create_ios(self) -> None:
        self._inputs = {DATA_REG_INPUT_NAME: self.data_reg_input}
        self._outputs = {DATA_REG_OUTPUT_NAME: self.data_reg_input}

        if isinstance(self.bound_reg_input, RegisterArithmeticInfo):
            self._inputs[BOUND_REG_INPUT_NAME] = self.bound_reg_input
            self._outputs[BOUND_REG_OUTPUT_NAME] = self.bound_reg_input
bound_reg_input: Union[classiq.interface.generator.arith.register_user_input.RegisterArithmeticInfo, float] pydantic-field required

Fixed number or variable that define the upper or lower bound for the mixing operation. In case of a fixed number bound, the value must be positive.

data_reg_input: RegisterArithmeticInfo pydantic-field required

The input variable to mix.

is_less_inequality: bool pydantic-field

Whether to mix below or above a certain bound.Less inequality mixes between 0 and the given bound.Greater inequality mixes between the bound and the maximal number allowed by the number of qubits (i.e 2^n - 1).

mixer_parameter: Union[float, str] pydantic-field required

The parameter used for rotation gates in the mixer.

linear_pauli_rotations

LinearPauliRotations (FunctionParams) pydantic-model

Perform independent linear rotations on target qubits, each controlled by an identical n-qubit state register |x>.

Each target qubit, indexed with k and denoted by q_k, undergoes the following transformation: |x>|q_k> -> |x> * [cos(theta(x,k)/2) + isin(theta(x,k)/2)sigma]|q_k> with sigma being 'X', 'Y' or 'Z' Pauli matrix, and the angle is a linear function of the state, theta(x,k)/2 = (slope(k)*x + offset(k))/2.

For example, a 'Y' rotation on one target qubit will result in a circuit implementing the following logic: |x>|0> -> cos((slopex + offset)/2)|x>|0> + sin((slopex + offset)/2)|x>|1>

    !!! q_0 "─────────────────────────■───────── ... ──────────────────────"
                                  │
                                  .
                                  │
q_(n-1): ─────────────────────────┼───────── ... ───────────■──────────
          ┌────────────┐  ┌───────┴───────┐       ┌─────────┴─────────┐
 !!! target "─┤ RY(offset) ├──┤ RY(2^0 slope) ├  ...  ┤ RY(2^(n-1) slope) ├"
          └────────────┘  └───────────────┘       └───────────────────┘
Source code in classiq/interface/generator/linear_pauli_rotations.py
class LinearPauliRotations(function_params.FunctionParams):
    """
    Perform independent linear rotations on target qubits, each controlled by an identical
    n-qubit state register |x>.

    Each target qubit, indexed with k and denoted by q_k, undergoes the following transformation:
    |x>|q_k> -> |x> * [cos(theta(x,k)/2) + i*sin(theta(x,k)/2)*sigma]|q_k>
    with sigma being 'X', 'Y' or 'Z' Pauli matrix, and the angle is a linear function of the state,
    theta(x,k)/2 = (slope(k)*x + offset(k))/2.

    For example, a 'Y' rotation on one target qubit will result in a circuit implementing the following logic:
    |x>|0> -> cos((slope*x + offset)/2)|x>|0> + sin((slope*x + offset)/2)|x>|1>

            q_0: ─────────────────────────■───────── ... ──────────────────────

                                          .

        q_(n-1): ─────────────────────────┼───────── ... ───────────■──────────
                  ┌────────────┐  ┌───────┴───────┐       ┌─────────┴─────────┐
         target: ─┤ RY(offset) ├──┤ RY(2^0 slope) ├  ...  ┤ RY(2^(n-1) slope) ├
                  └────────────┘  └───────────────┘       └───────────────────┘
    """

    num_state_qubits: pydantic.PositiveInt = pydantic.Field(
        description="The number of input qubits"
    )
    bases: List[PydanticPauliBasisStr] = pydantic.Field(
        description="The types of Pauli rotations ('X', 'Y', 'Z')."
    )
    slopes: List[float] = pydantic.Field(
        description="The slopes of the controlled rotations."
    )
    offsets: List[float] = pydantic.Field(
        description="The offsets of the controlled rotations."
    )

    @pydantic.validator("bases", "slopes", "offsets", pre=True, always=True)
    def as_list(cls, v: Any) -> List[Any]:
        if not isinstance(v, list):
            v = [v]
        return v

    @pydantic.root_validator()
    def validate_lists(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        offsets = values.get("offsets", list())
        bases = values.get("bases", list())
        slopes = values.get("slopes", list())
        if len(slopes) == len(offsets) and len(offsets) == len(bases):
            return values
        raise ClassiqValueError(LENGTH_ERROR_MESSAGE)

    def _create_ios(self) -> None:
        self._inputs = {
            STATE: RegisterArithmeticInfo(size=self.num_state_qubits),
            TARGET: RegisterArithmeticInfo(size=len(self.bases)),
        }
        self._outputs = {**self.inputs}
bases: List[classiq.interface.generator.linear_pauli_rotations.ConstrainedStrValue] pydantic-field required

The types of Pauli rotations ('X', 'Y', 'Z').

num_state_qubits: PositiveInt pydantic-field required

The number of input qubits

offsets: List[float] pydantic-field required

The offsets of the controlled rotations.

slopes: List[float] pydantic-field required

The slopes of the controlled rotations.

mcu

Mcu (FunctionParams) pydantic-model

Multi-controlled u-gate. Based on U(theta, phi, lam, gam) = e^(i*(gam + (phi + lam)/2)) * RZ(phi) * RY(theta) * RZ(lam) For a general gate U, four angles are required - theta, phi, lambda and gam.

U(gam, phi,theta, lam) = e^(igam) * cos(theta/2) & -e^(ilam)sin(theta/2) \ e^(iphi)sin(theta/2) & e^(i(phi+lam))*cos(theta/2) \

U(gam, phi,theta, lam) = e^(igam) * cos(theta/2) & -e^(ilam)sin(theta/2) \ e^(iphi)sin(theta/2) & e^(i(phi+lam))*cos(theta/2) \

Source code in classiq/interface/generator/mcu.py
class Mcu(FunctionParams):
    """
    Multi-controlled u-gate.
    Based on U(theta, phi, lam, gam) = e^(i*(gam + (phi + lam)/2)) * RZ(phi) * RY(theta) * RZ(lam)
    For a general gate U, four angles are required - theta, phi, lambda and gam.

    U(gam, phi,theta, lam) =
    e^(i*gam) *
    cos(theta/2) & -e^(i*lam)*sin(theta/2) \\
    e^(i*phi)*sin(theta/2) & e^(i*(phi+lam))*cos(theta/2) \\

    U(gam, phi,theta, lam) =
    e^(i*gam) *
    cos(theta/2)            &    -e^(i*lam)*sin(theta/2) \\
    e^(i*phi)*sin(theta/2)  &    e^(i*(phi+lam))*cos(theta/2) \\
    """

    theta: ParameterFloatType = pydantic.Field(
        default=0, description="Theta radian angle.", is_exec_param=True
    )
    phi: ParameterFloatType = pydantic.Field(
        default=0, description="Phi radian angle.", is_exec_param=True
    )
    lam: ParameterFloatType = pydantic.Field(
        default=0, description="Lambda radian angle.", is_exec_param=True
    )
    gam: ParameterFloatType = pydantic.Field(
        default=0, description="gam radian angle.", is_exec_param=True
    )

    num_ctrl_qubits: Optional[pydantic.PositiveInt] = pydantic.Field(
        default=None, description="The number of control qubits."
    )
    ctrl_state: Optional[str] = pydantic.Field(
        default=None, description="string of the control state"
    )

    @pydantic.root_validator()
    def _validate_control(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        num_ctrl_qubits = values.get("num_ctrl_qubits")
        ctrl_state = values.get("ctrl_state")

        if ctrl_state is not None:
            ctrl_state = cast(str, ctrl_state)
            ControlState.validate_control_string(ctrl_state)

        if ctrl_state is None and num_ctrl_qubits is None:
            raise ClassiqValueError("num_ctrl_qubits or ctrl_state must exist.")

        if ctrl_state is None and num_ctrl_qubits is not None:
            values["ctrl_state"] = "1" * num_ctrl_qubits
            ctrl_state = values["ctrl_state"]

        if num_ctrl_qubits is None and ctrl_state is not None:
            num_ctrl_qubits = len(ctrl_state)
            values["num_ctrl_qubits"] = num_ctrl_qubits

        if len(ctrl_state) != num_ctrl_qubits:
            raise ClassiqValueError(
                "control state length should be equal to the number of control qubits"
            )

        return values

    def _create_ios(self) -> None:
        if self.num_ctrl_qubits is None:
            raise ClassiqValueError("num_ctrl_qubits must have a valid value.")
        ctrl_register = RegisterUserInput(size=self.num_ctrl_qubits, name=CTRL)
        target_register = RegisterUserInput(size=1, name=TARGET)
        self._inputs = {reg.name: reg for reg in (ctrl_register, target_register)}
        self._outputs = {reg.name: reg for reg in (ctrl_register, target_register)}
ctrl_state: str pydantic-field

string of the control state

gam: Union[float, str] pydantic-field

gam radian angle.

lam: Union[float, str] pydantic-field

Lambda radian angle.

num_ctrl_qubits: PositiveInt pydantic-field

The number of control qubits.

phi: Union[float, str] pydantic-field

Phi radian angle.

theta: Union[float, str] pydantic-field

Theta radian angle.

mcx

Mcx (FunctionParams) pydantic-model

multi-controlled x-gate

Source code in classiq/interface/generator/mcx.py
class Mcx(FunctionParams):
    """
    multi-controlled x-gate
    """

    arguments: List[RegisterUserInput] = pydantic.Field(
        default_factory=list, description="registers describing the state (ordered)"
    )
    num_ctrl_qubits: Optional[pydantic.PositiveInt] = pydantic.Field(
        description="number of control qubits"
    )
    ctrl_state: str = pydantic.Field(default="", description="control state string")

    @pydantic.validator("arguments", always=True)
    def _validate_argument_names(
        cls, arguments: List[RegisterUserInput]
    ) -> List[RegisterUserInput]:
        register_name_list: List[Optional[str]] = [arg.name for arg in arguments]
        if None in register_name_list:
            raise ClassiqValueError("All registers must be named")
        if len(set(register_name_list)) != len(register_name_list):
            raise ClassiqValueError("Registers must have distinct names")
        return arguments

    @pydantic.validator("num_ctrl_qubits", always=True)
    def _validate_sizes(cls, num_ctrl_qubits: int, values: Dict[str, Any]) -> int:
        arguments_size = sum(arg.size for arg in values.get("arguments", list()))

        if not num_ctrl_qubits:
            num_ctrl_qubits = arguments_size - 1

        if num_ctrl_qubits < 1:
            raise ClassiqValueError("Must have control qubits")

        if arguments_size == 0:
            ctrl_register = RegisterUserInput(size=num_ctrl_qubits, name=CTRL)
            target_register = RegisterUserInput(size=1, name=TARGET_QUBIT)
            values["arguments"] = [ctrl_register, target_register]
        elif num_ctrl_qubits != arguments_size - 1:
            raise ClassiqValueError("Given sizes do not match")
        return num_ctrl_qubits

    @pydantic.validator("ctrl_state", always=True)
    def _validate_ctrl_state(cls, ctrl_state: str, values: Dict[str, Any]) -> str:
        num_ctrl_qubits = values.get("num_ctrl_qubits", -1)
        if not ctrl_state:
            return "1" * num_ctrl_qubits
        if len(ctrl_state) != num_ctrl_qubits:
            raise ClassiqValueError(
                "control state length should be equal to the number of control qubits"
            )
        ControlState.validate_control_string(ctrl_state)
        return ctrl_state

    def _create_ios(self) -> None:
        self._inputs = {arg.name: arg for arg in self.arguments}
        self._outputs = {arg.name: arg for arg in self.arguments}

    def get_power_order(self) -> int:
        return 2
arguments: List[classiq.interface.generator.arith.register_user_input.RegisterUserInput] pydantic-field

registers describing the state (ordered)

ctrl_state: str pydantic-field

control state string

num_ctrl_qubits: PositiveInt pydantic-field

number of control qubits

model special

constraints
Constraints (BaseModel) pydantic-model

Input constraints for the generated quantum circuit.

Source code in classiq/interface/generator/model/constraints.py
class Constraints(BaseModel, extra=Extra.forbid):
    """
    Input constraints for the generated quantum circuit.
    """

    max_width: Optional[pydantic.PositiveInt] = pydantic.Field(
        default=None,
        description="Maximum number of qubits in generated quantum circuit",
    )
    max_depth: Optional[pydantic.PositiveInt] = None

    max_gate_count: Dict[TranspilerBasisGates, pydantic.NonNegativeInt] = (
        pydantic.Field(default_factory=lambda: defaultdict(int))
    )

    optimization_parameter: OptimizationParameterType = pydantic.Field(
        default=OptimizationParameter.NO_OPTIMIZATION,
        description="If set, the synthesis engine optimizes the solution"
        " according to that chosen parameter",
    )
max_width: PositiveInt pydantic-field

Maximum number of qubits in generated quantum circuit

optimization_parameter: Union[classiq.interface.generator.model.constraints.OptimizationParameter, classiq.interface.generator.transpiler_basis_gates.TranspilerBasisGates] pydantic-field

If set, the synthesis engine optimizes the solution according to that chosen parameter

model
ClassiqBaseModel (VersionedModel, ABC) pydantic-model

All the relevant data for evaluating execution in one place.

Source code in classiq/interface/generator/model/model.py
class ClassiqBaseModel(VersionedModel, ABC):
    """
    All the relevant data for evaluating execution in one place.
    """

    types: List[StructDeclaration] = pydantic.Field(
        default_factory=list,
        description="The user-defined custom function library.",
    )

    constants: List[Constant] = pydantic.Field(
        default_factory=list,
    )

    classical_execution_code: str = pydantic.Field(
        description="The classical execution code of the model", default=""
    )

    execution_preferences: ExecutionPreferences = pydantic.Field(
        default_factory=ExecutionPreferences
    )

    @pydantic.validator("types")
    def types_validator(cls, types: List[StructDeclaration]) -> List[StructDeclaration]:
        if not is_list_unique([struct_type.name for struct_type in types]):
            raise ClassiqValueError(TYPE_LIBRARY_DUPLICATED_TYPE_NAMES)

        return types
classical_execution_code: str pydantic-field

The classical execution code of the model

types: List[classiq.interface.generator.types.struct_declaration.StructDeclaration] pydantic-field

The user-defined custom function library.

__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

ExecutionModel (ClassiqBaseModel) pydantic-model
Source code in classiq/interface/generator/model/model.py
class ExecutionModel(ClassiqBaseModel):
    circuit_outputs: ArithmeticIODict = pydantic.Field(
        description="Mapping between a measured register name and its arithmetic type",
        default_factory=dict,
    )
circuit_outputs: Dict[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue, classiq.interface.generator.arith.register_user_input.RegisterArithmeticInfo] pydantic-field

Mapping between a measured register name and its arithmetic type

__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

SynthesisModel (ClassiqBaseModel) pydantic-model

All the relevant data for generating quantum circuit in one place.

Source code in classiq/interface/generator/model/model.py
class SynthesisModel(ClassiqBaseModel):
    """
    All the relevant data for generating quantum circuit in one place.
    """

    kind: Literal["synthesis"] = pydantic.Field(default="synthesis")

    # Must be validated before logic_flow
    functions: List[ConcreteFunctionDefinition] = pydantic.Field(
        default_factory=_create_default_functions,
        description="The quantum functions of the model.",
    )

    constraints: Constraints = pydantic.Field(default_factory=Constraints)
    preferences: Preferences = pydantic.Field(default_factory=Preferences)

    def __init__(
        self,
        *,
        body: Optional[List[SynthesisQuantumFunctionCall]] = None,
        inputs: Optional[WireDict] = None,
        outputs: Optional[WireDict] = None,
        **kwargs: Any,
    ) -> None:
        super().__init__(**kwargs)
        if body:
            self.main_func.body.extend(body)
        if inputs:
            self.set_inputs(
                {
                    name: QRegGenericAlias(
                        QReg(DEFAULT_PORT_SIZE), (DEFAULT_PORT_SIZE, 0)
                    )
                    for name in inputs.keys()
                },
                inputs,
            )
        if outputs:
            self.set_outputs(
                {name: QReg(DEFAULT_PORT_SIZE) for name in outputs.keys()}, outputs
            )

    @property
    def main_func(self) -> SynthesisNativeFunctionDefinition:
        return self.function_dict[MAIN_FUNCTION_NAME]  # type:ignore[return-value]

    @property
    def body(self) -> List[SynthesisQuantumFunctionCall]:
        return self.main_func.body

    @property
    def inputs(self) -> WireDict:
        return self.main_func.input_ports_wiring

    def set_inputs(
        self,
        inputs: Mapping[IOName, QRegGenericAlias],
        input_wiring: Mapping[IOName, WireName],
    ) -> None:
        self._update_main_declarations(inputs, PortDeclarationDirection.Input)
        self.main_func.input_ports_wiring.update(input_wiring)

    @property
    def outputs(self) -> WireDict:
        return self.main_func.output_ports_wiring

    def set_outputs(
        self, outputs: Mapping[IOName, QReg], output_wiring: Mapping[IOName, WireName]
    ) -> None:
        self._update_main_declarations(outputs, PortDeclarationDirection.Output)
        self.main_func.output_ports_wiring.update(output_wiring)

    @pydantic.validator("preferences", always=True)
    def _seed_suffix_randomizer(cls, preferences: Preferences) -> Preferences:
        SUFFIX_RANDOMIZER.seed(preferences.random_seed)
        return preferences

    def _get_qualified_direction(
        self, port_name: str, direction: PortDeclarationDirection
    ) -> PortDeclarationDirection:
        if port_name in self.main_func.port_declarations:
            return PortDeclarationDirection.Inout
        return direction

    def _update_main_declarations(
        self,
        value: Union[Mapping[IOName, QReg], Mapping[IOName, QRegGenericAlias]],
        direction: PortDeclarationDirection,
    ) -> None:
        for port_name, register in value.items():
            if isinstance(register, QReg):
                size = len(register)
                is_signed = getattr(register, "is_signed", False) or False
                fraction_places = getattr(register, "fraction_places", 0) or 0
            else:
                size = register.size if register.size is not None else DEFAULT_PORT_SIZE
                is_signed = False
                fraction_places = (
                    register.fraction_places
                    if register.fraction_places is not None
                    else 0
                )

            self.main_func.port_declarations[port_name] = SynthesisPortDeclaration(
                name=port_name,
                size=size,
                direction=self._get_qualified_direction(port_name, direction),
                is_signed=is_signed,
                fraction_places=fraction_places,
            )

    @property
    def function_dict(self) -> Dict[str, SynthesisQuantumFunctionDeclaration]:
        return nameables_to_dict(self.functions)

    @pydantic.validator("functions", each_item=True)
    def validate_static_correctness(
        cls, func_def: ConcreteFunctionDefinition
    ) -> ConcreteFunctionDefinition:
        if isinstance(func_def, SynthesisNativeFunctionDefinition):
            func_def.validate_body()
        return func_def

    @pydantic.validator("functions")
    def validate_main_function_exists(
        cls, func_defs: List[ConcreteFunctionDefinition]
    ) -> List[ConcreteFunctionDefinition]:
        if MAIN_FUNCTION_NAME not in {func.name for func in func_defs}:
            raise ClassiqValueError("The model must contain a `main` function")
        return func_defs

    def get_model(self) -> SerializedModel:
        return SerializedModel(self.json(exclude_defaults=True, indent=2))

    def classical_model(self) -> ExecutionModel:
        return ExecutionModel(
            types=self.types,
            constants=self.constants,
            classical_execution_code=self.classical_execution_code,
            execution_preferences=self.execution_preferences,
            circuit_outputs=self.main_func.outputs,
        )
functions: List[Union[classiq.interface.generator.functions.foreign_function_definition.SynthesisForeignFunctionDefinition, classiq.interface.generator.functions.native_function_definition.SynthesisNativeFunctionDefinition]] pydantic-field

The quantum functions of the model.

__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

preferences special
preferences
Preferences (BaseModel) pydantic-model
Source code in classiq/interface/generator/model/preferences/preferences.py
class Preferences(pydantic.BaseModel, extra=pydantic.Extra.forbid):
    _backend_preferences: Optional[BackendPreferences] = pydantic.PrivateAttr(
        default=None
    )
    machine_precision: PydanticMachinePrecision = DEFAULT_MACHINE_PRECISION

    backend_service_provider: Optional[Union[Provider, ProviderVendor, str]] = (
        pydantic.Field(
            default=None,
            description="Provider company or cloud for the requested backend.",
        )
    )
    backend_name: Optional[Union[PydanticBackendName, AllBackendsNameByVendor]] = (
        pydantic.Field(
            default=None, description="Name of the requested backend or target."
        )
    )
    custom_hardware_settings: CustomHardwareSettings = pydantic.Field(
        default_factory=CustomHardwareSettings,
        description="Custom hardware settings which will be used during optimization. "
        "This field is ignored if backend preferences are given.",
    )
    debug_mode: bool = pydantic.Field(
        default=True,
        description="Add debug information to the synthesized result. "
        "Setting this option to False can potentially speed up the synthesis, and is "
        "recommended for executing iterative algorithms.",
    )
    output_format: PydanticConstrainedQuantumFormatList = pydantic.Field(
        default=[QuantumFormat.QASM],
        description="The quantum circuit output format(s). ",
    )

    pretty_qasm: bool = pydantic.Field(
        True,
        description="Prettify the OpenQASM2 outputs (use line breaks inside the gate "
        "declarations).",
    )

    qasm3: Optional[bool] = pydantic.Field(
        None,
        description="Output OpenQASM 3.0 instead of OpenQASM 2.0. Relevant only for "
        "the `qasm` and `transpiled_circuit.qasm` attributes of `GeneratedCircuit`.",
    )

    transpilation_option: TranspilationOption = pydantic.Field(
        default=TranspilationOption.AUTO_OPTIMIZE,
        description="If true, the returned result will contain a "
        "transpiled circuit and its depth",
    )

    timeout_seconds: pydantic.PositiveInt = pydantic.Field(
        default=300, description="Generation timeout in seconds"
    )

    optimization_timeout_seconds: Optional[pydantic.PositiveInt] = pydantic.Field(
        default=None,
        description="Optimization timeout in seconds, or None for no "
        "optimization timeout (will still timeout when the generation timeout is over)",
    )

    random_seed: int = pydantic.Field(
        default_factory=create_random_seed,
        description="The random seed used for the generation",
    )

    @pydantic.validator("backend_service_provider", pre=True)
    def validate_backend_service_provider(
        cls, backend_service_provider: Any
    ) -> Optional[Provider]:
        if backend_service_provider is None:
            return None
        return validate_backend_service_provider(backend_service_provider)

    @pydantic.validator("optimization_timeout_seconds")
    def optimization_timeout_less_than_generation_timeout(
        cls,
        optimization_timeout_seconds: Optional[pydantic.PositiveInt],
        values: Dict[str, Any],
    ) -> Optional[pydantic.PositiveInt]:
        generation_timeout_seconds = values.get("timeout_seconds")
        if generation_timeout_seconds is None or optimization_timeout_seconds is None:
            return optimization_timeout_seconds
        if optimization_timeout_seconds >= generation_timeout_seconds:
            raise ClassiqValueError(
                f"Generation timeout ({generation_timeout_seconds})"
                f"is greater than or equal to "
                f"optimization timeout ({optimization_timeout_seconds}) "
            )
        return optimization_timeout_seconds

    @pydantic.validator("output_format", pre=True)
    def make_output_format_list(cls, output_format: Any) -> List:
        if not pydantic.utils.sequence_like(output_format):
            output_format = [output_format]

        return output_format

    @pydantic.validator("output_format", always=True)
    def validate_output_format(
        cls, output_format: PydanticConstrainedQuantumFormatList, values: Dict[str, Any]
    ) -> PydanticConstrainedQuantumFormatList:
        if len(output_format) != len(set(output_format)):
            raise ClassiqValueError(
                f"output_format={output_format}\n"
                "has at least one format that appears twice or more"
            )

        service_provider = values.get("backend_service_provider")
        if service_provider is None:
            return output_format

        provider_format = _SERVICE_PROVIDER_TO_FORMAT.get(service_provider)
        if provider_format is not None and provider_format not in output_format:
            output_format.append(provider_format)

        return output_format

    @pydantic.root_validator()
    def validate_backend(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        backend_name = values.get("backend_name")
        backend_service_provider = values.get("backend_service_provider")
        if (backend_name is None) != (backend_service_provider is None):
            raise ClassiqValueError(BACKEND_VALIDATION_ERROR_MESSAGE)
        return values

    @property
    def backend_preferences(self) -> Optional[BackendPreferences]:
        if self.backend_name is None or self.backend_service_provider is None:
            return None
        if self._backend_preferences is None:
            self._backend_preferences = BackendPreferences(
                backend_name=self.backend_name,
                backend_service_provider=self.backend_service_provider,
            )
        return self._backend_preferences
backend_name: Union[classiq.interface.generator.model.preferences.preferences.ConstrainedStrValue, classiq.interface.backend.quantum_backend_providers.IBMQHardwareNames, classiq.interface.backend.quantum_backend_providers.AzureQuantumBackendNames, classiq.interface.backend.quantum_backend_providers.AmazonBraketBackendNames, classiq.interface.backend.quantum_backend_providers.IonqBackendNames, classiq.interface.backend.quantum_backend_providers.ClassiqNvidiaBackendNames, classiq.interface.backend.quantum_backend_providers.AliceBobBackendNames, classiq.interface.backend.quantum_backend_providers.OQCBackendNames] pydantic-field

Name of the requested backend or target.

backend_service_provider: Union[classiq.interface.hardware.Provider, classiq.interface.backend.quantum_backend_providers.ProviderVendor, str] pydantic-field

Provider company or cloud for the requested backend.

custom_hardware_settings: CustomHardwareSettings pydantic-field

Custom hardware settings which will be used during optimization. This field is ignored if backend preferences are given.

debug_mode: bool pydantic-field

Add debug information to the synthesized result. Setting this option to False can potentially speed up the synthesis, and is recommended for executing iterative algorithms.

optimization_timeout_seconds: PositiveInt pydantic-field

Optimization timeout in seconds, or None for no optimization timeout (will still timeout when the generation timeout is over)

output_format: ConstrainedListValue pydantic-field

The quantum circuit output format(s).

pretty_qasm: bool pydantic-field

Prettify the OpenQASM2 outputs (use line breaks inside the gate declarations).

qasm3: bool pydantic-field

Output OpenQASM 3.0 instead of OpenQASM 2.0. Relevant only for the qasm and transpiled_circuit.qasm attributes of GeneratedCircuit.

random_seed: int pydantic-field

The random seed used for the generation

timeout_seconds: PositiveInt pydantic-field

Generation timeout in seconds

transpilation_option: TranspilationOption pydantic-field

If true, the returned result will contain a transpiled circuit and its depth

noise_properties

NoiseProperties (BaseModel) pydantic-model
Source code in classiq/interface/generator/noise_properties.py
class NoiseProperties(BaseModel):
    measurement_bit_flip_probability: Optional[PydanticProbabilityFloat] = (
        pydantic.Field(
            default=None,
            description="Probability of measuring the wrong value for each qubit.",
        )
    )
measurement_bit_flip_probability: PydanticProbabilityFloat pydantic-field

Probability of measuring the wrong value for each qubit.

oracles special

custom_oracle
CustomOracle (OracleABC) pydantic-model
Source code in classiq/interface/generator/oracles/custom_oracle.py
class CustomOracle(OracleABC[QubitState]):
    custom_oracle: str = pydantic.Field(description="Oracle function")
    custom_oracle_params: CustomFunction = pydantic.Field(
        description="Oracle function parameters",
        default_factory=CustomFunction,
    )

    @pydantic.root_validator(pre=True)
    def _parse_oracle(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        parse_function_params_values(
            values=values,
            params_key="custom_oracle_params",
            discriminator_key="custom_oracle",
            param_classes={CustomFunction},
            default_parser_class=CustomFunction,
        )
        return values

    @pydantic.validator("custom_oracle_params")
    def _validate_names_match_oracle(
        cls, custom_oracle_params: CustomFunction
    ) -> CustomFunction:
        if set(custom_oracle_params.input_decls.keys()) != set(
            custom_oracle_params.output_decls.keys()
        ):
            raise ClassiqValueError("Oracle IO names must be identical")
        if any(
            custom_oracle_params.output_decls[name].size != input_decl.size
            for name, input_decl in custom_oracle_params.input_decls.items()
        ):
            raise ClassiqValueError("Oracle IO sizes must be identical")
        return custom_oracle_params

    def _get_register_transputs(self) -> ArithmeticIODict:
        return {**self.custom_oracle_params.input_decls}

    def binary_result_to_typed_result(
        self, bin_result: VariableBinResultMap
    ) -> VariableTypedResultMap[QubitState]:
        return bin_result

    def is_good_result(
        self, problem_result: VariableTypedResultMap[QubitState]
    ) -> bool:
        return True
custom_oracle: str pydantic-field required

Oracle function

custom_oracle_params: CustomFunction pydantic-field

Oracle function parameters

partitioned_register

PartitionedRegister dataclass

PartitionedRegister(name: str, num_qubits: int, partitions: Tuple[Tuple[int, ...], ...])

Source code in classiq/interface/generator/partitioned_register.py
@dataclass(frozen=True)
class PartitionedRegister:
    name: str

    # There are up to num_qubits qubits within the partitions, with unique values from 0 to num_qubits-1
    num_qubits: int
    partitions: Tuple[Tuple[int, ...], ...]

    def __post_init__(self) -> None:
        if not self.partitions:
            message = f"Error creating {self.name}. Must contain at least one partition"
            raise ClassiqValueError(message)

        if not all(self.partitions):
            message = f"Error creating {self.name}. Each partition must have at least one qubit"
            raise ClassiqValueError(message)

        partition_sets = [frozenset(part) for part in self.partitions]
        intersection = frozenset.intersection(*partition_sets)
        if len(self.partitions) > 1 and intersection:
            message = (
                f"Overlapping partitions in {self.name}. Intersection: {intersection}"
            )
            raise ClassiqValueError(message)

        union = frozenset.union(*partition_sets)
        possible_qubits = frozenset(range(self.num_qubits))
        if not union <= possible_qubits:
            message = f"Extra qubits in {self.name}: {union - possible_qubits}"
            raise ClassiqValueError(message)

    def get_partition(self, index: int) -> "RegisterPartition":
        return RegisterPartition(self, index)

    # Special partition containing qubits from [0..num_qubits) not in any other
    # partition. May contain no qubits.
    @property
    def leftover_partition(self) -> "RegisterPartition":
        return RegisterPartition(self, _index=None)

    @property
    def _leftover_qubits(self) -> Tuple[int, ...]:
        total_qubits = set(itertools.chain.from_iterable(self.partitions))
        return tuple(
            qubit for qubit in range(self.num_qubits) if qubit not in total_qubits
        )

    @property
    def all_qubits_in_partitions(self) -> Iterator[int]:
        return itertools.chain.from_iterable(self.partitions)

    def all_register_partitions(
        self, include_leftover_partition: bool = False
    ) -> List["RegisterPartition"]:
        all_partitions = [self.get_partition(i) for i in range(len(self.partitions))]
        if include_leftover_partition:
            all_partitions.append(self.leftover_partition)
        return all_partitions
RegisterPartition dataclass

RegisterPartition(partitioned_register: classiq.interface.generator.partitioned_register.PartitionedRegister, _index: Optional[int])

Source code in classiq/interface/generator/partitioned_register.py
@dataclass(frozen=True)
class RegisterPartition:
    partitioned_register: PartitionedRegister

    # index == None means this is the partition containing the leftover qubits.
    _index: Optional[int]

    def __post_init__(self) -> None:
        num_partitions = len(self.partitioned_register.partitions)
        if self._index is not None and (
            self._index >= num_partitions or self._index < 0
        ):
            message = f"Partition does not exist in {self.partitioned_register.name}. Index {self._index} not in range [0, {num_partitions})"
            raise ClassiqValueError(message)

    @property
    def qubits(self) -> Tuple[int, ...]:
        if self._index is None:
            return self.partitioned_register._leftover_qubits
        return self.partitioned_register.partitions[self._index]

    @property
    def _is_single_qubit(self) -> bool:
        return len(self.qubits) == 1

    # io_string is, for example, 'input' or 'foo[3:5]'
    def matches_string(self, io_string: str) -> bool:
        name, slice_ = parse_io_slicing(io_string)
        qubits = tuple(range(self.partitioned_register.num_qubits)[slice_])
        return self.partitioned_register.name == name and self.qubits == qubits

qft

QFT (FunctionParams) pydantic-model

Creates a quantum Fourier transform on a specified number of qubits.

Source code in classiq/interface/generator/qft.py
class QFT(FunctionParams):
    """
    Creates a quantum Fourier transform on a specified number of qubits.
    """

    num_qubits: pydantic.PositiveInt = pydantic.Field(
        description="The number of qubits on which the QFT acts."
    )
    approximation_degree: pydantic.NonNegativeInt = pydantic.Field(
        default=0,
        description="The degree of approximation (0 for no approximation). The smallest "
        "'approximation_degree' rotation angles are dropped from the QFT.",
    )
    do_swaps: bool = pydantic.Field(
        default=True, description="Whether to include the final swaps in the QFT."
    )

    def _create_ios(self) -> None:
        self._inputs = {
            DEFAULT_INPUT_NAME: RegisterArithmeticInfo(size=self.num_qubits)
        }
        self._outputs = {
            DEFAULT_OUTPUT_NAME: RegisterArithmeticInfo(size=self.num_qubits)
        }

    def get_power_order(self) -> int:
        return 4
approximation_degree: NonNegativeInt pydantic-field

The degree of approximation (0 for no approximation). The smallest 'approximation_degree' rotation angles are dropped from the QFT.

do_swaps: bool pydantic-field

Whether to include the final swaps in the QFT.

num_qubits: PositiveInt pydantic-field required

The number of qubits on which the QFT acts.

qpe

ExponentiationScaling (BaseModel) pydantic-model

Details of exponentiation scaling for phase estimation.

Source code in classiq/interface/generator/qpe.py
class ExponentiationScaling(pydantic.BaseModel):
    """
    Details of exponentiation scaling for phase estimation.
    """

    max_depth: pydantic.PositiveInt = pydantic.Field(
        description="The max_depth of the smallest exponentiation",
    )
    max_depth_scaling_factor: pydantic.NonNegativeFloat = pydantic.Field(
        default=2.0,
        description="The scaling factor of the exponentiation max_depth; defaults to 2.",
    )

    class Config:
        frozen = True
max_depth: PositiveInt pydantic-field required

The max_depth of the smallest exponentiation

max_depth_scaling_factor: NonNegativeFloat pydantic-field

The scaling factor of the exponentiation max_depth; defaults to 2.

ExponentiationSpecification (BaseModel) pydantic-model

Specifications of individual Exponentiation details for each qubit; only valid if Exponentiation is given as unitary_params for PhaseEstimation. This sets the optimization to ExponentiationOptimization.MINIMIZE_ERROR and overrides the max_depth constraints.

Source code in classiq/interface/generator/qpe.py
class ExponentiationSpecification(pydantic.BaseModel):
    """
    Specifications of individual Exponentiation details for each qubit; only valid if Exponentiation is given as unitary_params for PhaseEstimation.
    This sets the optimization to ExponentiationOptimization.MINIMIZE_ERROR and overrides the max_depth constraints.
    """

    scaling: Optional[ExponentiationScaling] = pydantic.Field(
        default=None,
        description="The scaling of the exponentiation functions.",
    )
    max_depths: Optional[Tuple[pydantic.NonNegativeInt, ...]] = pydantic.Field(
        default=None,
        description="The max_depth of each exponentiation function; overrides scaling.",
    )

    class Config:
        frozen = True

    @pydantic.root_validator
    def _validate_exponentiation_specification(
        cls, values: Dict[str, Any]
    ) -> Dict[str, Any]:
        if values.get("scaling") is None and values.get("max_depths") is None:
            raise ClassiqValueError("At least one specification must be provided.")
        return values
max_depths: Tuple[pydantic.types.NonNegativeInt, ...] pydantic-field

The max_depth of each exponentiation function; overrides scaling.

scaling: ExponentiationScaling pydantic-field

The scaling of the exponentiation functions.

PhaseEstimation (FunctionParams) pydantic-model

Quantum phase estimation of a given unitary function.

Source code in classiq/interface/generator/qpe.py
class PhaseEstimation(FunctionParams):
    """
    Quantum phase estimation of a given unitary function.
    """

    size: pydantic.PositiveInt = pydantic.Field(
        description="The number of qubits storing the estimated phase."
    )
    unitary: str = pydantic.Field(
        description="The unitary function for phase estimation.",
    )
    unitary_params: FunctionParams = pydantic.Field(
        description="The unitary function parameters.",
        default_factory=CustomFunction,
    )
    exponentiation_specification: Optional[ExponentiationSpecification] = (
        pydantic.Field(
            default=None,
            description="The specifications for phase estimation of exponentiation functions.",
        )
    )

    _output_name: IOName = pydantic.PrivateAttr(
        default=PHASE_ESTIMATION_DEFAULT_OUTPUT_NAME
    )

    @property
    def output_name(self) -> str:
        return self._output_name

    def _create_ios(self) -> None:
        self._inputs = {**self.unitary_params.inputs}
        self._outputs = {**self.unitary_params.outputs}
        self._outputs[self._output_name] = RegisterArithmeticInfo(size=self.size)
        self._create_zero_input_registers({DEFAULT_ZERO_NAME: self.size})

    @pydantic.root_validator(pre=True)
    def _validate_composite_name(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        if isinstance(values.get("unitary_params"), CustomFunction) and not values.get(
            "unitary"
        ):
            raise ClassiqValueError(
                "`PhaseEstimation` of a user define function (`CustomFunction`) must receive the function name from the `unitary` field"
            )
        return values

    @pydantic.root_validator(pre=True)
    def _parse_function_params(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        parse_function_params_values(
            values=values,
            params_key="unitary_params",
            discriminator_key="unitary",
            param_classes=function_param_library_without_self_reference.param_list,
            default_parser_class=CustomFunction,
        )
        return values

    @pydantic.validator("unitary_params")
    def _validate_unitary_params(cls, unitary_params: FunctionParams) -> FunctionParams:
        if not unitary_params.is_powerable():
            if isinstance(unitary_params, CustomFunction):
                raise ClassiqMismatchIOsError(CUSTOM_FUNCTIONS_IO_MISMATCH_ERROR)
            raise ClassiqValueError(
                f"Phase estimation of {unitary_params.discriminator()} is currently not supported."
            )
        return unitary_params

    @pydantic.validator("exponentiation_specification")
    def _validate_exponentiation_specification(
        cls,
        exponentiation_specification: Optional[ExponentiationSpecification],
        values: Dict[str, Any],
    ) -> Optional[ExponentiationSpecification]:
        if exponentiation_specification is None:
            return exponentiation_specification
        unitary_params = values.get("unitary_params")
        if not isinstance(unitary_params, Exponentiation):
            raise ClassiqValueError(
                "exponentiation_specification is only valid for Exponentiation unitary_params."
            )
        if exponentiation_specification.max_depths is not None and len(
            exponentiation_specification.max_depths
        ) != values.get("size"):
            raise ClassiqValueError(
                "Length of max_depths must match the provided size."
            )
        return exponentiation_specification
exponentiation_specification: ExponentiationSpecification pydantic-field

The specifications for phase estimation of exponentiation functions.

size: PositiveInt pydantic-field required

The number of qubits storing the estimated phase.

unitary: str pydantic-field required

The unitary function for phase estimation.

unitary_params: FunctionParams pydantic-field

The unitary function parameters.

qsvm

QSVMFeatureMap (FunctionParams) pydantic-model

Feature map circuit used for QSVM

Source code in classiq/interface/generator/qsvm.py
class QSVMFeatureMap(FunctionParams):
    """
    Feature map circuit used for QSVM
    """

    feature_map: FeatureMapType = pydantic.Field(
        description="The feature map for the qsvm",
        discriminator="map_type",
    )

    @property
    def num_qubits(self) -> int:
        if not self.feature_map.feature_dimension:
            raise ClassiqQSVMError(
                "Feature dimension should be provided to create a circuit."
            )
        if isinstance(self.feature_map, QSVMFeatureMapPauli):
            return self.feature_map.feature_dimension
        else:
            return int(np.ceil(self.feature_map.feature_dimension / 2))

    def _create_ios(self) -> None:
        self._inputs = {
            DEFAULT_INPUT_NAME: RegisterUserInput(
                name=DEFAULT_INPUT_NAME, size=self.num_qubits
            )
        }
        self._outputs = {
            DEFAULT_OUTPUT_NAME: RegisterUserInput(
                name=DEFAULT_OUTPUT_NAME, size=self.num_qubits
            )
        }
feature_map: Union[classiq.interface.generator.qsvm.QSVMFeatureMapBlochSphere, classiq.interface.generator.qsvm.QSVMFeatureMapPauli] pydantic-field required

The feature map for the qsvm

quantum_function_call

SynthesisQuantumFunctionCall (BaseModel) pydantic-model
Source code in classiq/interface/generator/quantum_function_call.py
class SynthesisQuantumFunctionCall(BaseModel):
    function: str = pydantic.Field(description="The function that is called")
    function_params: f_params.FunctionParams = pydantic.Field(
        description="The parameters necessary for defining the function",
        default_factory=CustomFunction,
    )
    is_inverse: bool = pydantic.Field(
        default=False, description="Call the function inverse."
    )
    strict_zero_ios: bool = pydantic.Field(
        default=True,
        description="Enables automated qubit allocation for pre-determined zero inputs "
        "and allows automated qubit release when performing inversion.\n"
        "Setting this flag to False exposes zero inputs and outputs as regular "
        "functional registers, and shifts the responsibility to the user to manually "
        "manage qubit allocation and release.",
    )
    release_by_inverse: bool = pydantic.Field(
        default=False, description="Release zero inputs in inverse call."
    )
    control_states: List[ControlState] = pydantic.Field(
        default_factory=list,
        description="Call the controlled function with the given controlled states.",
    )
    should_control: bool = pydantic.Field(
        default=True,
        description="False value indicates this call shouldn't be controlled even if the flow is controlled.",
    )
    inputs: IOType = pydantic.Field(
        default_factory=dict,
        description="A mapping from the input name to the wire it connects to",
    )
    inouts: Mapping[IOName, WirePair] = pydantic.Field(
        default_factory=dict,
        description="A mapping from in/out name to the wires that connect to it",
    )
    outputs: IOType = pydantic.Field(
        default_factory=dict,
        description="A mapping from the output name to the wire it connects to",
    )
    power: PydanticPowerType = pydantic.Field(
        default=1, description="Number of successive calls to the operation"
    )
    name: PydanticNonEmptyString = pydantic.Field(
        default=None,
        description="The name of the function instance. "
        "If not set, determined automatically.",
    )

    def __eq__(self, other: Any) -> bool:
        return (
            isinstance(other, SynthesisQuantumFunctionCall) and self.name == other.name
        )

    def __hash__(self) -> int:
        return hash(self.name)

    @property
    def non_zero_input_wires(self) -> List[WireName]:
        in_out_input_wires = [
            split_wire_pair_to_wires(inout)[0] for inout in self.inouts.values()
        ]
        return get_non_zero_wires(self.inputs_dict.values()) + in_out_input_wires

    @property
    def non_zero_output_wires(self) -> List[WireName]:
        in_out_output_wires = [
            split_wire_pair_to_wires(inout)[1] for inout in self.inouts.values()
        ]
        return get_non_zero_wires(self.outputs_dict.values()) + in_out_output_wires

    @property
    def inputs_dict(self) -> WireDict:
        assert isinstance(self.inputs, dict)
        return self.inputs

    @property
    def outputs_dict(self) -> WireDict:
        assert isinstance(self.outputs, dict)
        return self.outputs

    @property
    def input_regs_dict(self) -> ArithmeticIODict:
        ctrl_regs_dict = {
            ctrl_state.name: ctrl_state.control_register
            for ctrl_state in self.control_states
        }
        return {
            **self._true_io_dict(io=PortDirection.Input),
            **ctrl_regs_dict,
        }

    @property
    def output_regs_dict(self) -> ArithmeticIODict:
        ctrl_regs_dict = {
            ctrl_state.name: ctrl_state.control_register
            for ctrl_state in self.control_states
        }
        return {
            **self._true_io_dict(io=PortDirection.Output),
            **ctrl_regs_dict,
        }

    def _true_io_dict(self, io: PortDirection) -> ArithmeticIODict:
        if (io == PortDirection.Input) != self.is_inverse:
            return self.function_params.inputs_full(self.strict_zero_ios)
        return self.function_params.outputs

    @pydantic.validator("name", pre=True, always=True)
    def _create_name(cls, name: Optional[str], values: Dict[str, Any]) -> str:
        """
        generates a name to a user defined-functions as follows:
        <function_name>_<SUFFIX_MARKER>_<random_suffix>
        """
        if name is not None:
            match = re.fullmatch(pattern=NAME_REGEX, string=name)
            if match is None:
                raise ClassiqValueError(BAD_CALL_NAME_ERROR_MSG)
            return name

        function = values.get("function")

        params = values.get("function_params")
        if (
            isinstance(params, CustomFunction)
            and function == CustomFunction.discriminator()
            and params.name != ""
        ):
            function = params.name

        suffix = f"{SUFFIX_MARKER}_{randomize_suffix()}"
        if not function or params is None:
            return name if name else suffix
        return f"{function.split(f'_{EXPANDED_KEYWORD}')[0]}_{suffix}"

    @pydantic.root_validator(pre=True)
    def validate_composite_name(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        if isinstance(values.get("unitary_params"), CustomFunction) and not values.get(
            "unitary"
        ):
            raise ClassiqValueError(
                "`PhaseEstimation` of a user define function (`CustomFunction`) must receive the function name from the `unitary` field"
            )
        return values

    @pydantic.root_validator(pre=True)
    def _parse_function_params(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        f_params.parse_function_params_values(
            values=values,
            params_key="function_params",
            discriminator_key="function",
            param_classes=function_param_list.function_param_library.param_list,
            default_parser_class=CustomFunction,
        )
        return values

    # TODO: note that this checks QuantumFunctionCall input register names
    # are PARTIAL to FunctionParams input register names, not EQUAL.
    # We might want to change that.
    @staticmethod
    def _validate_input_names(
        *,
        params: f_params.FunctionParams,
        inputs: WireDict,
        is_inverse: bool,
        control_states: List[ControlState],
        strict_zero_ios: bool,
    ) -> None:
        (
            invalid_expressions,
            invalid_slicings,
            invalid_names,
        ) = SynthesisQuantumFunctionCall._get_invalid_ios(
            expressions=inputs.keys(),
            params=params,
            io=PortDirection.Input if not is_inverse else PortDirection.Output,
            control_states=control_states,
            strict_zero_ios=strict_zero_ios,
        )
        error_msg = []
        if invalid_expressions:
            error_msg.append(f"{BAD_INPUT_EXPRESSION_MSG}: {invalid_expressions}")
        if invalid_names:
            error_msg.append(f"{BAD_INPUT_ERROR_MSG}: {invalid_names}")
        if invalid_slicings:
            error_msg.append(f"{BAD_INPUT_SLICING_MSG}: {invalid_slicings}")
        if error_msg:
            raise ClassiqValueError("\n".join(error_msg))

    @pydantic.validator("strict_zero_ios")
    def _validate_arithmetic_cannot_strict_zero_ios(
        cls, strict_zero_ios: bool, values: Dict[str, Any]
    ) -> bool:
        assert not (
            values.get("function") == Arithmetic.discriminator() and not strict_zero_ios
        ), "when using the Arithmetic function, assign to the expression result register via the target parameter instead of the strict_zero_ios flag"
        return strict_zero_ios

    @pydantic.validator("control_states")
    def _validate_control_states(
        cls, control_states: List[ControlState], values: Dict[str, Any]
    ) -> List[ControlState]:
        control_names = [ctrl_state.name for ctrl_state in control_states]
        function_params = values.get("function_params")
        strict_zero_ios = values.get("strict_zero_ios")
        if not (
            isinstance(function_params, FunctionParams)
            and isinstance(strict_zero_ios, bool)
        ):
            return control_states
        all_input_names = [
            *function_params.inputs_full(strict_zero_ios=strict_zero_ios),
            *control_names,
        ]
        all_output_names = [*function_params.outputs, *control_names]
        if any(
            cls._has_repetitions(name_list)
            for name_list in (control_names, all_input_names, all_output_names)
        ):
            raise ClassiqControlError()
        return control_states

    @staticmethod
    def _has_repetitions(name_list: Sequence[str]) -> bool:
        return len(set(name_list)) < len(name_list)

    @staticmethod
    def _validate_slices(
        io: PortDirection,
        inputs: IOType,
        fp: FunctionParams,
        strict_zero_ios: bool,
        control_states: List[ControlState],
    ) -> None:
        name_slice_pairs = [parse_io_slicing(input) for input in inputs]
        slices_dict: Dict[str, List[slice]] = defaultdict(list)
        for name, slice in name_slice_pairs:
            slices_dict[name].append(slice)

        fp_inputs = (
            fp.inputs_full(strict_zero_ios)
            if (io == PortDirection.Input)
            else fp.outputs
        )
        widths = {name: reg.size for name, reg in fp_inputs.items()}
        control_names = {state.name for state in control_states}

        for name in slices_dict:
            if name in control_names:
                continue
            assert name in widths, "Name not in widths"
            if not SynthesisQuantumFunctionCall._register_validate_slices(
                slices_dict[name], widths[name]
            ):
                raise ClassiqValueError(BAD_INPUT_SLICING_MSG)

    @staticmethod
    def _register_validate_slices(slices: List[slice], reg_width: int) -> bool:
        widths_separated = [len(range(reg_width)[reg_slice]) for reg_slice in slices]
        # examples: slice(0), slice(5,None) when width <= 5, slice(5,3)
        empty_slices = 0 in widths_separated

        max_stop = max(reg_slice.stop or 0 for reg_slice in slices)
        out_of_range = max_stop > reg_width

        all_widths_separated = sum(widths_separated)
        all_indices = set(
            itertools.chain.from_iterable(
                range(reg_width)[reg_slice] for reg_slice in slices
            )
        )
        all_widths_combined = len(all_indices)
        overlapping_slices = all_widths_combined != all_widths_separated

        return not any((empty_slices, out_of_range, overlapping_slices))

    @pydantic.validator("inputs")
    def _validate_inputs(cls, inputs: IOType, values: Dict[str, Any]) -> WireDict:
        params: Optional[FunctionParams] = values.get("function_params")
        is_inverse: bool = values.get("is_inverse", False)
        strict_zero_ios: bool = values.get("strict_zero_ios", True)
        control_states: List[ControlState] = values.get("control_states", list())
        if params is None:
            return dict()
        if isinstance(params, CustomFunction):
            if not isinstance(inputs, dict):
                raise ClassiqValueError(CUSTOM_FUNCTION_SINGLE_IO_ERROR)
            return inputs

        if isinstance(inputs, str):
            inputs = SynthesisQuantumFunctionCall._single_wire_to_dict(
                io=f_params.PortDirection.Input,
                is_inverse=is_inverse,
                io_wire=inputs,
                params=params,
                strict_zero_ios=strict_zero_ios,
            )

        cls._validate_input_names(
            params=params,
            inputs=inputs,
            is_inverse=is_inverse,
            control_states=control_states,
            strict_zero_ios=strict_zero_ios,
        )

        cls._validate_slices(
            PortDirection.Input if not is_inverse else PortDirection.Output,
            inputs,
            params,
            strict_zero_ios,
            control_states,
        )

        return inputs

    @staticmethod
    def _validate_output_names(
        *,
        params: f_params.FunctionParams,
        outputs: WireDict,
        is_inverse: bool,
        control_states: List[ControlState],
        strict_zero_ios: bool,
    ) -> None:
        (
            invalid_expressions,
            invalid_slicings,
            invalid_names,
        ) = SynthesisQuantumFunctionCall._get_invalid_ios(
            expressions=outputs.keys(),
            params=params,
            io=PortDirection.Output if not is_inverse else PortDirection.Input,
            control_states=control_states,
            strict_zero_ios=strict_zero_ios,
        )
        error_msg = []
        if invalid_expressions:
            error_msg.append(f"{BAD_OUTPUT_EXPRESSION_MSG}: {invalid_expressions}")
        if invalid_names:
            error_msg.append(f"{BAD_OUTPUT_ERROR_MSG}: {invalid_names}")
        if invalid_slicings:
            error_msg.append(f"{BAD_OUTPUT_SLICING_MSG}: {invalid_slicings}")
        if error_msg:
            raise ClassiqValueError("\n".join(error_msg))

    @pydantic.validator("outputs")
    def _validate_outputs(cls, outputs: IOType, values: Dict[str, Any]) -> IOType:
        params = values.get("function_params")
        is_inverse: bool = values.get("is_inverse", False)
        strict_zero_ios: bool = values.get("strict_zero_ios", True)
        control_states = values.get("control_states", list())
        if params is None:
            return outputs
        if isinstance(params, CustomFunction):
            if not isinstance(outputs, dict):
                raise ClassiqValueError(CUSTOM_FUNCTION_SINGLE_IO_ERROR)
            return outputs

        if isinstance(outputs, str):
            outputs = SynthesisQuantumFunctionCall._single_wire_to_dict(
                io=f_params.PortDirection.Output,
                is_inverse=is_inverse,
                io_wire=outputs,
                params=params,
                strict_zero_ios=strict_zero_ios,
            )

        cls._validate_output_names(
            params=params,
            outputs=outputs,
            is_inverse=is_inverse,
            control_states=control_states,
            strict_zero_ios=strict_zero_ios,
        )

        cls._validate_slices(
            PortDirection.Input if is_inverse else PortDirection.Output,
            outputs,
            params,
            strict_zero_ios,
            control_states,
        )

        return outputs

    @pydantic.validator("power", always=True)
    def _validate_power(
        cls, power: pydantic.NonNegativeInt, values: Dict[str, Any]
    ) -> pydantic.NonNegativeInt:
        function_params = values.get("function_params")
        if function_params is None:
            return power
        if power != 1 and not function_params.is_powerable(
            values.get("strict_zero_ios")
        ):
            raise ClassiqValueError("Cannot power this operator")
        return power

    @staticmethod
    def _single_wire_to_dict(
        io: f_params.PortDirection,
        is_inverse: bool,
        io_wire: WireName,
        params: f_params.FunctionParams,
        strict_zero_ios: bool = True,
    ) -> WireDict:
        params_io = list(
            params.inputs_full(strict_zero_ios)
            if (io == PortDirection.Input) != is_inverse
            else params.outputs
        )

        if len(params_io) == 1:
            return {list(params_io)[0]: io_wire}
        error_message = _generate_single_io_err(
            io_str=io.name.lower(),
            io_regs=params_io,
            io_wire=io_wire,
            function_name=type(params).__name__,
        )
        raise ClassiqValueError(error_message)

    @staticmethod
    def _get_invalid_ios(
        *,
        expressions: Iterable[str],
        params: f_params.FunctionParams,
        io: f_params.PortDirection,
        control_states: List[ControlState],
        strict_zero_ios: bool,
    ) -> Tuple[List[str], List[str], List[str]]:
        expression_matches: Iterable[Optional[Match]] = map(
            functools.partial(re.fullmatch, IO_REGEX), expressions
        )

        valid_matches: List[Match] = []
        invalid_expressions: List[str] = []
        for expression, expression_match in zip(expressions, expression_matches):
            (
                invalid_expressions.append(expression)
                if expression_match is None
                else valid_matches.append(expression_match)
            )

        invalid_slicings: List[str] = []
        invalid_names: List[str] = []
        valid_names = frozenset(
            params.inputs_full(strict_zero_ios)
            if io == PortDirection.Input
            else params.outputs
        )
        for match in valid_matches:
            name = match.groupdict().get(NAME)
            if name is None:
                raise AssertionError("Input/output name validation error")

            slicing = match.groupdict().get(SLICING)
            if slicing is not None and re.fullmatch(LEGAL_SLICING, slicing) is None:
                invalid_slicings.append(match.string)

            if name in valid_names:
                continue
            elif all(state.name != name for state in control_states):
                invalid_names.append(name)

        return invalid_expressions, invalid_slicings, invalid_names

    def update_ios(self, inputs: ArithmeticIODict, outputs: ArithmeticIODict) -> None:
        if not isinstance(self.function_params, CustomFunction):
            raise AssertionError("CustomFunction object expected.")

        self.function_params.generate_ios(
            inputs=inputs,
            outputs=outputs,
        )
        SynthesisQuantumFunctionCall._validate_input_names(
            params=self.function_params,
            inputs=self.inputs_dict,
            is_inverse=self.is_inverse,
            control_states=self.control_states,
            strict_zero_ios=self.strict_zero_ios,
        )
        SynthesisQuantumFunctionCall._validate_output_names(
            params=self.function_params,
            outputs=self.outputs_dict,
            is_inverse=self.is_inverse,
            control_states=self.control_states,
            strict_zero_ios=self.strict_zero_ios,
        )

    def inverse(self) -> SynthesisQuantumFunctionCall:
        call_kwargs = self.__dict__.copy()
        call_kwargs["inputs"] = self.outputs_dict
        call_kwargs["outputs"] = self.inputs_dict
        call_kwargs["name"] = self.inverse_name(self.name)
        call_kwargs["is_inverse"] = not self.is_inverse
        return SynthesisQuantumFunctionCall(**call_kwargs)

    @staticmethod
    def inverse_name(name: str) -> str:
        if name.endswith(INVERSE_SUFFIX):
            return name[: -len(INVERSE_SUFFIX)]
        return f"{name}{INVERSE_SUFFIX}"

    def control(
        self, control_state: ControlState, input_wire: WireName, output_wire: WireName
    ) -> SynthesisQuantumFunctionCall:
        if (
            control_state.name in self.inputs_dict
            or control_state.name in self.outputs_dict
        ):
            raise ClassiqValueError(
                f"Control name: {control_state.name} already exists"
            )

        inputs, outputs = dict(self.inputs_dict), dict(self.outputs_dict)
        inputs.update({control_state.name: input_wire})
        outputs.update({control_state.name: output_wire})

        call_kwargs = self.__dict__.copy()
        call_kwargs["inputs"] = inputs
        call_kwargs["outputs"] = outputs
        call_kwargs["name"] = f"{self.name}_{control_state.name}"
        call_kwargs["control_states"] = self.control_states + [control_state]
        return SynthesisQuantumFunctionCall(**call_kwargs)

    class Config:
        extra = Extra.forbid
control_states: List[classiq.interface.generator.control_state.ControlState] pydantic-field

Call the controlled function with the given controlled states.

function: str pydantic-field required

The function that is called

function_params: FunctionParams pydantic-field

The parameters necessary for defining the function

inouts: Mapping[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue, classiq.interface.generator.quantum_function_call.WirePair] pydantic-field

A mapping from in/out name to the wires that connect to it

inputs: Union[Mapping[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue, classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue], classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue] pydantic-field

A mapping from the input name to the wire it connects to

is_inverse: bool pydantic-field

Call the function inverse.

name: ConstrainedStrValue pydantic-field

The name of the function instance. If not set, determined automatically.

outputs: Union[Mapping[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue, classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue], classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue] pydantic-field

A mapping from the output name to the wire it connects to

power: Union[classiq.interface.backend.pydantic_backend.ConstrainedStrValue, int] pydantic-field

Number of successive calls to the operation

release_by_inverse: bool pydantic-field

Release zero inputs in inverse call.

should_control: bool pydantic-field

False value indicates this call shouldn't be controlled even if the flow is controlled.

strict_zero_ios: bool pydantic-field

Enables automated qubit allocation for pre-determined zero inputs and allows automated qubit release when performing inversion. Setting this flag to False exposes zero inputs and outputs as regular functional registers, and shifts the responsibility to the user to manually manage qubit allocation and release.

__eq__(self, other) special

Return self==value.

Source code in classiq/interface/generator/quantum_function_call.py
def __eq__(self, other: Any) -> bool:
    return (
        isinstance(other, SynthesisQuantumFunctionCall) and self.name == other.name
    )
__hash__(self) special

Return hash(self).

Source code in classiq/interface/generator/quantum_function_call.py
def __hash__(self) -> int:
    return hash(self.name)

quantum_program

QuantumProgram (VersionedModel, CircuitCodeInterface) pydantic-model
Source code in classiq/interface/generator/quantum_program.py
class QuantumProgram(VersionedModel, CircuitCodeInterface):
    hardware_data: SynthesisHardwareData
    initial_values: Optional[InitialConditions]
    data: GeneratedCircuitData
    model: ExecutionModel
    transpiled_circuit: Optional[TranspiledCircuitData]
    creation_time: str = pydantic.Field(default_factory=datetime.utcnow().isoformat)
    synthesis_duration: Optional[SynthesisStepDurations]
    debug_info: Optional[List[FunctionDebugInfo]]
    program_id: str = pydantic.Field(default_factory=get_uuid_as_str)

    def _hardware_agnostic_program_code(self) -> CodeAndSyntax:
        circuit_code = self.program_circuit.get_code_by_priority()
        if circuit_code is not None:
            return circuit_code

        raise ClassiqMissingOutputFormatError(
            missing_formats=list(INSTRUCTION_SET_TO_FORMAT.values())
        )

    def _default_program_code(self) -> CodeAndSyntax:
        if self.hardware_data.backend_data is None:
            return self._hardware_agnostic_program_code()

        backend_provider = self.hardware_data.backend_data.hw_provider
        instruction_set: QuantumInstructionSet = VENDOR_TO_INSTRUCTION_SET.get(
            backend_provider, DEFAULT_INSTRUCTION_SET
        )
        return self.program_circuit.get_code(instruction_set), instruction_set

    def to_base_program(self) -> quantum_code.QuantumBaseCode:
        code, syntax = self._default_program_code()
        return quantum_code.QuantumBaseCode(code=code, syntax=syntax)

    def to_program(
        self,
        initial_values: Optional[InitialConditions] = None,
        instruction_set: Optional[QuantumInstructionSet] = None,
    ) -> quantum_code.QuantumCode:
        initial_values = initial_values or self.initial_values

        if instruction_set is not None:
            code, syntax = (
                self.program_circuit.get_code(instruction_set),
                instruction_set,
            )
        else:
            code, syntax = self._default_program_code()

        if initial_values is not None:
            registers_initialization = self.get_registers_initialization(
                initial_values=initial_values
            )
        else:
            registers_initialization = None
        return quantum_code.QuantumCode(
            code=code,
            syntax=syntax,
            output_qubits_map=self.data.qubit_mapping.physical_outputs,
            registers_initialization=registers_initialization,
            synthesis_execution_data=self.data.execution_data,
        )

    def _get_initialization_qubits(self, name: str) -> Tuple[int, ...]:
        qubits = self.data.qubit_mapping.logical_inputs.get(name)
        if qubits is None:
            raise ClassiqStateInitializationError(
                f"Cannot initialize register {name}, it does not appear in circuit inputs"
            )
        return qubits

    def get_registers_initialization(
        self, initial_values: InitialConditions
    ) -> Dict[RegisterName, RegisterInitialization]:
        return {
            name: RegisterInitialization(
                name=name,
                qubits=list(self._get_initialization_qubits(name)),
                initial_condition=init_value,
            )
            for name, init_value in initial_values.items()
        }

    def save_results(self, filename: Optional[Union[str, Path]] = None) -> None:
        """
        Saves quantum program results as json.
            Parameters:
                filename (Union[str, Path]): Optional, path + filename of file.
                                             If filename supplied add `.json` suffix.

            Returns:
                  None
        """
        if filename is None:
            filename = f"synthesised_circuit_{self.creation_time}.json"

        with open(filename, "w") as file:
            file.write(self.json(indent=4))

    @classmethod
    def from_qprog(cls, qprog: str) -> "QuantumProgram":
        return cls.parse_raw(qprog)

    @property
    def _can_use_transpiled_code(self) -> bool:
        return self.data.execution_data is None

    @property
    def program_circuit(self) -> CircuitCodeInterface:
        return (
            self.transpiled_circuit
            if self.transpiled_circuit and self._can_use_transpiled_code
            else self
        )
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

save_results(self, filename=None)

Saves quantum program results as json. !!! parameters filename (Union[str, Path]): Optional, path + filename of file. If filename supplied add .json suffix.

!!! returns
      None
Source code in classiq/interface/generator/quantum_program.py
def save_results(self, filename: Optional[Union[str, Path]] = None) -> None:
    """
    Saves quantum program results as json.
        Parameters:
            filename (Union[str, Path]): Optional, path + filename of file.
                                         If filename supplied add `.json` suffix.

        Returns:
              None
    """
    if filename is None:
        filename = f"synthesised_circuit_{self.creation_time}.json"

    with open(filename, "w") as file:
        file.write(self.json(indent=4))

range_mixer

RangeMixer (FunctionParams) pydantic-model

Mixing a fixed point number variable between a given lower and upper bounds. I.e. after applying this function the variable will hold a superposition of all the valid values.

Source code in classiq/interface/generator/range_mixer.py
class RangeMixer(FunctionParams):
    """
    Mixing a fixed point number variable between a given lower and upper bounds.
    I.e. after applying this function the variable will hold a
    superposition of all the valid values.
    """

    data_reg_input: RegisterArithmeticInfo = pydantic.Field(
        description="The input variable to mix."
    )

    lower_bound_reg_input: RegisterOrConst = pydantic.Field(
        description="Fixed number or variable that define the lower bound for"
        " the mixing operation. In case of a fixed number bound, the value"
        " must be positive."
    )

    upper_bound_reg_input: RegisterOrConst = pydantic.Field(
        description="Fixed number or variable that define the upper bound for"
        " the mixing operation. In case of a fixed number bound, the value"
        " must be positive."
    )

    mixer_parameter: ParameterFloatType = pydantic.Field(
        description="The parameter used for rotation gates in the mixer.",
        is_exec_param=True,
    )

    def _create_ios(self) -> None:
        self._inputs = {DATA_REG_INPUT_NAME: self.data_reg_input}
        self._outputs = {DATA_REG_OUTPUT_NAME: self.data_reg_input}

        if isinstance(self.lower_bound_reg_input, RegisterArithmeticInfo):
            self._inputs[LOWER_BOUND_REG_INPUT_NAME] = self.lower_bound_reg_input
            self._outputs[LOWER_BOUND_REG_OUTPUT_NAME] = self.lower_bound_reg_input

        if isinstance(self.upper_bound_reg_input, RegisterArithmeticInfo):
            self._inputs[UPPER_BOUND_REG_INPUT_NAME] = self.upper_bound_reg_input
            self._outputs[UPPER_BOUND_REG_OUTPUT_NAME] = self.upper_bound_reg_input
data_reg_input: RegisterArithmeticInfo pydantic-field required

The input variable to mix.

lower_bound_reg_input: Union[classiq.interface.generator.arith.register_user_input.RegisterArithmeticInfo, float] pydantic-field required

Fixed number or variable that define the lower bound for the mixing operation. In case of a fixed number bound, the value must be positive.

mixer_parameter: Union[float, str] pydantic-field required

The parameter used for rotation gates in the mixer.

upper_bound_reg_input: Union[classiq.interface.generator.arith.register_user_input.RegisterArithmeticInfo, float] pydantic-field required

Fixed number or variable that define the upper bound for the mixing operation. In case of a fixed number bound, the value must be positive.

standard_gates special

controlled_standard_gates
C3XGate (ControlledGateWithState) pydantic-model

The X Gate controlled on 3 qubits

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class C3XGate(ControlledGateWithState):  # type: ignore[misc]
    """
    The X Gate controlled on 3 qubits
    """

    _name: str = "mcx"
    num_ctrl_qubits: Literal[3] = pydantic.Field(default=3)

    def get_power_order(self) -> int:
        return 2
C4XGate (ControlledGateWithState) pydantic-model

The X Gate controlled on 4 qubits

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class C4XGate(ControlledGateWithState):  # type: ignore[misc]
    """
    The X Gate controlled on 4 qubits
    """

    _name: str = "mcx"
    num_ctrl_qubits: Literal[4] = pydantic.Field(default=4)

    def get_power_order(self) -> int:
        return 2
CCXGate (ControlledGateWithState) pydantic-model

The Double Controlled-X Gate

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class CCXGate(ControlledGateWithState):  # type: ignore[misc]
    """
    The Double Controlled-X Gate
    """

    num_ctrl_qubits: Literal[2] = pydantic.Field(default=2)

    def get_power_order(self) -> int:
        return 2
CHGate (ControlledGateWithState) pydantic-model

The Controlled-H Gate

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class CHGate(ControlledGateWithState):  # type: ignore[misc]
    """
    The Controlled-H Gate
    """

    def get_power_order(self) -> int:
        return 2
CPhaseGate (ControlledGateWithState) pydantic-model

The Controlled-Phase Gate

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class CPhaseGate(ControlledGateWithState, angles=["theta"]):  # type: ignore[misc]
    """
    The Controlled-Phase Gate
    """

    _name: str = "cp"
CRXGate (ControlledGateWithState) pydantic-model

The Controlled-RX Gate

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class CRXGate(ControlledGateWithState, angles=["theta"]):  # type: ignore[misc]
    """
    The Controlled-RX Gate
    """
CRYGate (ControlledGateWithState) pydantic-model

The Controlled-RY Gate

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class CRYGate(ControlledGateWithState, angles=["theta"]):  # type: ignore[misc]
    """
    The Controlled-RY Gate
    """
CRZGate (ControlledGateWithState) pydantic-model

The Controlled-RZ Gate

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class CRZGate(ControlledGateWithState, angles=["theta"]):  # type: ignore[misc]
    """
    The Controlled-RZ Gate
    """
CSXGate (ControlledGateWithState) pydantic-model

The Controlled-SX Gate

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class CSXGate(ControlledGateWithState):  # type: ignore[misc]
    """
    The Controlled-SX Gate
    """

    def get_power_order(self) -> int:
        return 4
CXGate (ControlledGateWithState) pydantic-model

The Controlled-X Gate

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class CXGate(ControlledGateWithState):  # type: ignore[misc]
    """
    The Controlled-X Gate
    """

    num_ctrl_qubits: Literal[1] = pydantic.Field(default=1)

    def get_power_order(self) -> int:
        return 2
CYGate (ControlledGateWithState) pydantic-model

The Controlled-Y Gate

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class CYGate(ControlledGateWithState):  # type: ignore[misc]
    """
    The Controlled-Y Gate
    """

    def get_power_order(self) -> int:
        return 2
CZGate (ControlledGateWithState) pydantic-model

The Controlled-Z Gate

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class CZGate(ControlledGateWithState):  # type: ignore[misc]
    """
    The Controlled-Z Gate
    """

    def get_power_order(self) -> int:
        return 2
ControlledGate (_StandardGate) pydantic-model

Base model for controlled Gates

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class ControlledGate(_StandardGate):  # type: ignore[misc]
    """
    Base model for controlled Gates
    """

    num_ctrl_qubits: pydantic.PositiveInt = pydantic.Field(
        default=DEFAULT_NUM_CTRL_QUBITS
    )

    def _create_ios(self) -> None:
        _StandardGate._create_ios(self)
        control = RegisterUserInput(
            name=CONTROLLED_GATE_CONTROL, size=self.num_ctrl_qubits
        )
        self._inputs[CONTROLLED_GATE_CONTROL] = control
        self._outputs[CONTROLLED_GATE_CONTROL] = control

    def to_control_state(self) -> ControlState:
        return ControlState(
            name=CONTROLLED_GATE_CONTROL, num_ctrl_qubits=self.num_ctrl_qubits
        )
ControlledGateWithState (ControlledGate) pydantic-model

Base model for controlled Gates with control over the controlled_state

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class ControlledGateWithState(ControlledGate):  # type: ignore[misc]
    """
    Base model for controlled Gates with control over the controlled_state
    """

    ctrl_state: CtrlState = pydantic.Field(
        description="The control state in decimal or as a bit string (e.g. '1011'). If not specified, the control "
        "state is 2**num_ctrl_qubits - 1.\n"
        "The gate will be performed if the state of the control qubits matches the control state"
    )

    @pydantic.validator("ctrl_state", always=True)
    def _validate_ctrl_state(
        cls, ctrl_state: CtrlState, values: Dict[str, Any]
    ) -> CtrlState:
        num_ctrl_qubits: int = values.get("num_ctrl_qubits", DEFAULT_NUM_CTRL_QUBITS)
        ctrl_state = ctrl_state if ctrl_state is not None else "1" * num_ctrl_qubits

        if isinstance(ctrl_state, str) and len(ctrl_state) != num_ctrl_qubits:
            raise ClassiqValueError(
                f"Invalid control state: {ctrl_state!r}. "
                f"Expected {num_ctrl_qubits} qubits"
            )
        elif isinstance(ctrl_state, int) and ctrl_state >= 2**num_ctrl_qubits:
            raise ClassiqValueError(
                f"Invalid control state: {ctrl_state}. "
                f"Expected value between 0 and {2**num_ctrl_qubits-1}"
            )
        return ctrl_state

    def to_control_state(self) -> ControlState:
        ctrl_state_str = (
            _num_to_control_string(self.ctrl_state, self.num_ctrl_qubits)
            if isinstance(self.ctrl_state, int)
            else self.ctrl_state
        )
        return ControlState(name=CONTROLLED_GATE_CONTROL, ctrl_state=ctrl_state_str)
ctrl_state: Union[pydantic.types.StrictStr, pydantic.types.NonNegativeInt] pydantic-field

The control state in decimal or as a bit string (e.g. '1011'). If not specified, the control state is 2**num_ctrl_qubits - 1. The gate will be performed if the state of the control qubits matches the control state

MCPhaseGate (ControlledGate) pydantic-model

The Controlled-Phase Gate

Source code in classiq/interface/generator/standard_gates/controlled_standard_gates.py
class MCPhaseGate(ControlledGate, angles=["lam"]):  # type: ignore[misc]
    """
    The Controlled-Phase Gate
    """

    _name: str = "mcphase"
standard_angle_metaclass
MyMetaAngledClass (type)
Source code in classiq/interface/generator/standard_gates/standard_angle_metaclass.py
class MyMetaAngledClass(type):
    def __new__(cls, name: str, bases: tuple, namespace: dict, **kwargs: Any) -> type:
        a_totally_new_namespace = cls._create_new_namespace(namespace, **kwargs)
        return type.__new__(cls, name, bases, a_totally_new_namespace)

    @staticmethod
    def _create_new_namespace(namespace: dict, **kwargs: Any) -> dict:
        angles = kwargs.get("angles", [])
        annotations = {angle: ParameterFloatType for angle in angles}
        fields = {
            angle: pydantic.fields.FieldInfo(is_exec_param=True) for angle in angles
        }
        original_annotations = namespace.get("__annotations__", {})
        return {
            **namespace,
            **fields,
            **{"__annotations__": {**original_annotations, **annotations}},
        }
__new__(cls, name, bases, namespace, **kwargs) special staticmethod

Create and return a new object. See help(type) for accurate signature.

Source code in classiq/interface/generator/standard_gates/standard_angle_metaclass.py
def __new__(cls, name: str, bases: tuple, namespace: dict, **kwargs: Any) -> type:
    a_totally_new_namespace = cls._create_new_namespace(namespace, **kwargs)
    return type.__new__(cls, name, bases, a_totally_new_namespace)
MyMetaAngledClassModel (ModelMetaclass, MyMetaAngledClass)
Source code in classiq/interface/generator/standard_gates/standard_angle_metaclass.py
class MyMetaAngledClassModel(PydanticMetaClass, MyMetaAngledClass):
    def __new__(
        cls, name: str, bases: tuple, namespace: dict, **kwargs: Any
    ) -> PydanticMetaClass:
        # First, populate the namespace (specifically, "__annotations__") according to `MyMetaAngledClass` with the angles defined
        namespace = MyMetaAngledClass._create_new_namespace(namespace, **kwargs)

        # Clean `kwargs` afterwards so that it won't pass again to the final class
        if "angles" in kwargs:
            kwargs.pop("angles")

        # Next, continue with pydantic's flow
        return PydanticMetaClass.__new__(cls, name, bases, namespace, **kwargs)
__new__(cls, name, bases, namespace, **kwargs) special staticmethod

Create and return a new object. See help(type) for accurate signature.

Source code in classiq/interface/generator/standard_gates/standard_angle_metaclass.py
def __new__(
    cls, name: str, bases: tuple, namespace: dict, **kwargs: Any
) -> PydanticMetaClass:
    # First, populate the namespace (specifically, "__annotations__") according to `MyMetaAngledClass` with the angles defined
    namespace = MyMetaAngledClass._create_new_namespace(namespace, **kwargs)

    # Clean `kwargs` afterwards so that it won't pass again to the final class
    if "angles" in kwargs:
        kwargs.pop("angles")

    # Next, continue with pydantic's flow
    return PydanticMetaClass.__new__(cls, name, bases, namespace, **kwargs)
standard_angled_gates
PhaseGate (_StandardGate) pydantic-model

Add relative phase of lambda

Source code in classiq/interface/generator/standard_gates/standard_angled_gates.py
class PhaseGate(_StandardGate, angles=["theta"]):  # type: ignore[misc]
    """
    Add relative phase of lambda
    """

    _name: str = "p"
RGate (_StandardGate) pydantic-model

Rotation by theta about the cos(phi)X + sin(phi)Y axis

Source code in classiq/interface/generator/standard_gates/standard_angled_gates.py
class RGate(_StandardGate, angles=["theta", "phi"]):  # type: ignore[misc]
    """
    Rotation by theta about the cos(phi)X + sin(phi)Y axis
    """
RXGate (_StandardGate) pydantic-model

Rotation by theta about the X axis

Source code in classiq/interface/generator/standard_gates/standard_angled_gates.py
class RXGate(_StandardGate, angles=["theta"]):  # type: ignore[misc]
    """
    Rotation by theta about the X axis
    """
RXXGate (_DoubleRotationGate) pydantic-model

Rotation by theta about the XX axis

Source code in classiq/interface/generator/standard_gates/standard_angled_gates.py
class RXXGate(_DoubleRotationGate):  # type: ignore[misc]
    """
    Rotation by theta about the XX axis
    """
RYGate (_StandardGate) pydantic-model

Rotation by theta about the Y axis

Source code in classiq/interface/generator/standard_gates/standard_angled_gates.py
class RYGate(_StandardGate, angles=["theta"]):  # type: ignore[misc]
    """
    Rotation by theta about the Y axis
    """
RYYGate (_DoubleRotationGate) pydantic-model

Rotation by theta about the YY axis

Source code in classiq/interface/generator/standard_gates/standard_angled_gates.py
class RYYGate(_DoubleRotationGate):  # type: ignore[misc]
    """
    Rotation by theta about the YY axis
    """
RZGate (_StandardGate) pydantic-model

Rotation by phi about the Z axis

Source code in classiq/interface/generator/standard_gates/standard_angled_gates.py
class RZGate(_StandardGate, angles=["phi"]):  # type: ignore[misc]
    """
    Rotation by phi about the Z axis
    """
RZZGate (_DoubleRotationGate) pydantic-model

Rotation by theta about the ZZ axis

Source code in classiq/interface/generator/standard_gates/standard_angled_gates.py
class RZZGate(_DoubleRotationGate):  # type: ignore[misc]
    """
    Rotation by theta about the ZZ axis
    """
standard_gates
HGate (UncontrolledStandardGate) pydantic-model

creates a Hadamard gate

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class HGate(UncontrolledStandardGate):  # type: ignore[misc]
    """
    creates a Hadamard gate
    """

    def get_power_order(self) -> int:
        return 2
IGate (UncontrolledStandardGate) pydantic-model

creates the identity gate

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class IGate(UncontrolledStandardGate):  # type: ignore[misc]
    """
    creates the identity gate
    """

    _name: str = "id"

    def get_power_order(self) -> int:
        return 1
SGate (UncontrolledStandardGate) pydantic-model

Z**0.5

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class SGate(UncontrolledStandardGate):  # type: ignore[misc]
    """
    Z**0.5
    """

    def get_power_order(self) -> int:
        return 4
SXGate (UncontrolledStandardGate) pydantic-model

X**0.5

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class SXGate(UncontrolledStandardGate):  # type: ignore[misc]
    """
    X**0.5
    """

    def get_power_order(self) -> int:
        return 4
SXdgGate (UncontrolledStandardGate) pydantic-model

creates the inverse SX gate

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class SXdgGate(UncontrolledStandardGate):  # type: ignore[misc]
    """
    creates the inverse SX gate
    """

    def get_power_order(self) -> int:
        return 4
SdgGate (UncontrolledStandardGate) pydantic-model

creates the inverse S gate

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class SdgGate(UncontrolledStandardGate):  # type: ignore[misc]
    """
    creates the inverse S gate
    """

    def get_power_order(self) -> int:
        return 4
SwapGate (UncontrolledStandardGate) pydantic-model

Swaps between two qubit states

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class SwapGate(UncontrolledStandardGate):  # type: ignore[misc]
    """
    Swaps between two qubit states
    """

    _num_target_qubits: pydantic.PositiveInt = pydantic.PrivateAttr(default=2)

    def get_power_order(self) -> int:
        return 2
TGate (UncontrolledStandardGate) pydantic-model

Z**0.25

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class TGate(UncontrolledStandardGate):  # type: ignore[misc]
    """
    Z**0.25
    """

    def get_power_order(self) -> int:
        return 8
TdgGate (UncontrolledStandardGate) pydantic-model

creates the inverse T gate

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class TdgGate(UncontrolledStandardGate):  # type: ignore[misc]
    """
    creates the inverse T gate
    """

    def get_power_order(self) -> int:
        return 8
XGate (UncontrolledStandardGate) pydantic-model

creates a X gate

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class XGate(UncontrolledStandardGate):  # type: ignore[misc]
    """
    creates a X gate
    """

    def get_power_order(self) -> int:
        return 2
YGate (UncontrolledStandardGate) pydantic-model

creates a Y gate

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class YGate(UncontrolledStandardGate):  # type: ignore[misc]
    """
    creates a Y gate
    """

    def get_power_order(self) -> int:
        return 2
ZGate (UncontrolledStandardGate) pydantic-model

create a Z gate

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class ZGate(UncontrolledStandardGate):  # type: ignore[misc]
    """
    create a Z gate
    """

    def get_power_order(self) -> int:
        return 2
iSwapGate (UncontrolledStandardGate) pydantic-model

Swaps between two qubit states and add phase of i to the amplitudes of |01> and |10>

Source code in classiq/interface/generator/standard_gates/standard_gates.py
class iSwapGate(UncontrolledStandardGate):  # type: ignore[misc] # noqa: N801
    """
    Swaps between two qubit states and add phase of i to the amplitudes of |01> and |10>
    """

    _num_target_qubits: pydantic.PositiveInt = pydantic.PrivateAttr(default=2)

    def get_power_order(self) -> int:
        return 4
u_gate
UGate (FunctionParams) pydantic-model

Matrix representation:

U(gam, phi,theta, lam) = e^(igam) * cos(theta/2) & -e^(ilam)sin(theta/2) \ e^(iphi)sin(theta/2) & e^(i(phi+lam))*cos(theta/2) \

Source code in classiq/interface/generator/standard_gates/u_gate.py
class UGate(function_params.FunctionParams):
    """
    Matrix representation:

    U(gam, phi,theta, lam) =
    e^(i*gam) *
    cos(theta/2) & -e^(i*lam)*sin(theta/2) \\
    e^(i*phi)*sin(theta/2) & e^(i*(phi+lam))*cos(theta/2) \\
    """

    theta: ParameterFloatType = pydantic.Field(
        description="Angle to rotate by the Y-axis.",
        is_exec_param=True,
    )

    phi: ParameterFloatType = pydantic.Field(
        description="First angle to rotate by the Z-axis.",
        is_exec_param=True,
    )

    lam: ParameterFloatType = pydantic.Field(
        description="Second angle to rotate by the Z-axis.",
        is_exec_param=True,
    )

    gam: ParameterFloatType = pydantic.Field(
        description="Angle to apply phase gate by.",
        is_exec_param=True,
    )

    _inputs = pydantic.PrivateAttr(
        default={
            DEFAULT_STANDARD_GATE_ARG_NAME: RegisterUserInput(
                name=DEFAULT_STANDARD_GATE_ARG_NAME, size=1
            )
        }
    )
    _outputs = pydantic.PrivateAttr(
        default={
            DEFAULT_STANDARD_GATE_ARG_NAME: RegisterUserInput(
                name=DEFAULT_STANDARD_GATE_ARG_NAME, size=1
            )
        }
    )

    @property
    def is_parametric(self) -> bool:
        return not all(
            isinstance(getattr(self, angle), (float, int)) for angle in self._params
        )
gam: Union[float, str] pydantic-field required

Angle to apply phase gate by.

lam: Union[float, str] pydantic-field required

Second angle to rotate by the Z-axis.

phi: Union[float, str] pydantic-field required

First angle to rotate by the Z-axis.

theta: Union[float, str] pydantic-field required

Angle to rotate by the Y-axis.

state_preparation special

computational_basis_state_preparation
ComputationalBasisStatePreparation (StatePreparationABC) pydantic-model
Source code in classiq/interface/generator/state_preparation/computational_basis_state_preparation.py
class ComputationalBasisStatePreparation(StatePreparationABC):
    computational_state: PydanticNonEmptyString = pydantic.Field(
        description="binary computational state to create"
    )

    @pydantic.validator("computational_state")
    def _validate_computational_state(
        cls, computational_state: PydanticNonEmptyString
    ) -> PydanticNonEmptyString:
        ControlState.validate_control_string(computational_state)
        return computational_state

    @property
    def num_state_qubits(self) -> int:
        return len(self.computational_state)

    def get_power_order(self) -> int:
        return 2
computational_state: ConstrainedStrValue pydantic-field required

binary computational state to create

distributions
GaussianMixture (BaseModel) pydantic-model
Source code in classiq/interface/generator/state_preparation/distributions.py
class GaussianMixture(pydantic.BaseModel):
    gaussian_moment_list: Tuple[GaussianMoments, ...]
    num_qubits: pydantic.PositiveInt = pydantic.Field(
        description="Number of qubits for the provided state."
    )

    class Config:
        frozen = True
num_qubits: PositiveInt pydantic-field required

Number of qubits for the provided state.

state_preparation
StatePreparation (StatePreparationABC) pydantic-model
Source code in classiq/interface/generator/state_preparation/state_preparation.py
class StatePreparation(StatePreparationABC):
    amplitudes: Optional[Amplitudes] = pydantic.Field(
        description="vector of probabilities", default=None
    )
    probabilities: Optional[Probabilities] = pydantic.Field(
        description="vector of amplitudes", default=None
    )
    error_metric: Dict[Metrics, NonNegativeFloatRange] = pydantic.Field(
        default_factory=lambda: {
            Metrics.L2: NonNegativeFloatRange(lower_bound=0, upper_bound=1e-4)
        }
    )
    # The order of validations is important: amplitudes, probabilities, error_metric

    @pydantic.validator("amplitudes", always=True, pre=True)
    def _initialize_amplitudes(
        cls, amplitudes: Optional[FlexibleAmplitudes]
    ) -> Optional[Amplitudes]:
        if amplitudes is None:
            return None
        amplitudes = np.array(amplitudes).squeeze()
        if amplitudes.ndim == 1:
            return validate_amplitudes(tuple(amplitudes))

        raise ClassiqValueError(
            "Invalid amplitudes were given, please ensure the amplitude is a vector of float in the form of either tuple or list or numpy array"
        )

    @pydantic.validator("probabilities", always=True, pre=True)
    def _initialize_probabilities(
        cls, probabilities: Optional[FlexibleProbabilities]
    ) -> Optional[Union[PMF, GaussianMixture, dict]]:
        if probabilities is None:
            return None
        if isinstance(probabilities, Probabilities.__args__):  # type: ignore[attr-defined]
            return probabilities
        if isinstance(probabilities, dict):  # a pydantic object
            return probabilities
        probabilities = np.array(probabilities).squeeze()
        if probabilities.ndim == 1:
            return PMF(pmf=probabilities.tolist())

        raise ClassiqValueError(
            "Invalid probabilities were given, please ensure the probabilities is a vector of float in the form of either tuple or list or numpy array"
        )

    @pydantic.validator("error_metric", always=True, pre=True)
    def _validate_error_metric(
        cls, error_metric: Dict[Metrics, NonNegativeFloatRange], values: Dict[str, Any]
    ) -> Dict[Metrics, NonNegativeFloatRange]:
        if not values.get("amplitudes"):
            return error_metric
        unsupported_metrics = {
            Metrics(metric).value
            for metric in error_metric
            if not Metrics(metric).supports_amplitudes
        }
        if unsupported_metrics:
            raise ClassiqValueError(
                f"{unsupported_metrics} are not supported for amplitude preparation"
            )
        return error_metric

    @pydantic.root_validator
    def _validate_either_probabilities_or_amplitudes(
        cls,
        values: Dict[str, Any],
    ) -> Optional[Union[PMF, GaussianMixture, dict]]:
        amplitudes = values.get("amplitudes")
        probabilities = values.get("probabilities")
        if amplitudes is not None and probabilities is not None:
            raise ClassiqValueError(
                "StatePreparation can't get both probabilities and amplitudes"
            )
        return values

    @property
    def num_state_qubits(self) -> int:
        distribution = self.probabilities or self.amplitudes
        if distribution is None:
            raise ClassiqValueError("Must have either probabilities or amplitudes")
        return num_of_qubits(distribution)
amplitudes: Tuple[float, ...] pydantic-field

vector of probabilities

probabilities: Union[classiq.interface.generator.state_preparation.distributions.PMF, classiq.interface.generator.state_preparation.distributions.GaussianMixture] pydantic-field

vector of amplitudes

state_propagator

StatePropagator (FunctionParams) pydantic-model

Creates a quantum circuit that propagates the start state vector to the end state vector, both are assumed to be pure states. The default start state vector is |000...0>.

Source code in classiq/interface/generator/state_propagator.py
class StatePropagator(function_params.FunctionParams):
    """
    Creates a quantum circuit that propagates the start state vector to the end state vector,
    both are assumed to be pure states.
    The default start state vector is |000...0>.
    """

    end_state_vector: List[Complex] = pydantic.Field(
        description="The desired state vector at the end of the operator."
        " Must be of size 2**num_qubits. Does not have to be "
        "normalized"
    )

    start_state_vector: List[Complex] = pydantic.Field(
        default_factory=list,
        description="The  state vector at the input of the operator."
        " Must be of size 2**num_qubits. Does not have to be"
        " normalized",
    )

    @pydantic.validator("start_state_vector", always=True)
    def validate_start_state(
        cls, start_state_vector: List[Complex], values: Dict[str, Any]
    ) -> List[Complex]:
        end_state_vector = values.get("end_state_vector")
        if end_state_vector is None:
            raise ClassiqValueError(
                "Cannot validate start_start_vector without end_state_vector"
            )

        num_qubits = cls._num_qubits(end_state_vector)
        if len(start_state_vector) == 0:
            default_start_state_vector = [Complex(0.0) for _ in range(2**num_qubits)]
            default_start_state_vector[0] = Complex(1.0)
            start_state_vector = default_start_state_vector

        if len(start_state_vector) != len(end_state_vector):
            raise ClassiqValueError(
                "Start and end state vectors are of non-equal length"
            )

        return start_state_vector

    @staticmethod
    def _num_qubits(vector: List[Complex]) -> int:
        return int(np.log2(len(vector)))

    def _create_ios(self) -> None:
        self._inputs = {
            DEFAULT_INPUT_NAME: RegisterArithmeticInfo(
                size=self._num_qubits(self.start_state_vector)
            )
        }
        self._outputs = {
            DEFAULT_OUTPUT_NAME: RegisterArithmeticInfo(
                size=self._num_qubits(self.end_state_vector)
            )
        }
end_state_vector: List[classiq.interface.generator.complex_type.Complex] pydantic-field required

The desired state vector at the end of the operator. Must be of size 2**num_qubits. Does not have to be normalized

start_state_vector: List[classiq.interface.generator.complex_type.Complex] pydantic-field

The state vector at the input of the operator. Must be of size 2**num_qubits. Does not have to be normalized

types special

struct_declaration
StructDeclaration (HashableASTNode) pydantic-model
Source code in classiq/interface/generator/types/struct_declaration.py
class StructDeclaration(HashableASTNode):
    name: str

    variables: Dict[str, ConcreteClassicalType] = pydantic.Field(
        default_factory=dict,
        description="Dictionary of variable names and their classical types",
    )

    BUILTIN_STRUCT_DECLARATIONS: ClassVar[Dict[str, "StructDeclaration"]] = {}

    def validate_fields(self, fields: Mapping[str, Any]) -> None:
        expected_field_names = list(self.variables.keys())
        received_field_names = list(fields.keys())
        if set(expected_field_names) != set(received_field_names):
            raise ClassiqValueError(
                f"Invalid fields for {self.name} instance. Expected fields "
                f"{expected_field_names}, got {received_field_names}"
            )
variables: Dict[str, Annotated[Union[classiq.interface.generator.functions.classical_type.Integer, classiq.interface.generator.functions.classical_type.Real, classiq.interface.generator.functions.classical_type.Bool, classiq.interface.generator.functions.classical_type.ClassicalList, classiq.interface.generator.functions.classical_type.Pauli, classiq.interface.generator.functions.classical_type.StructMetaType, classiq.interface.generator.functions.classical_type.Struct, classiq.interface.generator.functions.classical_type.ClassicalArray, classiq.interface.generator.functions.classical_type.VQEResult, classiq.interface.generator.functions.classical_type.Histogram, classiq.interface.generator.functions.classical_type.Estimation, classiq.interface.generator.functions.classical_type.LadderOperator, classiq.interface.generator.functions.classical_type.IQAERes], FieldInfo(default=PydanticUndefined, discriminator='kind', extra={})]] pydantic-field

Dictionary of variable names and their classical types

ucc

UCC (ChemistryFunctionParams) pydantic-model

Ucc ansatz

Source code in classiq/interface/generator/ucc.py
class UCC(ChemistryFunctionParams):
    """
    Ucc ansatz
    """

    use_naive_evolution: bool = pydantic.Field(
        default=False, description="Whether to evolve the operator naively"
    )
    excitations: EXCITATIONS_TYPE = pydantic.Field(
        default_factory=default_excitation_factory,
        description="type of excitation operators in the UCC ansatz",
    )
    max_depth: Optional[pydantic.PositiveInt] = pydantic.Field(
        default=None,
        description="Maximum depth of the generated quantum circuit ansatz",
    )
    parameter_prefix: str = pydantic.Field(
        default="param_",
        description="Prefix for the generated parameters",
    )

    @pydantic.validator("excitations")
    def _validate_excitations(cls, excitations: EXCITATIONS_TYPE) -> EXCITATIONS_TYPE:
        if isinstance(excitations, int):
            if excitations not in _EXCITATIONS_DICT.values():
                raise ClassiqValueError(
                    f"possible values of excitations are {list(_EXCITATIONS_DICT.values())}"
                )
            excitations = [excitations]

        elif isinstance(excitations, Iterable):
            excitations = list(excitations)  # type: ignore[assignment]
            if all(isinstance(idx, int) for idx in excitations):
                if any(idx not in _EXCITATIONS_DICT.values() for idx in excitations):
                    raise ClassiqValueError(
                        f"possible values of excitations are {list(_EXCITATIONS_DICT.values())}"
                    )

            elif all(isinstance(idx, str) for idx in excitations):
                if any(idx not in _EXCITATIONS_DICT.keys() for idx in excitations):
                    raise ClassiqValueError(
                        f"possible values of excitations are {list(_EXCITATIONS_DICT.keys())}"
                    )
                excitations = sorted(_EXCITATIONS_DICT[idx] for idx in excitations)  # type: ignore[index]

            else:
                raise ClassiqValueError(
                    "excitations must be of the same type (all str or all int)"
                )
        return excitations
excitations: Union[str, int, Iterable[int], Iterable[str]] pydantic-field

type of excitation operators in the UCC ansatz

max_depth: PositiveInt pydantic-field

Maximum depth of the generated quantum circuit ansatz

parameter_prefix: str pydantic-field

Prefix for the generated parameters

use_naive_evolution: bool pydantic-field

Whether to evolve the operator naively

unitary_gate

UnitaryGate (FunctionParams) pydantic-model

Creates a circuit implementing a specified 2n * 2n unitary transformation.

Source code in classiq/interface/generator/unitary_gate.py
class UnitaryGate(function_params.FunctionParams):
    """
    Creates a circuit implementing a specified 2**n * 2**n unitary transformation.
    """

    # TODO - add support to numpy array-like (requires custom pydantic type definition)
    data: DataArray = pydantic.Field(
        description="A 2**n * 2**n (n positive integer) unitary matrix."
    )

    # TODO - decide if to include assertion on the unitarity of the matrix. It is already done in Qiskit and could be computationally expensive
    @pydantic.validator("data")
    def validate_data(cls, data: DataArray) -> DataArray:
        data_np = np.array(data, dtype=object)
        if data_np.ndim != 2:
            raise ClassiqValueError("Data must me two dimensional")
        if data_np.shape[0] != data_np.shape[1]:
            raise ClassiqValueError("Matrix must be square")
        if not np.mod(np.log2(data_np.shape[0]), 1) == 0:
            raise ClassiqValueError(
                "Matrix dimensions must be an integer exponent of 2"
            )
        return data

    @property
    def num_target_qubits(self) -> int:
        return int(np.log2(len(self.data)))

    def _create_ios(self) -> None:
        self._inputs = {
            UNITARY_GATE_INPUT: RegisterArithmeticInfo(size=self.num_target_qubits)
        }
        self._outputs = {
            UNITARY_GATE_OUTPUT: RegisterArithmeticInfo(size=self.num_target_qubits)
        }
data: List[List[Union[classiq.interface.generator.complex_type.Complex, float, int]]] pydantic-field required

A 2n * 2n (n positive integer) unitary matrix.

user_defined_function_params

CustomFunction (FunctionParams) pydantic-model

A user-defined custom function parameters object.

Source code in classiq/interface/generator/user_defined_function_params.py
class CustomFunction(FunctionParams):
    """
    A user-defined custom function parameters object.
    """

    _name: str = pydantic.PrivateAttr(default="")

    input_decls: ArithmeticIODict = pydantic.Field(
        default_factory=dict,
        description="A mapping from the inputs names to the registers information. should be identical to the register defined in the function creation.",
    )

    output_decls: ArithmeticIODict = pydantic.Field(
        default_factory=dict,
        description="A mapping from the outputs names to the registers information. should be identical to the register defined in the function creation.",
    )

    def _create_ios(self) -> None:
        self._inputs = self.input_decls
        self._outputs = self.output_decls

    def generate_ios(
        self,
        inputs: Mapping[str, RegisterArithmeticInfo],
        outputs: Mapping[str, RegisterArithmeticInfo],
    ) -> None:
        self._inputs = dict(inputs)
        self._outputs = dict(outputs)

    @property
    def name(self) -> str:
        return self._name

    def set_name(self, name: str) -> None:
        self._name = name

    def __hash__(self) -> int:
        return hash((super().__hash__(), self.name))
input_decls: Dict[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue, classiq.interface.generator.arith.register_user_input.RegisterArithmeticInfo] pydantic-field

A mapping from the inputs names to the registers information. should be identical to the register defined in the function creation.

output_decls: Dict[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue, classiq.interface.generator.arith.register_user_input.RegisterArithmeticInfo] pydantic-field

A mapping from the outputs names to the registers information. should be identical to the register defined in the function creation.

validations special

flow_graph
Wire dataclass

Wire(start: Optional[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue] = None, end: Optional[classiq.interface.helpers.custom_pydantic_types.ConstrainedStrValue] = None)

Source code in classiq/interface/generator/validations/flow_graph.py
@dataclass
class Wire:
    start: Optional[PydanticNonEmptyString] = None
    end: Optional[PydanticNonEmptyString] = None

grover special

grover_modelling_params

GroverParams (BaseModel) pydantic-model
Source code in classiq/interface/grover/grover_modelling_params.py
class GroverParams(BaseModel):
    oracle: ArithmeticOracle = pydantic.Field(
        description="An arithmatic oracle for the grover search."
    )
    num_reps: int = pydantic.Field(
        default=1, description="The number of repetitions of the " "grover block."
    )
num_reps: int pydantic-field

The number of repetitions of the grover block.

oracle: ArithmeticOracle pydantic-field required

An arithmatic oracle for the grover search.

helpers special

versioned_model

VersionedModel (BaseModel) pydantic-model
Source code in classiq/interface/helpers/versioned_model.py
class VersionedModel(
    pydantic.BaseModel, extra=pydantic.Extra.forbid, json_encoders=CUSTOM_ENCODERS
):
    version: str = pydantic.Field(default=VERSION)
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

ide special

ide_data

IDEData (VersionedModel) pydantic-model
Source code in classiq/interface/ide/ide_data.py
class IDEData(VersionedModel):
    qubits: List[IDEDataQubit]
    operations: List[IDEDataOperation]
    register_data: List[RegisterData]
    segment_data: List[InterfaceSegmentData]
    circuit_metrics: Optional[CircuitMetrics]
    hardware_data: SynthesisHardwareData
    creation_time: str
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

jobs

JobDescriptionBase (GenericModel, Generic) pydantic-model

Source code in classiq/interface/jobs.py
class JobDescriptionBase(GenericModel, Generic[T], json_encoders=CUSTOM_ENCODERS):
    kind: str
    status: JobStatus
    description: Union[T, FailureDetails, Dict]
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

JobDescriptionBase[Any] (JobDescriptionBase) pydantic-model

Config
getter_dict (Representation)

Hack to make object's smell just enough like dicts for validate_model.

We can't inherit from Mapping[str, Any] because it upsets cython so we have to implement all methods ourselves.

get_field_info(name) classmethod

Get properties of FieldInfo from the fields property of the config class.

json_dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

Serialize obj to a JSON formatted str.

If skipkeys is true then dict keys that are not basic types (str, int, float, bool, None) will be skipped instead of raising a TypeError.

If ensure_ascii is false, then the return value can contain non-ASCII characters if they appear in strings contained in obj. Otherwise, all such characters are escaped in JSON strings.

If check_circular is false, then the circular reference check for container types will be skipped and a circular reference will result in an RecursionError (or worse).

If allow_nan is false, then it will be a ValueError to serialize out of range float values (nan, inf, -inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN, Infinity, -Infinity).

If indent is a non-negative integer, then JSON array elements and object members will be pretty-printed with that indent level. An indent level of 0 will only insert newlines. None is the most compact representation.

If specified, separators should be an (item_separator, key_separator) tuple. The default is (', ', ': ') if indent is None and (',', ': ') otherwise. To get the most compact JSON representation, you should specify (',', ':') to eliminate whitespace.

default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError.

If sort_keys is true (default: False), then the output of dictionaries will be sorted by key.

To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used.

Source code in classiq/interface/jobs.py
def dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True,
        allow_nan=True, cls=None, indent=None, separators=None,
        default=None, sort_keys=False, **kw):
    """Serialize ``obj`` to a JSON formatted ``str``.

    If ``skipkeys`` is true then ``dict`` keys that are not basic types
    (``str``, ``int``, ``float``, ``bool``, ``None``) will be skipped
    instead of raising a ``TypeError``.

    If ``ensure_ascii`` is false, then the return value can contain non-ASCII
    characters if they appear in strings contained in ``obj``. Otherwise, all
    such characters are escaped in JSON strings.

    If ``check_circular`` is false, then the circular reference check
    for container types will be skipped and a circular reference will
    result in an ``RecursionError`` (or worse).

    If ``allow_nan`` is false, then it will be a ``ValueError`` to
    serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in
    strict compliance of the JSON specification, instead of using the
    JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).

    If ``indent`` is a non-negative integer, then JSON array elements and
    object members will be pretty-printed with that indent level. An indent
    level of 0 will only insert newlines. ``None`` is the most compact
    representation.

    If specified, ``separators`` should be an ``(item_separator, key_separator)``
    tuple.  The default is ``(', ', ': ')`` if *indent* is ``None`` and
    ``(',', ': ')`` otherwise.  To get the most compact JSON representation,
    you should specify ``(',', ':')`` to eliminate whitespace.

    ``default(obj)`` is a function that should return a serializable version
    of obj or raise TypeError. The default simply raises TypeError.

    If *sort_keys* is true (default: ``False``), then the output of
    dictionaries will be sorted by key.

    To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
    ``.default()`` method to serialize additional types), specify it with
    the ``cls`` kwarg; otherwise ``JSONEncoder`` is used.

    """
    # cached encoder
    if (not skipkeys and ensure_ascii and
        check_circular and allow_nan and
        cls is None and indent is None and separators is None and
        default is None and not sort_keys and not kw):
        return _default_encoder.encode(obj)
    if cls is None:
        cls = JSONEncoder
    return cls(
        skipkeys=skipkeys, ensure_ascii=ensure_ascii,
        check_circular=check_circular, allow_nan=allow_nan, indent=indent,
        separators=separators, default=default, sort_keys=sort_keys,
        **kw).encode(obj)
json_loads(s, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)

Deserialize s (a str, bytes or bytearray instance containing a JSON document) to a Python object.

object_hook is an optional function that will be called with the result of any object literal decode (a dict). The return value of object_hook will be used instead of the dict. This feature can be used to implement custom decoders (e.g. JSON-RPC class hinting).

object_pairs_hook is an optional function that will be called with the result of any object literal decoded with an ordered list of pairs. The return value of object_pairs_hook will be used instead of the dict. This feature can be used to implement custom decoders. If object_hook is also defined, the object_pairs_hook takes priority.

parse_float, if specified, will be called with the string of every JSON float to be decoded. By default this is equivalent to float(num_str). This can be used to use another datatype or parser for JSON floats (e.g. decimal.Decimal).

parse_int, if specified, will be called with the string of every JSON int to be decoded. By default this is equivalent to int(num_str). This can be used to use another datatype or parser for JSON integers (e.g. float).

parse_constant, if specified, will be called with one of the following strings: -Infinity, Infinity, NaN. This can be used to raise an exception if invalid JSON numbers are encountered.

To use a custom JSONDecoder subclass, specify it with the cls kwarg; otherwise JSONDecoder is used.

Source code in classiq/interface/jobs.py
def loads(s, *, cls=None, object_hook=None, parse_float=None,
        parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):
    """Deserialize ``s`` (a ``str``, ``bytes`` or ``bytearray`` instance
    containing a JSON document) to a Python object.

    ``object_hook`` is an optional function that will be called with the
    result of any object literal decode (a ``dict``). The return value of
    ``object_hook`` will be used instead of the ``dict``. This feature
    can be used to implement custom decoders (e.g. JSON-RPC class hinting).

    ``object_pairs_hook`` is an optional function that will be called with the
    result of any object literal decoded with an ordered list of pairs.  The
    return value of ``object_pairs_hook`` will be used instead of the ``dict``.
    This feature can be used to implement custom decoders.  If ``object_hook``
    is also defined, the ``object_pairs_hook`` takes priority.

    ``parse_float``, if specified, will be called with the string
    of every JSON float to be decoded. By default this is equivalent to
    float(num_str). This can be used to use another datatype or parser
    for JSON floats (e.g. decimal.Decimal).

    ``parse_int``, if specified, will be called with the string
    of every JSON int to be decoded. By default this is equivalent to
    int(num_str). This can be used to use another datatype or parser
    for JSON integers (e.g. float).

    ``parse_constant``, if specified, will be called with one of the
    following strings: -Infinity, Infinity, NaN.
    This can be used to raise an exception if invalid JSON numbers
    are encountered.

    To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
    kwarg; otherwise ``JSONDecoder`` is used.
    """
    if isinstance(s, str):
        if s.startswith('\ufeff'):
            raise JSONDecodeError("Unexpected UTF-8 BOM (decode using utf-8-sig)",
                                  s, 0)
    else:
        if not isinstance(s, (bytes, bytearray)):
            raise TypeError(f'the JSON object must be str, bytes or bytearray, '
                            f'not {s.__class__.__name__}')
        s = s.decode(detect_encoding(s), 'surrogatepass')

    if (cls is None and object_hook is None and
            parse_int is None and parse_float is None and
            parse_constant is None and object_pairs_hook is None and not kw):
        return _default_decoder.decode(s)
    if cls is None:
        cls = JSONDecoder
    if object_hook is not None:
        kw['object_hook'] = object_hook
    if object_pairs_hook is not None:
        kw['object_pairs_hook'] = object_pairs_hook
    if parse_float is not None:
        kw['parse_float'] = parse_float
    if parse_int is not None:
        kw['parse_int'] = parse_int
    if parse_constant is not None:
        kw['parse_constant'] = parse_constant
    return cls(**kw).decode(s)
prepare_field(field) classmethod

Optional hook to check or modify fields during model creation.

__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

JobDescriptionFailure (JobDescriptionBase[Any]) pydantic-model

Source code in classiq/interface/jobs.py
class JobDescriptionFailure(JobDescriptionBase[Any]):
    kind: Literal["failure"] = pydantic.Field(default="failure")
    status: FailureStatus
    description: FailureDetails
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

JobDescriptionNonFinal (JobDescriptionBase[Any]) pydantic-model

Source code in classiq/interface/jobs.py
class JobDescriptionNonFinal(JobDescriptionBase[Any]):
    kind: Literal["non_final"] = pydantic.Field(default="non_final")
    status: NonFinalStatus
    description: Dict = Field(default_factory=dict)

    @pydantic.validator("description")
    def validate_empty_description(cls, description: Dict) -> Dict:
        if description:
            raise ValueError("Non-final job description must be empty")

        return description
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

JobDescriptionSuccess (JobDescriptionBase, Generic) pydantic-model

Source code in classiq/interface/jobs.py
class JobDescriptionSuccess(JobDescriptionBase[T], Generic[T]):
    kind: Literal["success"] = pydantic.Field(default="success")
    status: SuccessStatus = Field(default=JobStatus.COMPLETED)
    description: T
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

JobDescriptionUnion (GenericModel, Generic) pydantic-model

Source code in classiq/interface/jobs.py
class JobDescriptionUnion(GenericModel, Generic[T], json_encoders=CUSTOM_ENCODERS):
    __root__: Union[
        JobDescriptionSuccess[T], JobDescriptionFailure, JobDescriptionNonFinal
    ] = Field(discriminator="kind")
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

model special

call_synthesis_data

CallSynthesisData (Mapping, Generic) dataclass

CallSynthesisData(power: Union[classiq.interface.backend.pydantic_backend.ConstrainedStrValue, int] = 1, is_inverse: bool = False, control_states: List[classiq.interface.generator.control_state.ControlState] = , should_control: bool = True)

Source code in classiq/interface/model/call_synthesis_data.py
@dataclasses.dataclass
class CallSynthesisData(Mapping):
    power: PydanticPowerType = 1
    is_inverse: bool = False
    control_states: List[ControlState] = dataclasses.field(default_factory=list)
    should_control: bool = True

    def merge(self, other: "CallSynthesisData") -> "CallSynthesisData":
        return CallSynthesisData(
            power=_merge_power(self.power, other.power),
            is_inverse=self.is_inverse != other.is_inverse,
            control_states=self.control_states + other.control_states,
            should_control=self.should_control and other.should_control,
        )

    def set_control(self, ctrl_name: str, ctrl_size: int) -> None:
        self.control_states = [
            ControlState(
                name=ctrl_name,
                num_ctrl_qubits=ctrl_size,
            )
        ]

    def update_control_state(self, ctrl_size: int, ctrl_state: str) -> None:
        prev_ctrl_state = self.control_states.pop()
        self.control_states.append(
            ControlState(
                name=prev_ctrl_state.name,
                num_ctrl_qubits=ctrl_size,
                ctrl_state=ctrl_state,
            )
        )

    @property
    def has_control(self) -> bool:
        return bool(self.control_states)

    def __getitem__(self, key: str) -> Any:
        return dataclasses.asdict(self)[key]

    def __iter__(self) -> Iterator[str]:
        return iter(dataclasses.asdict(self))

    def __len__(self) -> int:
        return len(dataclasses.asdict(self))

handle_binding

HandleBinding (ASTNode) pydantic-model
Source code in classiq/interface/model/handle_binding.py
class HandleBinding(ASTNode):
    name: str

    class Config:
        frozen = True
        extra = Extra.forbid

    def __str__(self) -> str:
        return self.name

    def is_bindable(self) -> bool:
        return True
__str__(self) special

Return str(self).

Source code in classiq/interface/model/handle_binding.py
def __str__(self) -> str:
    return self.name

model

Model (VersionedModel, ASTNode) pydantic-model

All the relevant data for generating quantum circuit in one place.

Source code in classiq/interface/model/model.py
class Model(VersionedModel, ASTNode):
    """
    All the relevant data for generating quantum circuit in one place.
    """

    kind: Literal["user"] = pydantic.Field(default=USER_MODEL_MARKER)

    # Must be validated before logic_flow
    functions: List[NativeFunctionDefinition] = pydantic.Field(
        default_factory=list,
        description="The user-defined custom type library.",
    )

    types: List[StructDeclaration] = pydantic.Field(
        default_factory=list,
        description="The user-defined custom function library.",
    )

    classical_execution_code: str = pydantic.Field(
        description="The classical execution code of the model", default=""
    )

    constants: List[Constant] = pydantic.Field(
        default_factory=list,
    )

    constraints: Constraints = pydantic.Field(default_factory=Constraints)

    execution_preferences: ExecutionPreferences = pydantic.Field(
        default_factory=ExecutionPreferences
    )
    preferences: Preferences = pydantic.Field(default_factory=Preferences)

    @property
    def main_func(self) -> NativeFunctionDefinition:
        return self.function_dict[MAIN_FUNCTION_NAME]  # type:ignore[return-value]

    @property
    def body(self) -> StatementBlock:
        return self.main_func.body

    @pydantic.validator("preferences", always=True)
    def _seed_suffix_randomizer(cls, preferences: Preferences) -> Preferences:
        SUFFIX_RANDOMIZER.seed(preferences.random_seed)
        return preferences

    def _get_qualified_direction(
        self, port_name: str, direction: PortDeclarationDirection
    ) -> PortDeclarationDirection:
        if port_name in self.main_func.port_declarations:
            return PortDeclarationDirection.Inout
        return direction

    @property
    def function_dict(self) -> Dict[str, QuantumFunctionDeclaration]:
        return nameables_to_dict(self.functions)

    @pydantic.validator("functions", always=True)
    def _add_empty_main(
        cls, functions: List[NativeFunctionDefinition]
    ) -> List[NativeFunctionDefinition]:
        function_dict = nameables_to_dict(functions)
        if MAIN_FUNCTION_NAME not in function_dict:
            functions.append(_create_empty_main_function())
        return functions

    @pydantic.root_validator()
    def validate_static_correctness(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        functions: Optional[List[QuantumFunctionDeclaration]] = values.get("functions")
        if functions is None:
            return values

        resolve_function_calls(
            values,
            nameables_to_dict(functions),
        )
        for func_def in functions:
            if isinstance(func_def, NativeFunctionDefinition):
                func_def.validate_body()
        return values

    @pydantic.validator("types")
    def types_validator(cls, types: List[StructDeclaration]) -> List[StructDeclaration]:
        user_defined_types: Set[str] = set()
        for ctype in types:
            if ctype.name in StructDeclaration.BUILTIN_STRUCT_DECLARATIONS:
                raise ClassiqValueError(
                    TYPE_NAME_CONFLICT_BUILTIN.format(name=ctype.name)
                )
            if ctype.name in user_defined_types:
                raise ClassiqValueError(TYPE_NAME_CONFLICT_USER.format(name=ctype.name))
            user_defined_types.add(ctype.name)

        return types

    def get_model(self) -> SerializedModel:
        return SerializedModel(
            self.json(exclude_defaults=True, exclude_unset=True, indent=2)
        )

    @pydantic.validator("functions")
    def _validate_entry_point(
        cls, functions: List[NativeFunctionDefinition]
    ) -> List[NativeFunctionDefinition]:
        function_dict = nameables_to_dict(functions)
        if MAIN_FUNCTION_NAME not in function_dict:
            raise ClassiqValueError("The model must contain a `main` function")
        if any(
            pd.direction != PortDeclarationDirection.Output
            for pd in function_dict[MAIN_FUNCTION_NAME].port_declarations.values()
        ):
            raise ClassiqValueError("Function 'main' cannot declare quantum inputs")

        return functions

    @pydantic.validator("constants")
    def _validate_constants(cls, constants: List[Constant]) -> List[Constant]:
        constant_definition_counts = Counter(
            [constant.name for constant in constants]
        ).items()
        multiply_defined_constants = {
            constant for constant, count in constant_definition_counts if count > 1
        }
        if len(multiply_defined_constants) > 0:
            raise ClassiqValueError(
                f"The following constants were defined more than once: "
                f"{multiply_defined_constants}"
            )
        return constants
classical_execution_code: str pydantic-field

The classical execution code of the model

functions: List[classiq.interface.model.native_function_definition.NativeFunctionDefinition] pydantic-field

The user-defined custom type library.

types: List[classiq.interface.generator.types.struct_declaration.StructDeclaration] pydantic-field

The user-defined custom function library.

__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

VersionedSerializedModel (VersionedModel) pydantic-model
Source code in classiq/interface/model/model.py
class VersionedSerializedModel(VersionedModel):
    model: SerializedModel
__json_encoder__(obj) special staticmethod

partial(func, args, *keywords) - new function with partial application of the given arguments and keywords.

native_function_definition

NativeFunctionDefinition (QuantumFunctionDeclaration) pydantic-model

Facilitates the creation of a user-defined composite function

This class sets extra to forbid so that it can be used in a Union and not "steal" objects from other classes.

Source code in classiq/interface/model/native_function_definition.py
class NativeFunctionDefinition(QuantumFunctionDeclaration):
    """
    Facilitates the creation of a user-defined composite function

    This class sets extra to forbid so that it can be used in a Union and not "steal"
    objects from other classes.
    """

    body: StatementBlock = pydantic.Field(
        default_factory=list, description="List of function calls to perform."
    )

    def validate_body(self) -> None:
        handle_validator = HandleValidator(self.port_declarations)

        for statement in self.body:
            if isinstance(statement, VariableDeclarationStatement):
                handle_validator.handle_variable_declaration(statement)
            else:
                handle_validator.handle_operation(statement)

        handle_validator.report_errored_handles(ClassiqValueError)
body: List[Union[classiq.interface.model.quantum_function_call.QuantumFunctionCall, classiq.interface.model.quantum_expressions.arithmetic_operation.ArithmeticOperation, classiq.interface.model.quantum_expressions.amplitude_loading_operation.AmplitudeLoadingOperation, classiq.interface.model.variable_declaration_statement.VariableDeclarationStatement, classiq.interface.model.bind_operation.BindOperation, classiq.interface.model.inplace_binary_operation.InplaceBinaryOperation, classiq.interface.model.repeat.Repeat, classiq.interface.model.power.Power, classiq.interface.model.invert.Invert, classiq.interface.model.classical_if.ClassicalIf, classiq.interface.model.control.Control, classiq.interface.model.within_apply_operation.WithinApply]] pydantic-field

List of function calls to perform.

quantum_expressions special

arithmetic_operation
ArithmeticOperation (QuantumAssignmentOperation) pydantic-model
Source code in classiq/interface/model/quantum_expressions/arithmetic_operation.py
class ArithmeticOperation(QuantumAssignmentOperation):
    inplace_result: bool = pydantic.Field(
        description="Determines whether the result variable is initialized",
    )

    def initialize_var_types(
        self,
        var_types: Dict[str, QuantumType],
        machine_precision: int,
    ) -> None:
        super().initialize_var_types(var_types, machine_precision)
        self._result_type = compute_arithmetic_result_type(
            self.expression.expr, var_types, machine_precision
        )

    @property
    def wiring_inouts(
        self,
    ) -> Mapping[
        str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
    ]:
        inouts = dict(super().wiring_inouts)
        if self.inplace_result:
            inouts[self.result_name()] = self.result_var
        return inouts

    @property
    def wiring_outputs(self) -> Mapping[str, HandleBinding]:
        if self.inplace_result:
            return {}
        return super().wiring_outputs

    @classmethod
    def result_name(cls) -> str:
        return ARITHMETIC_EXPRESSION_RESULT_NAME
inplace_result: bool pydantic-field required

Determines whether the result variable is initialized

quantum_expression
QuantumAssignmentOperation (QuantumExpressionOperation) pydantic-model
Source code in classiq/interface/model/quantum_expressions/quantum_expression.py
class QuantumAssignmentOperation(QuantumExpressionOperation):
    result_var: HandleBinding = pydantic.Field(
        description="The variable storing the expression result"
    )
    _result_type: Optional[QuantumType] = pydantic.PrivateAttr(
        default=None,
    )

    @property
    def result_type(self) -> QuantumType:
        assert self._result_type is not None
        return self._result_type

    @property
    def wiring_outputs(self) -> Mapping[str, HandleBinding]:
        return {self.result_name(): self.result_var}

    @classmethod
    @abc.abstractmethod
    def result_name(cls) -> str:
        raise NotImplementedError()
result_var: HandleBinding pydantic-field required

The variable storing the expression result

VarRefCollector (NodeVisitor)
Source code in classiq/interface/model/quantum_expressions/quantum_expression.py
class VarRefCollector(ast.NodeVisitor):
    def __init__(self) -> None:
        self.var_names: Set[str] = set()

    def generic_visit(self, node: ast.AST) -> None:
        if isinstance(node, ast.Name) and node.id not in set(
            SYMPY_SUPPORTED_EXPRESSIONS
        ) | set(DEFAULT_SUPPORTED_FUNC_NAMES):
            self.var_names.add(node.id)
        super().generic_visit(node)
generic_visit(self, node)

Called if no explicit visitor function exists for a node.

Source code in classiq/interface/model/quantum_expressions/quantum_expression.py
def generic_visit(self, node: ast.AST) -> None:
    if isinstance(node, ast.Name) and node.id not in set(
        SYMPY_SUPPORTED_EXPRESSIONS
    ) | set(DEFAULT_SUPPORTED_FUNC_NAMES):
        self.var_names.add(node.id)
    super().generic_visit(node)

quantum_function_call

QuantumFunctionCall (QuantumOperation) pydantic-model
Source code in classiq/interface/model/quantum_function_call.py
class QuantumFunctionCall(QuantumOperation):
    function: Union[str, OperandIdentifier] = pydantic.Field(
        description="The function that is called"
    )
    params: Dict[str, Expression] = pydantic.Field(default_factory=dict)
    inputs: Dict[str, HandleBinding] = pydantic.Field(
        default_factory=dict,
        description="A mapping from the input name to the wire it connects to",
    )
    inouts: Dict[
        str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
    ] = pydantic.Field(
        default_factory=dict,
        description="A mapping from in/out name to the wires that connect to it",
    )
    outputs: Dict[str, HandleBinding] = pydantic.Field(
        default_factory=dict,
        description="A mapping from the output name to the wire it connects to",
    )
    operands: Dict[str, QuantumOperand] = pydantic.Field(
        description="Function calls passed to the operator",
        default_factory=dict,
    )
    positional_args: List[ArgValue] = pydantic.Field(default_factory=list)

    _func_decl: Optional[QuantumFunctionDeclaration] = pydantic.PrivateAttr(
        default=None
    )

    _synthesis_data: CallSynthesisData = pydantic.PrivateAttr(
        default_factory=CallSynthesisData
    )

    @property
    def func_decl(self) -> QuantumFunctionDeclaration:
        if self._func_decl is None:
            raise ClassiqError("Accessing an unresolved quantum function call")

        return self._func_decl

    def set_func_decl(self, fd: Optional[FunctionDeclaration]) -> None:
        if fd is not None and not isinstance(fd, QuantumFunctionDeclaration):
            raise ClassiqValueError(
                "the declaration of a quantum function call cannot be set to a non-quantum function declaration."
            )
        self._func_decl = fd

    @property
    def func_name(self) -> str:
        if isinstance(self.function, OperandIdentifier):
            return self.function.name
        return self.function

    @property
    def wiring_inputs(self) -> Mapping[str, HandleBinding]:
        return self.inputs

    @property
    def wiring_inouts(
        self,
    ) -> Mapping[
        str, Union[SlicedHandleBinding, SubscriptHandleBinding, HandleBinding]
    ]:
        return self.inouts

    @property
    def wiring_outputs(self) -> Mapping[str, HandleBinding]:
        return self.outputs

    def get_positional_args(self) -> List[ArgValue]:
        result: List[ArgValue] = self.positional_args
        if not result:
            result = list(self.params.values())
            result.extend(self.operands.values())
            result.extend(self.inputs.values())
            result.extend(self.inouts.values())
            result.extend(self.outputs.values())
        return result

    @property
    def pos_param_args(self) -> Dict[str, Expression]:
        return dict(
            zip(
                self.func_decl.param_decls.keys(),
                (
                    param
                    for param in self.positional_args
                    if isinstance(param, Expression)
                ),
            )
        )

    @property
    def pos_operand_args(self) -> Dict[str, "QuantumOperand"]:
        return dict(
            zip(
                self.func_decl.operand_declarations.keys(),
                (
                    param
                    for param in self.positional_args
                    if not isinstance(param, (Expression, HandleBinding))
                ),
            )
        )

    @property
    def pos_port_args(self) -> Dict[str, HandleBinding]:
        return dict(
            zip(
                self.func_decl.port_declarations.keys(),
                (
                    param
                    for param in self.positional_args
                    if isinstance(param, HandleBinding)
                ),
            )
        )

    def _update_pos_port_params(self) -> None:
        for name, port_decl in self.func_decl.port_declarations.items():
            if port_decl.direction == PortDeclarationDirection.Input:
                self.inputs[name] = self.pos_port_args[name]
            elif port_decl.direction == PortDeclarationDirection.Output:
                self.outputs[name] = self.pos_port_args[name]
            else:
                self.inouts[name] = self.pos_port_args[name]

    def _reduce_positional_args_to_keywords(self) -> None:
        self.params.update(self.pos_param_args)
        self.operands.update(self.pos_operand_args)
        self._update_pos_port_params()

    def resolve_function_decl(
        self,
        function_dict: Mapping[str, QuantumFunctionDeclaration],
        check_operands: bool,
    ) -> None:
        if self._func_decl is None:
            func_decl = function_dict.get(self.func_name)
            if func_decl is None:
                raise ClassiqValueError(
                    f"Error resolving function {self.func_name}, the function is not found in included library."
                )
            self.set_func_decl(func_decl)

        if self.positional_args:
            self._reduce_positional_args_to_keywords()

        _check_params_against_declaration(
            set(self.params.keys()),
            set(self.func_decl.param_decls.keys()),
            self.func_decl.name,
        )
        _check_ports_against_declaration(self, self.func_decl)
        _check_params_against_declaration(
            set(self.operands.keys()),
            set(self.func_decl.operand_declarations.keys()),
            self.func_name,
        )
        if check_operands:
            _check_operands_against_declaration(self, self.func_decl, function_dict)

        for name, op in self.operands.items():
            op_decl = self.func_decl.operand_declarations[name]
            for qlambda in get_lambda_defs(op):
                if isinstance(qlambda, QuantumLambdaFunction):
                    qlambda.set_op_decl(op_decl)

    @property
    def synthesis_data(self) -> CallSynthesisData:
        return self._synthesis_data

    def merge_synthesis_data(self, other: CallSynthesisData) -> None:
        self._synthesis_data = self._synthesis_data.merge(other)

    @pydantic.root_validator()
    def validate_handles(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        inputs = values.get("inputs", dict())
        outputs = values.get("outputs", dict())
        inouts = values.get("inouts", dict())

        _validate_no_duplicated_ports(inputs, outputs, inouts)
        _validate_no_duplicated_handles(inputs, outputs, inouts)
        _validate_no_mixing_sliced_and_whole_handles(inouts)

        return values
function: Union[str, classiq.interface.model.quantum_function_call.OperandIdentifier] pydantic-field required

The function that is called

inouts: Dict[str, Union[classiq.interface.model.handle_binding.SlicedHandleBinding, classiq.interface.model.handle_binding.SubscriptHandleBinding, classiq.interface.model.handle_binding.HandleBinding]] pydantic-field

A mapping from in/out name to the wires that connect to it

inputs: Dict[str, classiq.interface.model.handle_binding.HandleBinding] pydantic-field

A mapping from the input name to the wire it connects to

operands: Dict[str, Union[str, classiq.interface.model.quantum_lambda_function.QuantumLambdaFunction, List[Union[str, classiq.interface.model.quantum_lambda_function.QuantumLambdaFunction]], classiq.interface.model.quantum_lambda_function.LambdaListComprehension]] pydantic-field

Function calls passed to the operator

outputs: Dict[str, classiq.interface.model.handle_binding.HandleBinding] pydantic-field

A mapping from the output name to the wire it connects to

quantum_function_declaration

QuantumFunctionDeclaration (FunctionDeclaration) pydantic-model

Facilitates the creation of a common quantum function interface object.

Source code in classiq/interface/model/quantum_function_declaration.py
class QuantumFunctionDeclaration(FunctionDeclaration):
    """
    Facilitates the creation of a common quantum function interface object.
    """

    port_declarations: Dict[str, PortDeclaration] = pydantic.Field(
        description="The input and output ports of the function.",
        default_factory=dict,
    )

    operand_declarations: Mapping[str, "QuantumOperandDeclaration"] = pydantic.Field(
        description="The expected interface of the quantum function operands",
        default_factory=dict,
    )

    positional_arg_declarations: List[PositionalArg] = pydantic.Field(
        default_factory=list
    )

    BUILTIN_FUNCTION_DECLARATIONS: ClassVar[Dict[str, "QuantumFunctionDeclaration"]] = (
        {}
    )

    @property
    def input_set(self) -> Set[str]:
        return set(self.inputs.keys())

    @property
    def output_set(self) -> Set[str]:
        return set(self.outputs.keys())

    @property
    def inputs(self) -> ArithmeticIODict:
        return _ports_to_registers(self.port_declarations, PortDirection.Input)

    @property
    def outputs(self) -> ArithmeticIODict:
        return _ports_to_registers(self.port_declarations, PortDirection.Output)

    def update_logic_flow(
        self, function_dict: Mapping[str, "QuantumFunctionDeclaration"]
    ) -> None:
        pass

    @property
    def port_names(self) -> List[str]:
        return list(self.port_declarations.keys())

    @property
    def operand_names(self) -> List[str]:
        return list(self.operand_declarations.keys())

    def ports_by_direction(
        self, direction: PortDirection
    ) -> Mapping[str, PortDeclaration]:
        return {
            name: port
            for name, port in self.port_declarations.items()
            if port.direction.includes_port_direction(direction)
        }

    def ports_by_declaration_direction(
        self, direction: PortDeclarationDirection
    ) -> Set[str]:
        return {
            name
            for name, port in self.port_declarations.items()
            if port.direction == direction
        }

    def get_positional_arg_decls(self) -> List[PositionalArg]:
        result: List[PositionalArg] = self.positional_arg_declarations
        if not result:
            result = [
                ClassicalParameterDeclaration(name=name, classical_type=ctype)
                for name, ctype in self.param_decls.items()
            ]
            result.extend(self.operand_declarations.values())
            result.extend(self.port_declarations.values())
        return result

    @pydantic.validator("operand_declarations")
    def _validate_operand_declarations_names(
        cls, operand_declarations: Dict[str, "QuantumOperandDeclaration"]
    ) -> Dict[str, "QuantumOperandDeclaration"]:
        validate_nameables_mapping(operand_declarations, "Operand")
        return operand_declarations

    @pydantic.validator("port_declarations")
    def _validate_port_declarations_names(
        cls, port_declarations: Dict[str, PortDeclaration]
    ) -> Dict[str, PortDeclaration]:
        validate_nameables_mapping(port_declarations, "Port")
        return port_declarations

    @pydantic.root_validator()
    def _validate_params_and_operands_uniqueness(
        cls, values: Dict[str, Any]
    ) -> Dict[str, Any]:
        operand_declarations = values.get("operand_declarations")
        parameter_declarations = values.get("param_decls")
        port_declarations = values.get("port_declarations")
        operand_parameter = validate_nameables_no_overlap(
            operand_declarations, parameter_declarations, "operand", "parameter"
        )
        operand_port = validate_nameables_no_overlap(
            operand_declarations, port_declarations, "operand", "port"
        )
        parameter_port = validate_nameables_no_overlap(
            parameter_declarations, port_declarations, "parameter", "port"
        )
        error_message = ",".join(
            msg
            for msg in [operand_parameter, operand_port, parameter_port]
            if msg is not None
        )

        if error_message:
            raise ClassiqValueError(error_message)

        return values

    @pydantic.root_validator()
    def _reduce_positional_declarations_to_keyword(
        cls, values: Dict[str, Any]
    ) -> Dict[str, Any]:
        operand_declarations = values.get("operand_declarations", dict())
        parameter_declarations = values.get("param_decls", dict())
        port_declarations = values.get("port_declarations", dict())

        positional_arg_declarations = values.get("positional_arg_declarations", list())

        _populate_declaration_dicts_with_positional_lists(
            positional_arg_declarations,
            parameter_declarations,
            ClassicalParameterDeclaration,
        )
        _populate_declaration_dicts_with_positional_lists(
            positional_arg_declarations,
            operand_declarations,
            QuantumOperandDeclaration,
        )
        _populate_declaration_dicts_with_positional_lists(
            positional_arg_declarations, port_declarations, PortDeclaration
        )

        values["operand_declarations"] = operand_declarations
        values["param_decls"] = parameter_declarations
        values["port_declarations"] = port_declarations

        return values
operand_declarations: Mapping[str, QuantumOperandDeclaration] pydantic-field

The expected interface of the quantum function operands

port_declarations: Dict[str, classiq.interface.model.port_declaration.PortDeclaration] pydantic-field

The input and output ports of the function.

QuantumOperandDeclaration (QuantumFunctionDeclaration) pydantic-model
Source code in classiq/interface/model/quantum_function_declaration.py
class QuantumOperandDeclaration(QuantumFunctionDeclaration):
    is_list: bool = pydantic.Field(
        description="Indicate whether the operand expects an unnamed list of lambdas",
        default=False,
    )
is_list: bool pydantic-field

Indicate whether the operand expects an unnamed list of lambdas

quantum_lambda_function

LambdaListComprehension (ASTNode) pydantic-model

Specification of a list of lambda functions iteratively

Source code in classiq/interface/model/quantum_lambda_function.py
class LambdaListComprehension(ASTNode):
    """
    Specification of a list of lambda functions iteratively
    """

    count: Expression = pydantic.Field(
        description="The number of lambda functions in the list"
    )

    index_var: str = pydantic.Field(
        description="The name of the integer variable holding the iteration index"
    )

    func: QuantumLambdaFunction = pydantic.Field(
        description="A lambda function definition replicated for index values 0 to count-1"
    )
count: Expression pydantic-field required

The number of lambda functions in the list

func: QuantumLambdaFunction pydantic-field required

A lambda function definition replicated for index values 0 to count-1

index_var: str pydantic-field required

The name of the integer variable holding the iteration index

QuantumLambdaFunction (ASTNode) pydantic-model

The definition of an anonymous function passed as operand to higher-level functions

Source code in classiq/interface/model/quantum_lambda_function.py
class QuantumLambdaFunction(ASTNode):
    """
    The definition of an anonymous function passed as operand to higher-level functions
    """

    rename_params: Dict[str, str] = pydantic.Field(
        default_factory=dict,
        description="Mapping of the declared param to the actual variable name used ",
    )

    body: "StatementBlock" = pydantic.Field(
        description="A list of function calls passed to the operator"
    )

    _func_decl: Optional[QuantumOperandDeclaration] = pydantic.PrivateAttr(default=None)

    @property
    def func_decl(self) -> Optional[QuantumOperandDeclaration]:
        return self._func_decl

    def set_op_decl(self, fd: QuantumOperandDeclaration) -> None:
        self._func_decl = fd
body: List[Union[classiq.interface.model.quantum_function_call.QuantumFunctionCall, classiq.interface.model.quantum_expressions.arithmetic_operation.ArithmeticOperation, classiq.interface.model.quantum_expressions.amplitude_loading_operation.AmplitudeLoadingOperation, classiq.interface.model.variable_declaration_statement.VariableDeclarationStatement, classiq.interface.model.bind_operation.BindOperation, classiq.interface.model.inplace_binary_operation.InplaceBinaryOperation, classiq.interface.model.repeat.Repeat, classiq.interface.model.power.Power, classiq.interface.model.invert.Invert, classiq.interface.model.classical_if.ClassicalIf, classiq.interface.model.control.Control, classiq.interface.model.within_apply_operation.WithinApply]] pydantic-field required

A list of function calls passed to the operator

rename_params: Dict[str, str] pydantic-field

Mapping of the declared param to the actual variable name used

quantum_register

QReg

Represents a logical sequence of qubits. The QReg can be used as an in_wires or out_wires argument to Model function calls, assisting in model connectivity.

Source code in classiq/interface/model/quantum_register.py
class QReg:
    """Represents a logical sequence of qubits.
    The QReg can be used as an `in_wires` or `out_wires` argument to Model function calls,
    assisting in model connectivity.
    """

    def __init__(self, size: int) -> None:
        """Initializes a new QReg with the specified number of qubits.

        Args:
            size (int): The number of qubits in the QReg.
        """
        if size <= 0:
            raise ClassiqQRegError(f"Cannot create {size} new qubits")
        self._qubits = [Qubit() for _ in range(size)]

    @classmethod
    def _from_qubits(cls, qubits: List[Qubit]) -> "QReg":
        if (
            not isinstance(qubits, list)
            or not all(isinstance(qubit, Qubit) for qubit in qubits)
            or len(qubits) == 0
        ):
            raise ClassiqQRegError(f"Cannot create QReg from {qubits}")
        qreg = cls(size=1)
        qreg._qubits = qubits
        return qreg

    def __getitem__(self, key: Union[int, slice]) -> "QReg":
        state = self._qubits[key]
        return QReg._from_qubits(state if isinstance(state, list) else [state])

    def __setitem__(self, key: Union[int, slice], value: "QReg") -> None:
        if isinstance(key, int) and len(value) != 1:
            raise ClassiqQRegError(
                f"Size mismatch: value size {len(value)}, expected size 1"
            )
        self._qubits[key] = value._qubits[0] if isinstance(key, int) else value._qubits  # type: ignore[call-overload]

    def __iter__(self) -> Iterator["QReg"]:
        return iter([self[idx] for idx in range(len(self))])

    def __eq__(self, other: Any) -> bool:
        return isinstance(other, QReg) and self._qubits == other._qubits

    def isoverlapping(self, other: "QReg") -> bool:
        return isinstance(other, QReg) and not set(self._qubits).isdisjoint(
            set(other._qubits)
        )

    @classmethod
    def concat(cls, *qregs: "QReg") -> "QReg":
        """Concatenate two QRegs.

        Args:
            qregs: the QRegs to concat in order, as separate arguments.

        Returns:
            A QReg representing the concatenation of the given QRegs.

        """
        qubits = list(itertools.chain.from_iterable(qreg._qubits for qreg in qregs))
        return cls._from_qubits(qubits)

    def __len__(self) -> int:
        return len(self._qubits)

    @property
    def qubits(self) -> List[Qubit]:
        return self._qubits

    def __class_getitem__(cls, params: Any) -> QRegGenericAlias:
        # Supporting python 3.7+, thus returning `typing._GenericAlias` instead of `types.GenericAlias`
        if isinstance(params, int):
            return QRegGenericAlias(cls, params)

        raise ClassiqQRegError(f"Invalid size: {params} ; int required")

    def to_register_user_input(self, name: str = "") -> RegisterUserInput:
        fraction_places = getattr(self, "fraction_places", 0)
        is_signed = getattr(self, "is_signed", False)
        return RegisterUserInput(
            name=name,
            size=len(self),
            is_signed=is_signed,
            fraction_places=fraction_places,
        )

    @staticmethod
    def from_arithmetic_info(info: RegisterArithmeticInfo) -> "QReg":
        method = _get_qreg_type_from_arithmetic_info(info)
        frac_attr = {"fraction_places": info.fraction_places} if info.is_frac else {}
        return method(size=info.size, **frac_attr)
__init__(self, size) special

Initializes a new QReg with the specified number of qubits.

Parameters:

Name Type Description Default
size int

The number of qubits in the QReg.

required
Source code in classiq/interface/model/quantum_register.py
def __init__(self, size: int) -> None:
    """Initializes a new QReg with the specified number of qubits.

    Args:
        size (int): The number of qubits in the QReg.
    """
    if size <= 0:
        raise ClassiqQRegError(f"Cannot create {size} new qubits")
    self._qubits = [Qubit() for _ in range(size)]
concat(*qregs) classmethod

Concatenate two QRegs.

Parameters:

Name Type Description Default
qregs QReg

the QRegs to concat in order, as separate arguments.

()

Returns:

Type Description
QReg

A QReg representing the concatenation of the given QRegs.

Source code in classiq/interface/model/quantum_register.py
@classmethod
def concat(cls, *qregs: "QReg") -> "QReg":
    """Concatenate two QRegs.

    Args:
        qregs: the QRegs to concat in order, as separate arguments.

    Returns:
        A QReg representing the concatenation of the given QRegs.

    """
    qubits = list(itertools.chain.from_iterable(qreg._qubits for qreg in qregs))
    return cls._from_qubits(qubits)

validation_handle

ValidationHandle dataclass

ValidationHandle(initial_state: Optional[classiq.interface.model.validation_handle.HandleState] = None, errors: Optional[List[str]] = None)

Source code in classiq/interface/model/validation_handle.py
@dataclasses.dataclass
class ValidationHandle:
    _state: HandleState
    errors: List[str] = dataclasses.field(default_factory=list)

    def __init__(
        self,
        initial_state: Optional[HandleState] = None,
        errors: Optional[List[str]] = None,
    ) -> None:
        if initial_state is None and not errors:
            raise ClassiqError("Missing initial state for ValidationHandle")

        self._state = initial_state or HandleState.ERRORED
        self.errors = errors or []

    @property
    def state(self) -> HandleState:
        return self._state

    def append_error(self, error: str) -> None:
        self.errors.append(error)
        self._state = HandleState.ERRORED

    def initialize(self) -> None:
        self._state = HandleState.INITIALIZED

    def uninitialize(self) -> None:
        self._state = HandleState.UNINITIALIZED

qmod special

cfunc

get_caller_locals()

Print the local variables in the caller's frame.

Source code in classiq/qmod/cfunc.py
def get_caller_locals() -> Dict[str, Any]:
    """Print the local variables in the caller's frame."""
    import inspect

    frame = inspect.currentframe()
    try:
        assert frame is not None
        cfunc_frame = frame.f_back
        assert cfunc_frame is not None
        caller_frame = cfunc_frame.f_back
        assert caller_frame is not None

        return caller_frame.f_locals
    finally:
        # See here for information about the `del`
        # https://docs.python.org/3/library/inspect.html#the-interpreter-stack
        del frame

native special

expression_to_qmod

ASTToQMODCode dataclass

ASTToQMODCode(level: int, decimal_precision: int, indent_seq: str = ' ')

Source code in classiq/qmod/native/expression_to_qmod.py
@dataclass
class ASTToQMODCode:
    level: int
    decimal_precision: int
    indent_seq: str = "  "

    @property
    def indent(self) -> str:
        return self.level * self.indent_seq

    def visit(self, node: ast.AST) -> str:
        return self.ast_to_code(node)

    def ast_to_code(self, node: ast.AST) -> str:
        if isinstance(node, ast.Module):
            return self.indent.join(self.ast_to_code(child) for child in node.body)
        elif isinstance(node, ast.Attribute):
            # Enum attribute access
            if not isinstance(node.attr, str):
                raise AssertionError("Error parsing enum attribute access")
            access_operator = "." if node.attr in CLASSICAL_ATTRIBUTES else "::"
            return f"{self.ast_to_code(node.value)!s}{access_operator}{node.attr!s}"
        elif isinstance(node, ast.Name):
            return node.id
        elif isinstance(node, ast.Num):
            return str(np.round(node.n, self.decimal_precision))
        elif isinstance(node, ast.Str):
            return repr(node.s)
        elif isinstance(node, ast.Constant):
            return repr(node.value)
        elif isinstance(node, ast.BinOp):
            return "({} {} {})".format(
                self.ast_to_code(node.left),
                BINARY_OPS[type(node.op)],
                self.ast_to_code(node.right),
            )
        elif isinstance(node, ast.UnaryOp):
            unary_op = UNARY_OPS[type(node.op)]
            space = " " if unary_op == "not" else ""
            return f"({unary_op}{space}{self.ast_to_code(node.operand)})"
        elif isinstance(node, ast.BoolOp):
            return "({})".format(
                (" " + BOOL_OPS[type(node.op)] + " ").join(
                    self.ast_to_code(value) for value in node.values
                )
            )
        elif isinstance(node, ast.Compare):
            if len(node.ops) != 1 or len(node.comparators) != 1:
                raise AssertionError("Error parsing comparison expression.")
            return "({} {} {})".format(
                self.ast_to_code(node.left),
                COMPARE_OPS[type(node.ops[0])],
                self.ast_to_code(node.comparators[0]),
            )
        elif isinstance(node, ast.List):
            elts = node.elts
            elements = self.indent_items(
                lambda: [self.ast_to_code(element) for element in elts]
            )
            return f"[{elements}]"
        elif isinstance(node, ast.Subscript):
            return f"{self.ast_to_code(node.value)}[{_remove_redundant_parentheses(self.ast_to_code(node.slice))}]"
        elif isinstance(node, ast.Slice):
            # A QMOD expression does not support slice step
            if node.lower is None or node.upper is None or node.step is not None:
                raise AssertionError("Error parsing slice expression.")
            return f"{self.ast_to_code(node.lower)}:{self.ast_to_code(node.upper)}"
        elif isinstance(node, ast.Call):
            func = self.ast_to_code(node.func)
            if func == "get_field":
                if len(node.args) != 2:
                    raise AssertionError("Error parsing struct field access.")
                field = str(self.ast_to_code(node.args[1])).replace("'", "")
                if not IDENTIFIER.match(field):
                    raise AssertionError("Error parsing struct field access.")
                return f"{self.ast_to_code(node.args[0])}.{field}"
            elif func == "struct_literal":
                if len(node.args) != 1 or not isinstance(node.args[0], ast.Name):
                    raise AssertionError("Error parsing struct literal.")
                keywords = node.keywords
                initializer_list = self.indent_items(
                    lambda: [
                        f"{keyword.arg} = {self._cleaned_ast_to_code(keyword.value)}"
                        for keyword in keywords
                        if keyword.arg is not None
                    ]
                )
                return f"{self.ast_to_code(node.args[0])} {{{initializer_list}}}"
            else:
                return "{}({})".format(
                    func, ", ".join(self._cleaned_ast_to_code(arg) for arg in node.args)
                )
        elif isinstance(node, ast.Expr):
            return self._cleaned_ast_to_code(node.value)
        else:
            raise AssertionError("Error parsing expression: unsupported AST node.")

    def indent_items(self, items: Callable[[], List[str]]) -> str:
        should_indent = (
            len("".join([i.strip() for i in items()])) >= LIST_FORMAT_CHAR_LIMIT
        )
        if should_indent:
            self.level += 1
            left_ws = "\n" + self.indent
            inner_ws = ",\n" + self.indent
        else:
            left_ws = ""
            inner_ws = ", "
        items_ = items()
        if should_indent:
            self.level -= 1
            right_ws = "\n" + self.indent
        else:
            right_ws = ""
        return f"{left_ws}{inner_ws.join(items_)}{right_ws}"

    def _cleaned_ast_to_code(self, node: ast.AST) -> str:
        return _remove_redundant_parentheses(self.ast_to_code(node))