microsoft/qdk
Publicmirrored fromhttps://github.com/microsoft/qdkAvailable
source/npm/qsharp/ux/generate_report_code.py
243lines · modecode
| 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.physicalCounts.breakdown.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() |