qsharp-lang 1.0.32-dev → 1.0.34-dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,238 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ // A component including the results table and the scatter chart together.
5
+ // The results table is also a legend for the scatter chart.
6
+
7
+ import { useState } from "preact/hooks";
8
+ import { ColorMap } from "./colormap.js";
9
+ import {
10
+ CreateSingleEstimateResult,
11
+ FrontierEntry,
12
+ ReData,
13
+ SingleEstimateResult,
14
+ } from "./data.js";
15
+ import { ResultsTable, Row } from "./resultsTable.js";
16
+ import {
17
+ Axis,
18
+ HideTooltip,
19
+ PlotItem,
20
+ ScatterChart,
21
+ ScatterSeries,
22
+ SelectPoint,
23
+ } from "./scatterChart.js";
24
+
25
+ const columnNames = [
26
+ "Run name",
27
+ "Estimate type",
28
+ "Qubit type",
29
+ "QEC scheme",
30
+ "Error budget",
31
+ "Logical qubits",
32
+ "Logical depth",
33
+ "Code distance",
34
+ "T states",
35
+ "T factories",
36
+ "T factory fraction",
37
+ "Runtime",
38
+ "rQOPS",
39
+ "Physical qubits",
40
+ ];
41
+
42
+ const initialColumns = [0, 1, 2, 3, 4, 10, 11, 12];
43
+
44
+ const xAxis: Axis = {
45
+ isTime: true,
46
+ label: "Runtime",
47
+ };
48
+
49
+ const yAxis: Axis = {
50
+ isTime: false,
51
+ label: "Physical qubits",
52
+ };
53
+
54
+ function reDataToRow(input: ReData, color: string): Row {
55
+ const data = CreateSingleEstimateResult(input, 0);
56
+ const estimateType =
57
+ input.frontierEntries == null
58
+ ? "Single"
59
+ : "Frontier (" + input.frontierEntries.length + " items)";
60
+
61
+ return {
62
+ cells: [
63
+ data.jobParams.runName,
64
+ estimateType,
65
+ data.jobParams.qubitParams.name,
66
+ data.jobParams.qecScheme.name,
67
+ data.jobParams.errorBudget,
68
+ data.physicalCounts.breakdown.algorithmicLogicalQubits,
69
+ data.physicalCounts.breakdown.algorithmicLogicalDepth,
70
+ data.logicalQubit.codeDistance,
71
+ data.physicalCounts.breakdown.numTstates,
72
+ data.physicalCounts.breakdown.numTfactories,
73
+ data.physicalCountsFormatted.physicalQubitsForTfactoriesPercentage,
74
+ {
75
+ value: data.physicalCountsFormatted.runtime,
76
+ sortBy: data.physicalCounts.runtime,
77
+ },
78
+ data.physicalCounts.rqops,
79
+ data.physicalCounts.physicalQubits,
80
+ data.new ? "New" : "Cached",
81
+ ],
82
+ color: color,
83
+ };
84
+ }
85
+
86
+ function frontierEntryToPlotEntry(entry: FrontierEntry): PlotItem {
87
+ return {
88
+ x: entry.physicalCounts.runtime,
89
+ y: entry.physicalCounts.physicalQubits,
90
+ label:
91
+ entry.physicalCountsFormatted.runtime +
92
+ " " +
93
+ entry.physicalCountsFormatted.physicalQubits,
94
+ };
95
+ }
96
+
97
+ function reDataToRowScatter(data: ReData, color: string): ScatterSeries {
98
+ if (data.frontierEntries == null || data.frontierEntries.length === 0) {
99
+ return {
100
+ color: color,
101
+ items: [
102
+ {
103
+ x: data.physicalCounts.runtime,
104
+ y: data.physicalCounts.physicalQubits,
105
+ label:
106
+ data.physicalCountsFormatted.runtime +
107
+ " " +
108
+ data.physicalCountsFormatted.physicalQubits,
109
+ },
110
+ ],
111
+ };
112
+ }
113
+
114
+ return {
115
+ color: color,
116
+ items: data.frontierEntries.map(frontierEntryToPlotEntry),
117
+ };
118
+ }
119
+
120
+ export function EstimatesOverview(props: {
121
+ estimatesData: ReData[];
122
+ colors: string[] | null;
123
+ runNames: string[] | null;
124
+ isSimplifiedView: boolean;
125
+ onRowDeleted: (rowId: string) => void;
126
+ setEstimate: (estimate: SingleEstimateResult | null) => void;
127
+ }) {
128
+ const [selectedRow, setSelectedRow] = useState<string | null>(null);
129
+
130
+ props.estimatesData.forEach((item, idx) => {
131
+ if (
132
+ props.runNames != null &&
133
+ props.runNames.length == props.estimatesData.length
134
+ ) {
135
+ item.jobParams.runName = props.runNames[idx];
136
+ } else {
137
+ if (item.jobParams.runName == null) {
138
+ // Start indexing with 0 to match with the original object indexing.
139
+ item.jobParams.runName = `(${idx})`;
140
+ }
141
+ }
142
+ });
143
+
144
+ function onPointSelected(seriesIndex: number, pointIndex: number): void {
145
+ const data = props.estimatesData[seriesIndex];
146
+ props.setEstimate(CreateSingleEstimateResult(data, pointIndex));
147
+ const rowId = props.estimatesData[seriesIndex].jobParams.runName;
148
+ setSelectedRow(rowId);
149
+ }
150
+
151
+ function onRowSelected(rowId: string) {
152
+ setSelectedRow(rowId);
153
+ // On any selection, clear the "new" flag on all rows. This ensures that
154
+ // new rows do not steal focus from the user selected row.
155
+ props.estimatesData.forEach((data) => (data.new = false));
156
+ HideTooltip();
157
+ if (!rowId) {
158
+ props.setEstimate(null);
159
+ } else {
160
+ const index = props.estimatesData.findIndex(
161
+ (data) => data.jobParams.runName === rowId,
162
+ );
163
+
164
+ if (index == -1) {
165
+ props.setEstimate(null);
166
+ } else {
167
+ const estimateFound = props.estimatesData[index];
168
+ props.setEstimate(CreateSingleEstimateResult(estimateFound, 0));
169
+ SelectPoint(index, 0);
170
+ }
171
+ }
172
+ }
173
+
174
+ const colormap =
175
+ props.colors != null && props.colors.length == props.estimatesData.length
176
+ ? props.colors
177
+ : ColorMap(props.estimatesData.length);
178
+
179
+ if (props.isSimplifiedView) {
180
+ return (
181
+ <>
182
+ <ResultsTable
183
+ columnNames={columnNames}
184
+ rows={props.estimatesData.map((dataItem, index) =>
185
+ reDataToRow(dataItem, colormap[index]),
186
+ )}
187
+ initialColumns={initialColumns}
188
+ ensureSelected={true}
189
+ onRowDeleted={props.onRowDeleted}
190
+ selectedRow={selectedRow}
191
+ setSelectedRow={onRowSelected}
192
+ />
193
+ <ScatterChart
194
+ xAxis={xAxis}
195
+ yAxis={yAxis}
196
+ data={props.estimatesData.map((dataItem, index) =>
197
+ reDataToRowScatter(dataItem, colormap[index]),
198
+ )}
199
+ onPointSelected={onPointSelected}
200
+ />
201
+ </>
202
+ );
203
+ }
204
+
205
+ return (
206
+ <>
207
+ <details open>
208
+ <summary style="font-size: 1.5em; font-weight: bold; margin: 24px 8px;">
209
+ Results
210
+ </summary>
211
+ <ResultsTable
212
+ columnNames={columnNames}
213
+ rows={props.estimatesData.map((dataItem, index) =>
214
+ reDataToRow(dataItem, colormap[index]),
215
+ )}
216
+ initialColumns={initialColumns}
217
+ selectedRow={selectedRow}
218
+ setSelectedRow={onRowSelected}
219
+ ensureSelected={true}
220
+ onRowDeleted={props.onRowDeleted}
221
+ />
222
+ </details>
223
+ <details open>
224
+ <summary style="font-size: 1.5em; font-weight: bold; margin: 24px 8px;">
225
+ Qubit-time diagram
226
+ </summary>
227
+ <ScatterChart
228
+ xAxis={xAxis}
229
+ yAxis={yAxis}
230
+ data={props.estimatesData.map((dataItem, index) =>
231
+ reDataToRowScatter(dataItem, colormap[index]),
232
+ )}
233
+ onPointSelected={onPointSelected}
234
+ />
235
+ </details>
236
+ </>
237
+ );
238
+ }
@@ -0,0 +1,243 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+
4
+ # This script generates the code for the report page from the output_data.md file.
5
+ # To run, simply execute `python generate_report_code.py` in the npm/ux folder.
6
+ # copy the output and paste it into the report.tsx file.
7
+ # It provides a code for the CreateReport function.
8
+
9
+ import re
10
+
11
+ parse = False
12
+
13
+ title = ""
14
+ always_visible = True
15
+ first_entry = True
16
+ entries = []
17
+
18
+ label = ""
19
+ path = ""
20
+ value = ""
21
+ description = ""
22
+ explanation = ""
23
+
24
+ assumptions = []
25
+
26
+ ignore_paths = [
27
+ "floquet_code",
28
+ "surface_code",
29
+ "qubit_gate_ns_e3",
30
+ "qubit_gate_ns_e4",
31
+ "qubit_gate_us_e3",
32
+ "qubit_gate_us_e4",
33
+ "qubit_maj_ns_e4",
34
+ "qubit_maj_ns_e6",
35
+ ]
36
+
37
+ path_map = {
38
+ "errorBudget/rotations": "result.errorBudget.rotations",
39
+ "jobParams/qecScheme/crossingPrefactor": "result.jobParams.qecScheme.crossingPrefactor",
40
+ "jobParams/qecScheme/errorCorrectionThreshold": "result.jobParams.qecScheme.errorCorrectionThreshold",
41
+ "jobParams/qecScheme/logicalCycleTime": "result.jobParams.qecScheme.logicalCycleTime",
42
+ "jobParams/qecScheme/physicalQubitsPerLogicalQubit": "result.jobParams.qecScheme.physicalQubitsPerLogicalQubit",
43
+ "jobParams/qubitParams/tGateErrorRate": "result.jobParams.qubitParams.tGateErrorRate",
44
+ "logicalCounts/ccixCount": "numberFormat.format(result.logicalCounts.ccixCount)",
45
+ "logicalCounts/cczCount": "numberFormat.format(result.logicalCounts.cczCount)",
46
+ "logicalCounts/measurementCount": "numberFormat.format(result.logicalCounts.measurementCount)",
47
+ "logicalCounts/numQubits": "numberFormat.format(result.logicalCounts.numQubits)",
48
+ "logicalCounts/rotationCount": "numberFormat.format(result.logicalCounts.rotationCount)",
49
+ "logicalCounts/rotationDepth": "numberFormat.format(result.logicalCounts.rotationDepth)",
50
+ "logicalCounts/tCount": "numberFormat.format(result.logicalCounts.tCount)",
51
+ "logicalQubit/codeDistance": "result.logicalQubit.codeDistance",
52
+ "logicalQubit/logicalCyclesPerSecond": "numberFormatF64.format(result.physicalCounts.breakdown.clockFrequency)",
53
+ "logicalQubit/logicalCycleTime": "numberFormat.format(result.logicalQubit.logicalCycleTime)",
54
+ "logicalQubit/physicalQubits": "numberFormat.format(result.logicalQubit.physicalQubits)",
55
+ "physicalCounts/breakdown/algorithmicLogicalDepth": "numberFormat.format(result.physicalCountsFormatted.algorithmicLogicalDepth)",
56
+ "physicalCounts/breakdown/algorithmicLogicalQubits": "numberFormat.format(result.physicalCounts.breakdown.algorithmicLogicalQubits)",
57
+ "physicalCounts/breakdown/cliffordErrorRate": "result.physicalCounts.breakdown.cliffordErrorRate",
58
+ "physicalCounts/breakdown/logicalDepth": "numberFormat.format(result.physicalCounts.breakdown.logicalDepth)",
59
+ "physicalCounts/breakdown/physicalQubitsForAlgorithm": "numberFormat.format(result.physicalCounts.breakdown.physicalQubitsForAlgorithm)",
60
+ "physicalCounts/breakdown/physicalQubitsForTfactories": "numberFormat.format(result.physicalCounts.breakdown.physicalQubitsForTfactories)",
61
+ "physicalCounts/breakdown/numTfactories": "numberFormat.format(result.physicalCounts.breakdown.numTfactories)",
62
+ "physicalCounts/breakdown/numTfactoryRuns": "numberFormat.format(result.physicalCounts.breakdown.numTfactoryRuns)",
63
+ "physicalCounts/breakdown/numTstates": "numberFormat.format(result.physicalCounts.breakdown.numTstates)",
64
+ "physicalCounts/breakdown/requiredLogicalQubitErrorRate": "result.physicalCounts.breakdown.requiredLogicalQubitErrorRate",
65
+ "physicalCounts/physicalQubits": "numberFormat.format(result.physicalCounts.physicalQubits)",
66
+ "physicalCounts/runtime": "numberFormat.format(result.physicalCounts.runtime)",
67
+ "physicalCountsFormatted/clockFrequency": "result.physicalCountsFormatted.clockFrequency",
68
+ "physicalCountsFormatted/errorBudget": "result.physicalCountsFormatted.errorBudget",
69
+ "physicalCountsFormatted/errorBudgetLogical": "result.physicalCountsFormatted.errorBudgetLogical",
70
+ "physicalCountsFormatted/errorBudgetRotations": "result.physicalCountsFormatted.errorBudgetRotations",
71
+ "physicalCountsFormatted/errorBudgetTstates": "result.physicalCountsFormatted.errorBudgetTstates",
72
+ "physicalCountsFormatted/logicalCycleTime": "result.physicalCountsFormatted.logicalCycleTime",
73
+ "physicalCountsFormatted/numTsPerRotation": "result.physicalCountsFormatted.numTsPerRotation",
74
+ "physicalCountsFormatted/requiredLogicalQubitErrorRate": "result.physicalCountsFormatted.requiredLogicalQubitErrorRate",
75
+ "physicalCountsFormatted/requiredLogicalTstateErrorRate": "result.physicalCountsFormatted.requiredLogicalTstateErrorRate",
76
+ "physicalCountsFormatted/runtime": "result.physicalCountsFormatted.runtime",
77
+ "physicalCountsFormatted/tfactoryRuntime": "result.physicalCountsFormatted.tfactoryRuntime",
78
+ "physicalCountsFormatted/tstateLogicalErrorRate": "result.physicalCountsFormatted.tstateLogicalErrorRate",
79
+ "tfactory/physicalQubits": "numberFormat.format(result.tfactory == null ? 0 : result.tfactory.physicalQubits)",
80
+ "tfactory/numInputTstates": "numberFormat.format(result.tfactory == null ? 0 : result.tfactory.numInputTstates)",
81
+ "tfactory/numTstates": "numberFormat.format(result.tfactory == null ? 0 : result.tfactory.numTstates)",
82
+ "tfactory/runtime": "numberFormat.format(result.tfactory == null ? 0 : result.tfactory.runtime)",
83
+ }
84
+
85
+ print()
86
+ print()
87
+ print(
88
+ "// THIS CODE HAS BEEN AUTOMATICALLY GENERATED WITH generate_report_code.py from output_data.md"
89
+ )
90
+ print("export function CreateReport(result: ReData): ReportData {")
91
+ print(" const groups = [] as ReportGroup[];")
92
+ print(" let entries = [] as ReportEntry[];")
93
+ print(" const numberFormat = new Intl.NumberFormat();")
94
+ print(
95
+ " const numberFormatF64 = new Intl.NumberFormat(undefined, { maximumFractionDigits: 2, minimumFractionDigits: 2,});"
96
+ )
97
+ print()
98
+
99
+
100
+ def add_group():
101
+ global always_visible, entries, title
102
+
103
+ if len(entries) != 0:
104
+ if title == "T factory parameters":
105
+ print(" if (result.tfactory != null) {")
106
+
107
+ always_visible_str = "true" if always_visible else "false"
108
+ print(" entries = [];")
109
+ for path, label, description, explanation in entries:
110
+ if path in [
111
+ "jobParams/qubitParams/oneQubitGateTime",
112
+ "jobParams/qubitParams/twoQubitGateTime",
113
+ "jobParams/qubitParams/oneQubitGateErrorRate",
114
+ "jobParams/qubitParams/twoQubitGateErrorRate",
115
+ ]:
116
+ print(
117
+ ' if (result.jobParams.qubitParams.instructionSet == "GateBased") {'
118
+ )
119
+ print(
120
+ f' entries.push({{path: "{path}", label: "{label}", description: {description}, explanation: {explanation}}});'
121
+ )
122
+ print(" }")
123
+ elif path in [
124
+ "jobParams/qubitParams/twoQubitJointMeasurementTime",
125
+ "jobParams/qubitParams/twoQubitJointMeasurementErrorRate",
126
+ ]:
127
+ print(
128
+ ' if (result.jobParams.qubitParams.instructionSet == "Majorana") {'
129
+ )
130
+ print(
131
+ f' entries.push({{path: "{path}", label: "{label}", description: {description}, explanation: {explanation}}});'
132
+ )
133
+ print(" }")
134
+ else:
135
+ print(
136
+ f' entries.push({{path: "{path}", label: "{label}", description: {description}, explanation: {explanation}}});'
137
+ )
138
+ print(
139
+ f' groups.push({{ title: "{title}", alwaysVisible: {always_visible_str}, entries: entries }});'
140
+ )
141
+ print()
142
+
143
+ if title == "T factory parameters":
144
+ print(" }")
145
+
146
+ always_visible = False
147
+ entries.clear()
148
+
149
+
150
+ def create_fmt_string(string):
151
+ args = []
152
+
153
+ # Find in-text `paths`
154
+ pos = string.find("`")
155
+ while pos != -1:
156
+ pos2 = string.find("`", pos + 1)
157
+ path = string[pos + 1 : pos2]
158
+
159
+ if path in ignore_paths:
160
+ pos = string.find("`", pos2 + 1)
161
+ else:
162
+ string = string[:pos] + "${" + path_map[path] + "}" + string[pos2 + 1 :]
163
+ pos = string.find("`", pos + 1)
164
+
165
+ # Find in-math \mathtt{paths}
166
+ pos = string.find("\\mathtt{")
167
+ while pos != -1:
168
+ pos2 = string.find("}", pos + 1)
169
+ path = string[pos + 8 : pos2]
170
+
171
+ string = string[:pos] + "${" + path_map[path] + "}" + string[pos2 + 1 :]
172
+ pos = string.find("\\mathtt{", pos + 1)
173
+
174
+ if len(args) != 0:
175
+ args_list = ", ".join(args)
176
+
177
+ cur = 0
178
+ while cur < len(string):
179
+ if string[cur] == "{" and string[cur + 1] != "}":
180
+ string = string[:cur] + "{" + string[cur:]
181
+ cur += 2
182
+ elif string[cur] == "}" and string[cur - 1] != "{":
183
+ string = string[:cur] + "}" + string[cur:]
184
+ cur += 2
185
+ else:
186
+ cur += 1
187
+
188
+ string = string.replace("\\", "\\\\")
189
+ string = string.replace("`", "\\`")
190
+ return f"`{string}`"
191
+
192
+
193
+ with open("output_data.md", "r") as f:
194
+ for line in f.readlines():
195
+ line = line.strip()
196
+
197
+ if line == "":
198
+ continue
199
+
200
+ if not parse:
201
+ if line.startswith("## "):
202
+ parse = True
203
+ else:
204
+ continue
205
+
206
+ if line.startswith("## "):
207
+ # Finish previous group?
208
+ if len(entries) != 0:
209
+ add_group()
210
+
211
+ title = line[3:].strip()
212
+ elif line.startswith("### "):
213
+ label = line[4:].strip()
214
+ elif line.startswith("[//]: #"):
215
+ path = line[9:-1]
216
+ elif line.startswith("_"):
217
+ description = line[1:-1]
218
+ elif line.startswith("-"):
219
+ assumptions.append(line[2:])
220
+ else:
221
+ explanation = line
222
+
223
+ entries.append(
224
+ (
225
+ path,
226
+ label,
227
+ create_fmt_string(description),
228
+ create_fmt_string(explanation),
229
+ )
230
+ )
231
+
232
+ # Add assumptions
233
+ assert title == "Assumptions"
234
+ print(" const assumptions = [")
235
+ for assumption in assumptions:
236
+ print(f" '{assumption}',")
237
+ print(" ];")
238
+ print()
239
+ print(" return { groups: groups, assumptions: assumptions };")
240
+ print("}")
241
+ print("// END OF AUTOMATICALLY GENERATED CODE")
242
+ print()
243
+ print()
package/ux/index.ts CHANGED
@@ -5,7 +5,9 @@
5
5
  // to a CSS file adjacent to the JS bundle and with the same name.
6
6
  import "./qsharp-ux.css";
7
7
 
8
+ export { CreateSingleEstimateResult, type ReData } from "./data.js";
8
9
  export { Histogram } from "./histogram.js";
9
- export { ReTable, type ReData } from "./reTable.js";
10
+ export { ReTable } from "./reTable.js";
10
11
  export { SpaceChart } from "./spaceChart.js";
11
- export { ResultsTable } from "./resultsTable.js";
12
+ export { ScatterChart } from "./scatterChart.js";
13
+ export { EstimatesOverview } from "./estimatesOverview.js";