Skip to content

Commit

Permalink
Deprecate cost estimation in azure-quantum-python SDK (#646)
Browse files Browse the repository at this point in the history
* Deleted cirq estimate_cost functions

* Deleted qiskit estimate_cost functions

* Deleted target estimate_cost functions

* Deleted cost estimation unit tests

* Deleted cost estimation step from hello-world notebooks

* Deleted cost estimation references in hidden-shift notebook
  • Loading branch information
warren-jones authored Oct 23, 2024
1 parent 46c47f8 commit 035acc6
Show file tree
Hide file tree
Showing 18 changed files with 12 additions and 713 deletions.
30 changes: 0 additions & 30 deletions azure-quantum/azure/quantum/cirq/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,36 +160,6 @@ def create_job(
name=name
)

def estimate_cost(
self,
program: cirq.Circuit,
repetitions: int,
target: str = None,
param_resolver: cirq.ParamResolverOrSimilarType = cirq.ParamResolver({}),
**kwargs
):
"""
Estimate the cost for a given circuit.
:param program: Cirq program or circuit
:type program: cirq.Circuit
:param repetitions: Number of measurement repetitions
:type repetitions: int
:param target: Target name, defaults to default_target
:type target: str
:param param_resolver: Cirq parameters, defaults to `cirq.ParamResolver({})`
:type param_resolver: cirq.ParamResolverOrSimilarType
"""

# Resolve parameters
resolved_circuit = cirq.resolve_parameters(program, param_resolver)
target = self.get_target(name=target)
return target.estimate_cost(
program=resolved_circuit,
repetitions=repetitions,
**kwargs
)

def run(
self,
program: cirq.Circuit,
Expand Down
31 changes: 0 additions & 31 deletions azure-quantum/azure/quantum/cirq/targets/ionq.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,37 +119,6 @@ def _to_cirq_job(self, azure_job: "AzureJob") -> "CirqIonqJob":
job_dict = self._client._create_job_dict(azure_job)
return CirqIonqJob(client=self._client, job_dict=job_dict)

def estimate_cost(
self,
program: "cirq.Circuit",
repetitions: int,
price_1q: float = None,
price_2q: float = None,
min_price: float = None) -> float:
"""Estimate cost for running this program
:param program: Cirq quantum program
:type program: cirq.Circuit
:param repetitions: Number of repetitions
:type repetitions: int
:param price_1q: The price of running a single-qubit gate.
:type price_1q: float, optional
:param price_2q: The price of running a double-qubit gate.
:type price_2q: float, optional
:param min_price: The minimum price for running a job.
:type min_price: float, optional
:return: Price estimate
:rtype: float
"""
serialized_program = self._translate_cirq_circuit(program)
return super().estimate_cost(
serialized_program.body,
repetitions,
price_1q=price_1q,
price_2q=price_2q,
min_price=min_price
)

def submit(
self,
program: "cirq.Circuit",
Expand Down
20 changes: 0 additions & 20 deletions azure-quantum/azure/quantum/cirq/targets/quantinuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,26 +74,6 @@ def _measurement_dict(program) -> Dict[str, Sequence[int]]:
meas.gate.key: [q.x for q in meas.qubits] for meas in measurements
}

def estimate_cost(
self,
program: str,
repetitions: int
) -> float:
"""Estimate cost for running this program
:param program: Cirq quantum program
:type program: str, optional
:param repetitions: Number of repetitions
:type repetitions: int, optional
:return: Price estimate in HQC
:rtype: float
"""
serialized_program = self._translate_circuit(program)
return super().estimate_cost(
circuit=serialized_program,
shots=repetitions
)

def submit(
self,
program: "cirq.Circuit",
Expand Down
19 changes: 0 additions & 19 deletions azure-quantum/azure/quantum/qiskit/backends/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,25 +500,6 @@ def get_func_name(func: pyqir.Function) -> str:

return str(module).encode("utf-8")

def _estimate_cost_qir(
self, circuits: Union[QuantumCircuit, List[QuantumCircuit]], shots, options={}
):
"""Estimate the cost for the given circuit."""
input_params = self._get_input_params(options, shots=shots)

if not (isinstance(circuits, list)):
circuits = [circuits]

skip_transpilation = input_params.pop("skipTranspile", False)
target_profile = self._get_target_profile(input_params)
module = self._generate_qir(
circuits, target_profile, skip_transpilation=skip_transpilation
)

workspace = self.provider().get_workspace()
target = workspace.get_targets(self.name())
return target.estimate_cost(module, shots=shots)

def _get_target_profile(self, input_params) -> TargetProfile:
# Default to Adaptive_RI if not specified on the backend
# this is really just a safeguard in case the backend doesn't have a default
Expand Down
15 changes: 0 additions & 15 deletions azure-quantum/azure/quantum/qiskit/backends/ionq.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,6 @@ def _azure_config(self) -> Dict[str, str]:
)
return config

def estimate_cost(self, circuits, shots, options={}):
"""Estimate the cost for the given circuit."""
return self._estimate_cost_qir(circuits, shots, options)

def run(
self,
run_input: Union[QuantumCircuit, List[QuantumCircuit]] = [],
Expand Down Expand Up @@ -265,17 +261,6 @@ def _translate_input(self, circuit):
def gateset(self):
return self.configuration().gateset

def estimate_cost(self, circuit, shots):
"""Estimate the cost for the given circuit."""
ionq_circ, _, _ = qiskit_circ_to_ionq_circ(circuit, gateset=self.gateset())
input_data = {
"qubits": circuit.num_qubits,
"circuit": ionq_circ,
}
workspace = self.provider().get_workspace()
target = workspace.get_targets(self.name())
return target.estimate_cost(input_data, shots=shots)


class IonQSimulatorBackend(IonQBackend):
backend_names = ("ionq.simulator",)
Expand Down
31 changes: 0 additions & 31 deletions azure-quantum/azure/quantum/qiskit/backends/quantinuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,6 @@ def _azure_config(self) -> Dict[str, str]:
def _get_n_qubits(self, name):
return _get_n_qubits(name)

def estimate_cost(self, circuits, shots, options={}):
"""Estimate the cost for the given circuit."""
return self._estimate_cost_qir(circuits, shots, options)


class QuantinuumSyntaxCheckerQirBackend(QuantinuumQirBackendBase):
backend_names = (
Expand Down Expand Up @@ -248,33 +244,6 @@ def _translate_input(self, circuit):
"""Translates the input values to the format expected by the AzureBackend."""
return dumps(circuit)

def estimate_cost(
self, circuit: QuantumCircuit, shots: int = None, count: int = None
):
"""Estimate cost for running this circuit
:param circuit: Qiskit quantum circuit
:type circuit: QuantumCircuit
:param shots: Shot count
:type shots: int
:param count: Shot count (alternative to 'shots')
:type count: int
"""
if count is not None:
warnings.warn(
"The 'count' parameter will be deprecated. Please, use 'shots' parameter instead.",
category=DeprecationWarning,
)
shots = count

if shots is None:
raise ValueError("Missing input argument 'shots'.")

input_data = dumps(circuit)
workspace = self.provider().get_workspace()
target = workspace.get_targets(self.name())
return target.estimate_cost(input_data, shots=shots)

def _get_n_qubits(self, name):
return _get_n_qubits(name)

Expand Down
111 changes: 0 additions & 111 deletions azure-quantum/azure/quantum/target/ionq.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,114 +126,3 @@ def submit(
input_params=input_params,
**kwargs
)

def estimate_cost(
self,
circuit: Union[Dict[str, Any], Any],
num_shots: int = None,
price_1q: float = None,
price_2q: float = None,
min_price: float = None,
shots: int = None
) -> CostEstimate:
"""Estimate the cost of submitting a circuit to IonQ targets.
Optionally, you can provide the number of gate and measurement operations
manually.
The actual price charged by the provider may differ from this calculation.
Specify pricing details for your area to get most accurate results.
By default, this function charges depending on the target:
ionq.qpu.aria-1:
price_1q = 0.00022 USD for a single-qubit gate.
price_2q = 0.00098 USD for a two-qubit gate.
min_price = 1 USD, total minimum price per circuit.
For the most current pricing details, see
https://docs.microsoft.com/azure/quantum/provider-ionq#pricing
or find your workspace and view pricing options in the "Provider" tab
of your workspace: https://aka.ms/aq/myworkspaces
:param circuit: Quantum circuit in IonQ JSON format (for examples,
see: https://docs.ionq.com/#section/Sample-JSON-Circuits)
:type circuit: Dict[str, Any]
:param num_shots: Number of shots, defaults to None
:type num_shots: int
:param price_1q: The price of running a single-qubit gate
for one shot.
:type price_1q: float
:param price_2q: The price of running a double-qubit gate
for one shot.
:type price_2q: float
:param min_price: The minimum price for running a job.
:type min_price: float
:param shots: Number of shots, defaults to None
:type shots: int
"""

if num_shots is None and shots is None:
raise ValueError("The 'shots' parameter has to be specified")

if num_shots is not None:
warn(
"The 'num_shots' parameter will be deprecated. Please, use 'shots' parameter instead.",
category=DeprecationWarning,
)
shots = num_shots

# Get the costs for the gates depending on the provider if not specified
if price_1q is None:
price_1q = COST_1QUBIT_GATE_MAP[self.name]

if price_2q is None:
price_2q = COST_2QUBIT_GATE_MAP[self.name]

if min_price is None:
min_price = MIN_PRICE_MAP[self.name]

if (isinstance(circuit, Dict)):
def is_1q_gate(gate: Dict[str, Any]):
return "controls" not in gate and "control" not in gate

def is_multi_q_gate(gate):
return "controls" in gate or "control" in gate

def num_2q_gates(gate):
controls = gate.get("controls")
if controls is None or len(controls) == 1:
# Only one control qubit
return 1
# Multiple control qubits
return 6 * (len(controls) - 2)

gates = circuit.get("circuit", [])
N_1q = sum(map(is_1q_gate, gates))
N_2q = sum(map(num_2q_gates, filter(is_multi_q_gate, gates)))

else:
N_1q, N_2q, _ = Target._calculate_qir_module_gate_stats(circuit)

price = (price_1q * N_1q + price_2q * N_2q) * shots
price = max(price, min_price)

return CostEstimate(
events = [
UsageEvent(
dimension_id="gs1q",
dimension_name="1Q Gate Shot",
measure_unit="1q gate shot",
amount_billed=0.0,
amount_consumed=N_1q * shots,
unit_price=0.0
),
UsageEvent(
dimension_id="gs2q",
dimension_name="2Q Gate Shot",
measure_unit="2q gate shot",
amount_billed=0.0,
amount_consumed=N_2q * shots,
unit_price=0.0
)
],
currency_code="USD",
estimated_total=price
)
Loading

0 comments on commit 035acc6

Please sign in to comment.