Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions samples/qre/cost_example.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "4d47cb98-6af6-4757-b450-c2209ce8f5df",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>qubits</th>\n",
" <th>runtime</th>\n",
" <th>error</th>\n",
" <th>$ cost</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>18624</td>\n",
" <td>0 days 00:00:02.788569</td>\n",
" <td>0.009573</td>\n",
" <td>474.85</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>24444</td>\n",
" <td>0 days 00:00:01.858696</td>\n",
" <td>0.008309</td>\n",
" <td>316.51</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>29052</td>\n",
" <td>0 days 00:00:01.791981</td>\n",
" <td>0.008555</td>\n",
" <td>305.15</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>30264</td>\n",
" <td>0 days 00:00:01.394022</td>\n",
" <td>0.006875</td>\n",
" <td>237.38</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>38752</td>\n",
" <td>0 days 00:00:01.194651</td>\n",
" <td>0.008540</td>\n",
" <td>271.24</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>39964</td>\n",
" <td>0 days 00:00:00.929348</td>\n",
" <td>0.005442</td>\n",
" <td>211.01</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" qubits runtime error $ cost\n",
"0 18624 0 days 00:00:02.788569 0.009573 474.85\n",
"1 24444 0 days 00:00:01.858696 0.008309 316.51\n",
"2 29052 0 days 00:00:01.791981 0.008555 305.15\n",
"3 30264 0 days 00:00:01.394022 0.006875 237.38\n",
"4 38752 0 days 00:00:01.194651 0.008540 271.24\n",
"5 39964 0 days 00:00:00.929348 0.005442 211.01"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from pathlib import Path\n",
"\n",
"import qdk\n",
"from qdk import qsharp\n",
"from qdk.qre import estimate, property_name, instruction_name, PSSPC, LatticeSurgery\n",
"from qdk.qre.models import GateBased, SurfaceCode, RoundBasedFactory\n",
"from qdk.qre.application import QSharpApplication\n",
"\n",
"from qdk.qre.instruction_ids import T, LATTICE_SURGERY\n",
"from qdk.qre.property_keys import NUM_TS_PER_ROTATION\n",
"\n",
"# Evaluate the Q# application into the scope\n",
"qsharp.eval(Path(\"../algorithms/Shor.qs\").read_text(encoding=\"utf-8\"))\n",
"\n",
"# The entry point in the Q# code above is called Main\n",
"app = QSharpApplication(qdk.code.Main)\n",
"\n",
"arch = GateBased(error_rate=1e-4, gate_time=100, measurement_time=500)\n",
"\n",
"results = estimate(\n",
" app,\n",
" arch,\n",
" isa_query=SurfaceCode.q() * RoundBasedFactory.q(),\n",
" trace_query=PSSPC.q() * LatticeSurgery.q(slow_down_factor=[1.0, 1.5, 2.0, 3.0, 4.0]),\n",
" max_error=0.01,\n",
" cost_spec_path=\"example_cost_spec.json\"\n",
")\n",
"results.as_frame()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
43 changes: 43 additions & 0 deletions samples/qre/example_cost_spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"system": {
"name": "example_cost_spec",
"qubits_per_node": 16000,
"cnot_time": 10000,
"cnot_error_rate": 0.001,
"one_qubit_time": 1000,
"one_qubit_error_rate": 0.0001,
"measurement_time": 1000,
"measurement_error_rate": 0.0001,
"target_year": 2030,
"lifetime_in_years": 10,
"uptime": 0.9,
"control_lines_per_physical_qubit": 1,
"readout_lines_per_physical_qubit": 0,
"fixed_control_lines": 0,
"fixed_readout_lines": 0,
"magical_speedup_factor": 1
},
"fixed_units": [
{
"name": "Fixed cost of constructing the system",
"cost": 10000000.0,
"quantity": 1,
"eos_factor": 1.0
}
],
"scaled_units": [
{
"name": "Black box cost per qubit",
"cost": 1000000.00,
"units_per_control_line": 1,
"units_per_readout_line": 0,
"eos_factor": 1.0
}
],
"opex": [
{
"name": "FTE costs",
"cost": 10000000
}
]
}
48 changes: 48 additions & 0 deletions source/qdk_package/qdk/qre/_dollar_cost.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import math

from ._json_specs import JsonSpec
from ._results import EstimationTableEntry


def compute_dollar_cost(cost_spec_path: str, result: EstimationTableEntry) -> float:
"""Computes cost in dollars."""
spec = JsonSpec.from_file(cost_spec_path)
system = spec.system

# Build the node cost
qubits_per_node = system.qubits_per_node
control_lines = (
system.fixed_control_lines
+ qubits_per_node * system.control_lines_per_physical_qubit
)
readout_lines = (
system.fixed_readout_lines
+ qubits_per_node * system.readout_lines_per_physical_qubit
)
cost_per_control_line = 0
for unit in spec.scaled_units:
cost_per_control_line += (
unit.cost * unit.units_per_control_line * unit.eos_factor
)
cost_per_readout_line = 0
for unit in spec.scaled_units:
cost_per_readout_line += (
unit.cost * unit.units_per_readout_line * unit.eos_factor
)

capex = 0
for unit in spec.fixed_units:
capex += unit.cost * unit.quantity * unit.eos_factor
capex += cost_per_control_line * control_lines
capex += cost_per_readout_line * readout_lines

opex = sum(item.cost for item in spec.opex)

number_of_nodes = math.ceil(result.qubits / qubits_per_node) + 1
runtime_hours = result.runtime / (3600 * 1_000_000_000) # Convert to hours
runtime_hours /= system.magical_speedup_factor
operating_lifetime = system.lifetime_in_years
up_hours_per_year = 8760 * system.uptime
hourly_cost = (opex + capex / operating_lifetime) / up_hours_per_year
dollar_cost = number_of_nodes * hourly_cost * runtime_hours
return math.ceil(dollar_cost * 100) / 100
26 changes: 18 additions & 8 deletions source/qdk_package/qdk/qre/_estimation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,36 @@

from __future__ import annotations

from typing import cast, Optional, Any
from typing import Any, cast

from .. import telemetry_events
from ._application import Application
from ._architecture import Architecture
from ._dollar_cost import compute_dollar_cost
from ._isa_enumeration import ISAQuery
from ._qre import (
_estimate_parallel,
_estimate_with_graph,
_EstimationCollection,
ErrorComposition,
Trace,
_EstimationCollection,
_estimate_parallel,
_estimate_with_graph,
)
from ._trace import TraceQuery, PSSPC, LatticeSurgery
from ._isa_enumeration import ISAQuery
from ._results import EstimationTable, EstimationTableEntry
from ._trace import LatticeSurgery, PSSPC, TraceQuery


def estimate(
application: Application,
architecture: Architecture,
isa_query: ISAQuery,
trace_query: Optional[TraceQuery] = None,
trace_query: TraceQuery | None = None,
*,
max_error: float = 1.0,
post_process: bool = False,
use_graph: bool = True,
composition: ErrorComposition = ErrorComposition.UnionBound,
name: Optional[str] = None,
name: str | None = None,
cost_spec_path: str | None = None,
) -> EstimationTable:
"""
Estimate the resource requirements for a given application instance and
Expand Down Expand Up @@ -82,6 +84,8 @@ def estimate(
``1 - prod(1 - p_i)``.
name (Optional[str]): An optional name for the estimation. If given, this
will be added as a first column to the results table for all entries.
json_spec_path (Optional[str]): Path to the system specification in
JSON format. If provided, a ``$ cost`` column is added to the results.

Returns:
EstimationTable: A table containing the optimal estimation results.
Expand Down Expand Up @@ -223,6 +227,12 @@ def estimate(
EstimationTableEntry.from_result(result, arch_ctx) for result in collection
)

if cost_spec_path is not None:
table.add_column(
"$ cost",
lambda entry: compute_dollar_cost(cost_spec_path, entry),
)

# Fill in the stats for this estimation run
table.stats.num_traces = num_traces
table.stats.num_isas = num_isas
Expand Down
Loading
Loading