azure-quantum 2.2.0.dev3__tar.gz → 2.2.0.dev5__tar.gz

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.
Files changed (92) hide show
  1. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/PKG-INFO +1 -1
  2. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/_version.py +1 -1
  3. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/qiskit/backends/backend.py +121 -65
  4. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/qiskit/backends/ionq.py +3 -3
  5. azure-quantum-2.2.0.dev5/azure/quantum/qiskit/backends/microsoft.py +161 -0
  6. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/qiskit/backends/qci.py +9 -4
  7. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/qiskit/backends/quantinuum.py +2 -22
  8. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/qiskit/backends/rigetti.py +2 -1
  9. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/qiskit/job.py +7 -2
  10. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/ionq.py +8 -3
  11. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/microsoft/target.py +26 -7
  12. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/pasqal/target.py +7 -1
  13. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/quantinuum.py +7 -3
  14. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/rigetti/target.py +13 -6
  15. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/target.py +16 -3
  16. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/version.py +1 -1
  17. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure_quantum.egg-info/PKG-INFO +1 -1
  18. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure_quantum.egg-info/requires.txt +4 -4
  19. azure-quantum-2.2.0.dev5/requirements-qiskit.txt +5 -0
  20. azure-quantum-2.2.0.dev3/azure/quantum/qiskit/backends/microsoft.py +0 -114
  21. azure-quantum-2.2.0.dev3/requirements-qiskit.txt +0 -5
  22. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/README.md +0 -0
  23. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/__init__.py +0 -0
  24. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_authentication/__init__.py +0 -0
  25. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_authentication/_chained.py +0 -0
  26. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_authentication/_default.py +0 -0
  27. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_authentication/_token.py +0 -0
  28. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/__init__.py +0 -0
  29. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/_client.py +0 -0
  30. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/_configuration.py +0 -0
  31. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/_patch.py +0 -0
  32. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/_serialization.py +0 -0
  33. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/_vendor.py +0 -0
  34. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/models/__init__.py +0 -0
  35. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/models/_enums.py +0 -0
  36. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/models/_models.py +0 -0
  37. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/models/_patch.py +0 -0
  38. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/operations/__init__.py +0 -0
  39. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/operations/_operations.py +0 -0
  40. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_client/operations/_patch.py +0 -0
  41. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_constants.py +0 -0
  42. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/_workspace_connection_params.py +0 -0
  43. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/argument_types/__init__.py +0 -0
  44. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/argument_types/types.py +0 -0
  45. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/chemistry/__init__.py +0 -0
  46. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/cirq/__init__.py +0 -0
  47. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/cirq/job.py +0 -0
  48. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/cirq/service.py +0 -0
  49. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/cirq/targets/__init__.py +0 -0
  50. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/cirq/targets/ionq.py +0 -0
  51. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/cirq/targets/quantinuum.py +0 -0
  52. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/cirq/targets/target.py +0 -0
  53. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/job/__init__.py +0 -0
  54. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/job/base_job.py +0 -0
  55. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/job/filtered_job.py +0 -0
  56. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/job/job.py +0 -0
  57. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/job/job_failed_with_results_error.py +0 -0
  58. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/job/session.py +0 -0
  59. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/job/workspace_item.py +0 -0
  60. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/job/workspace_item_factory.py +0 -0
  61. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/qiskit/__init__.py +0 -0
  62. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/qiskit/backends/__init__.py +0 -0
  63. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/qiskit/provider.py +0 -0
  64. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/qiskit/results/__init__.py +0 -0
  65. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/qiskit/results/resource_estimator.py +0 -0
  66. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/storage.py +0 -0
  67. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/__init__.py +0 -0
  68. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/microsoft/__init__.py +0 -0
  69. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/microsoft/elements/__init__.py +0 -0
  70. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/microsoft/elements/dft/__init__.py +0 -0
  71. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/microsoft/elements/dft/job.py +0 -0
  72. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/microsoft/elements/dft/target.py +0 -0
  73. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/microsoft/job.py +0 -0
  74. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/microsoft/result.py +0 -0
  75. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/params.py +0 -0
  76. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/pasqal/__init__.py +0 -0
  77. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/pasqal/result.py +0 -0
  78. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/rigetti/__init__.py +0 -0
  79. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/rigetti/result.py +0 -0
  80. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/target/target_factory.py +0 -0
  81. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure/quantum/workspace.py +0 -0
  82. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure_quantum.egg-info/SOURCES.txt +0 -0
  83. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure_quantum.egg-info/dependency_links.txt +0 -0
  84. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/azure_quantum.egg-info/top_level.txt +0 -0
  85. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/requirements-cirq.txt +0 -0
  86. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/requirements-dev.txt +0 -0
  87. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/requirements-pulser.txt +0 -0
  88. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/requirements-qsharp.txt +0 -0
  89. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/requirements-quil.txt +0 -0
  90. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/requirements.txt +0 -0
  91. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/setup.cfg +0 -0
  92. {azure-quantum-2.2.0.dev3 → azure-quantum-2.2.0.dev5}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: azure-quantum
3
- Version: 2.2.0.dev3
3
+ Version: 2.2.0.dev5
4
4
  Summary: Python client for Azure Quantum
5
5
  Home-page: https://github.com/microsoft/azure-quantum-python
6
6
  Author: Microsoft
@@ -6,4 +6,4 @@
6
6
  # Changes may cause incorrect behavior and will be lost if the code is regenerated.
7
7
  # --------------------------------------------------------------------------
8
8
 
9
- VERSION = "2.2.0.dev3"
9
+ VERSION = "2.2.0.dev5"
@@ -21,14 +21,15 @@ from abc import abstractmethod
21
21
  from azure.quantum.job.session import SessionHost
22
22
 
23
23
  try:
24
- from qiskit import QuantumCircuit, transpile
24
+ from qiskit import QuantumCircuit
25
25
  from qiskit.providers import BackendV1 as Backend
26
26
  from qiskit.providers import Options
27
27
  from qiskit.providers import Provider
28
28
  from qiskit.providers.models import BackendConfiguration
29
29
  from qiskit.qobj import QasmQobj, PulseQobj
30
- from pyqir import Module
31
- from qiskit_qir import to_qir_module
30
+ import pyqir as pyqir
31
+ from qsharp.interop.qiskit import QSharpBackend
32
+ from qsharp import TargetProfile
32
33
 
33
34
  except ImportError:
34
35
  raise ImportError(
@@ -36,23 +37,37 @@ except ImportError:
36
37
  To install run: pip install azure-quantum[qiskit]"
37
38
  )
38
39
 
40
+ # barrier is handled by an extra flag which will transpile
41
+ # them away if the backend doesn't support them. This has
42
+ # to be done as a special pass as the transpiler will not
43
+ # remove barriers by default.
39
44
  QIR_BASIS_GATES = [
40
- "x",
41
- "y",
42
- "z",
45
+ "measure",
46
+ "reset",
47
+ "ccx",
48
+ "cx",
49
+ "cy",
50
+ "cz",
43
51
  "rx",
52
+ "rxx",
53
+ "crx",
44
54
  "ry",
55
+ "ryy",
56
+ "cry",
45
57
  "rz",
58
+ "rzz",
59
+ "crz",
46
60
  "h",
47
- "swap",
48
- "cx",
49
- "cz",
50
- "reset",
51
61
  "s",
52
62
  "sdg",
63
+ "swap",
53
64
  "t",
54
65
  "tdg",
55
- "measure",
66
+ "x",
67
+ "y",
68
+ "z",
69
+ "id",
70
+ "ch",
56
71
  ]
57
72
 
58
73
 
@@ -391,98 +406,139 @@ class AzureQirBackend(AzureBackendBase):
391
406
  return {}
392
407
 
393
408
  def _generate_qir(
394
- self, circuits, targetCapability, **to_qir_kwargs
395
- ) -> Tuple[Module, List[str]]:
409
+ self, circuits: List[QuantumCircuit], target_profile: TargetProfile, **kwargs
410
+ ) -> pyqir.Module:
411
+
412
+ if len(circuits) == 0:
413
+ raise ValueError("No QuantumCircuits provided")
396
414
 
397
415
  config = self.configuration()
398
416
  # Barriers aren't removed by transpilation and must be explicitly removed in the Qiskit to QIR translation.
399
- emit_barrier_calls = "barrier" in config.basis_gates
400
- return to_qir_module(
401
- circuits,
402
- targetCapability,
403
- emit_barrier_calls=emit_barrier_calls,
404
- **to_qir_kwargs,
417
+ supports_barrier = "barrier" in config.basis_gates
418
+ skip_transpilation = kwargs.pop("skip_transpilation", False)
419
+
420
+ backend = QSharpBackend(
421
+ qiskit_pass_options={"supports_barrier": supports_barrier},
422
+ target_profile=target_profile,
423
+ skip_transpilation=skip_transpilation,
424
+ **kwargs,
405
425
  )
406
426
 
407
- def _get_qir_str(self, circuits, targetCapability, **to_qir_kwargs) -> str:
408
- module, _ = self._generate_qir(circuits, targetCapability, **to_qir_kwargs)
427
+ name = "batch"
428
+ if len(circuits) == 1:
429
+ name = circuits[0].name
430
+
431
+ if isinstance(circuits, list):
432
+ for value in circuits:
433
+ if not isinstance(value, QuantumCircuit):
434
+ raise ValueError("Input must be List[QuantumCircuit]")
435
+ else:
436
+ raise ValueError("Input must be List[QuantumCircuit]")
437
+
438
+ context = pyqir.Context()
439
+ llvm_module = pyqir.qir_module(context, name)
440
+ for circuit in circuits:
441
+ qir_str = backend.qir(circuit)
442
+ module = pyqir.Module.from_ir(context, qir_str)
443
+ llvm_module.link(module)
444
+ err = llvm_module.verify()
445
+ if err is not None:
446
+ raise Exception(err)
447
+
448
+ return llvm_module
449
+
450
+ def _get_qir_str(
451
+ self,
452
+ circuits: List[QuantumCircuit],
453
+ target_profile: TargetProfile,
454
+ **to_qir_kwargs,
455
+ ) -> str:
456
+ module = self._generate_qir(circuits, target_profile, **to_qir_kwargs)
409
457
  return str(module)
410
458
 
411
459
  def _translate_input(
412
- self, circuits: List[QuantumCircuit], input_params: Dict[str, Any]
460
+ self, circuits: Union[QuantumCircuit, List[QuantumCircuit]], input_params: Dict[str, Any]
413
461
  ) -> bytes:
414
462
  """Translates the input values to the QIR expected by the Backend."""
415
463
  logger.info(f"Using QIR as the job's payload format.")
416
- config = self.configuration()
464
+ if not (isinstance(circuits, list)):
465
+ circuits = [circuits]
417
466
 
418
- # Override QIR translation parameters
419
- # We will record the output by default, but allow the backend to override this, and allow the user to override the backend.
420
- to_qir_kwargs = input_params.pop(
421
- "to_qir_kwargs", config.azure.get("to_qir_kwargs", {"record_output": True})
422
- )
423
- targetCapability = input_params.pop(
424
- "targetCapability",
425
- self.options.get("targetCapability", "AdaptiveExecution"),
426
- )
467
+ target_profile = self._get_target_profile(input_params)
427
468
 
428
469
  if logger.isEnabledFor(logging.DEBUG):
429
- qir = self._get_qir_str(circuits, targetCapability, **to_qir_kwargs)
470
+ qir = self._get_qir_str(circuits, target_profile, skip_transpilation=True)
430
471
  logger.debug(f"QIR:\n{qir}")
431
472
 
432
473
  # We'll transpile automatically to the supported gates in QIR unless explicitly skipped.
433
- if not input_params.pop("skipTranspile", False):
434
- # Set of gates supported by QIR targets.
435
- circuits = transpile(
436
- circuits, basis_gates=config.basis_gates, optimization_level=0
437
- )
474
+ skip_transpilation = input_params.pop("skipTranspile", False)
475
+
476
+ module = self._generate_qir(
477
+ circuits, target_profile, skip_transpilation=skip_transpilation
478
+ )
479
+
480
+ def get_func_name(func: pyqir.Function) -> str:
481
+ return func.name
482
+
483
+ entry_points = list(
484
+ map(get_func_name, filter(pyqir.is_entry_point, module.functions))
485
+ )
486
+
487
+ if not skip_transpilation:
438
488
  # We'll only log the QIR again if we performed a transpilation.
439
489
  if logger.isEnabledFor(logging.DEBUG):
440
- qir = self._get_qir_str(circuits, targetCapability, **to_qir_kwargs)
490
+ qir = str(module)
441
491
  logger.debug(f"QIR (Post-transpilation):\n{qir}")
442
492
 
443
- (module, entry_points) = self._generate_qir(
444
- circuits, targetCapability, **to_qir_kwargs
445
- )
446
-
447
- if not "items" in input_params:
493
+ if "items" not in input_params:
448
494
  arguments = input_params.pop("arguments", [])
449
495
  input_params["items"] = [
450
496
  {"entryPoint": name, "arguments": arguments} for name in entry_points
451
497
  ]
452
498
 
453
- return module.bitcode
499
+ return str(module).encode("utf-8")
454
500
 
455
- def _estimate_cost_qir(self, circuits, shots, options={}):
501
+ def _estimate_cost_qir(
502
+ self, circuits: Union[QuantumCircuit, List[QuantumCircuit]], shots, options={}
503
+ ):
456
504
  """Estimate the cost for the given circuit."""
457
- config = self.configuration()
458
505
  input_params = self._get_input_params(options, shots=shots)
459
506
 
460
507
  if not (isinstance(circuits, list)):
461
508
  circuits = [circuits]
462
-
463
- to_qir_kwargs = input_params.pop(
464
- "to_qir_kwargs", config.azure.get("to_qir_kwargs", {"record_output": True})
465
- )
466
- targetCapability = input_params.pop(
467
- "targetCapability",
468
- self.options.get("targetCapability", "AdaptiveExecution"),
469
- )
470
509
 
471
- if not input_params.pop("skipTranspile", False):
472
- # Set of gates supported by QIR targets.
473
- circuits = transpile(
474
- circuits, basis_gates=config.basis_gates, optimization_level=0
475
- )
476
-
477
-
478
- (module, _) = self._generate_qir(
479
- circuits, targetCapability, **to_qir_kwargs
510
+ skip_transpilation = input_params.pop("skipTranspile", False)
511
+ target_profile = self._get_target_profile(input_params)
512
+ module = self._generate_qir(
513
+ circuits, target_profile, skip_transpilation=skip_transpilation
480
514
  )
481
-
515
+
482
516
  workspace = self.provider().get_workspace()
483
517
  target = workspace.get_targets(self.name())
484
518
  return target.estimate_cost(module, shots=shots)
485
519
 
520
+ def _get_target_profile(self, input_params) -> TargetProfile:
521
+ # Default to Adaptive_RI if not specified on the backend
522
+ # this is really just a safeguard in case the backend doesn't have a default
523
+ default_profile = self.options.get("target_profile", TargetProfile.Adaptive_RI)
524
+
525
+ # If the user is using the old targetCapability parameter, we'll warn them
526
+ # and use that value for now. This will be removed in the future.
527
+ if "targetCapability" in input_params:
528
+ warnings.warn(
529
+ "The 'targetCapability' parameter is deprecated and will be ignored in the future. "
530
+ "Please, use 'target_profile' parameter instead.",
531
+ category=DeprecationWarning,
532
+ )
533
+ cap = input_params.pop("targetCapability")
534
+ if cap == "AdaptiveExecution":
535
+ default_profile = TargetProfile.Adaptive_RI
536
+ else:
537
+ default_profile = TargetProfile.Base
538
+ # If the user specifies a target profile, use that.
539
+ # Otherwise, use the profile we got from the backend/targetCapability.
540
+ return input_params.pop("target_profile", default_profile)
541
+
486
542
 
487
543
  class AzureBackend(AzureBackendBase):
488
544
  """Base class for interfacing with a backend in Azure Quantum"""
@@ -7,7 +7,7 @@ from azure.quantum import __version__
7
7
  from azure.quantum.qiskit.job import AzureQuantumJob
8
8
  from azure.quantum.target.ionq import IonQ
9
9
  from abc import abstractmethod
10
-
10
+ from qsharp import TargetProfile
11
11
  from qiskit import QuantumCircuit
12
12
 
13
13
  from .backend import (
@@ -65,7 +65,7 @@ class IonQQirBackendBase(AzureQirBackend):
65
65
  **{
66
66
  cls._SHOTS_PARAM_NAME: _DEFAULT_SHOTS_COUNT,
67
67
  },
68
- targetCapability="BasicExecution",
68
+ target_profile=TargetProfile.Base,
69
69
  )
70
70
 
71
71
  def _azure_config(self) -> Dict[str, str]:
@@ -147,7 +147,7 @@ class IonQAriaQirBackend(IonQQirBackendBase):
147
147
  "description": "IonQ Aria QPU on Azure Quantum",
148
148
  "basis_gates": self._basis_gates(),
149
149
  "memory": False,
150
- "n_qubits": 23,
150
+ "n_qubits": 25,
151
151
  "conditional": False,
152
152
  "max_shots": 10000,
153
153
  "max_experiments": 1,
@@ -0,0 +1,161 @@
1
+ ##
2
+ # Copyright (c) Microsoft Corporation.
3
+ # Licensed under the MIT License.
4
+ ##
5
+
6
+ from typing import TYPE_CHECKING, Any, Dict, List, Union
7
+ from azure.quantum.version import __version__
8
+ from qiskit import QuantumCircuit
9
+ from abc import abstractmethod
10
+ from .backend import AzureQirBackend, QIR_BASIS_GATES
11
+
12
+ from qiskit.providers.models import BackendConfiguration
13
+ from qiskit.providers import Options, Provider
14
+ from qsharp import TargetProfile
15
+ from qsharp.interop.qiskit import ResourceEstimatorBackend
16
+ import pyqir as pyqir
17
+
18
+ if TYPE_CHECKING:
19
+ from azure.quantum.qiskit import AzureQuantumProvider
20
+
21
+ import logging
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ __all__ = ["MicrosoftBackend", "MicrosoftResourceEstimationBackend"]
26
+
27
+
28
+ class MicrosoftBackend(AzureQirBackend):
29
+ """Base class for interfacing with a Microsoft backend in Azure Quantum"""
30
+
31
+ @abstractmethod
32
+ def __init__(
33
+ self, configuration: BackendConfiguration, provider: Provider = None, **fields
34
+ ):
35
+ super().__init__(configuration, provider, **fields)
36
+
37
+ @classmethod
38
+ def _default_options(cls):
39
+ return Options(target_profile=TargetProfile.Adaptive_RI)
40
+
41
+ def _azure_config(self) -> Dict[str, str]:
42
+ config = super()._azure_config()
43
+ config.update(
44
+ {
45
+ "provider_id": "microsoft-qc",
46
+ "output_data_format": "microsoft.resource-estimates.v1",
47
+ }
48
+ )
49
+ return config
50
+
51
+ def _translate_input(
52
+ self,
53
+ circuits: Union[QuantumCircuit, List[QuantumCircuit]],
54
+ input_params: Dict[str, Any],
55
+ ) -> bytes:
56
+ """Translates the input values to the QIR expected by the Backend."""
57
+ # All the logic is in the base class, but we need to override
58
+ # this method to ensure that the bitcode QIR format is used for RE.
59
+
60
+ # normal translation is to QIR text format in utf-8 encoded bytes
61
+ ir_byte_str = super()._translate_input(circuits, input_params)
62
+ # decode the utf-8 encoded bytes to a string
63
+ ir_str = ir_byte_str.decode('utf-8')
64
+ # convert the QIR text format to QIR bitcode format
65
+ module = pyqir.Module.from_ir(pyqir.Context(), ir_str)
66
+ return module.bitcode
67
+
68
+ def _generate_qir(
69
+ self, circuits: List[QuantumCircuit], target_profile: TargetProfile, **kwargs
70
+ ) -> pyqir.Module:
71
+ if len(circuits) == 0:
72
+ raise ValueError("No QuantumCircuits provided")
73
+
74
+ name = "circuits"
75
+ if isinstance(circuits, QuantumCircuit):
76
+ name = circuits.name
77
+ circuits = [circuits]
78
+ elif isinstance(circuits, list):
79
+ for value in circuits:
80
+ if not isinstance(value, QuantumCircuit):
81
+ raise ValueError(
82
+ "Input must be Union[QuantumCircuit, List[QuantumCircuit]]"
83
+ )
84
+ else:
85
+ raise ValueError(
86
+ "Input must be Union[QuantumCircuit, List[QuantumCircuit]]"
87
+ )
88
+
89
+ skip_transpilation = kwargs.pop("skip_transpilation", False)
90
+ backend = ResourceEstimatorBackend(
91
+ skip_transpilation=skip_transpilation, **kwargs
92
+ )
93
+ context = pyqir.Context()
94
+ llvm_module = pyqir.qir_module(context, name)
95
+ for circuit in circuits:
96
+ qir_str = backend.qir(circuit, target_profile=target_profile)
97
+ module = pyqir.Module.from_ir(context, qir_str)
98
+ llvm_module.link(module)
99
+
100
+ # Add NOOP for recording output tuples
101
+ # the service isn't set up to handle any output recording calls
102
+ # and the Q# compiler will always emit them.
103
+ noop_tuple_record_output = """; NOOP the extern calls to recording output tuples
104
+ define void @__quantum__rt__tuple_record_output(i64, i8*) {
105
+ ret void
106
+ }"""
107
+ noop_tuple_record_output_module = pyqir.Module.from_ir(
108
+ context, noop_tuple_record_output
109
+ )
110
+ llvm_module.link(noop_tuple_record_output_module)
111
+
112
+ err = llvm_module.verify()
113
+ if err is not None:
114
+ raise Exception(err)
115
+
116
+ return llvm_module
117
+
118
+
119
+ class MicrosoftResourceEstimationBackend(MicrosoftBackend):
120
+ """Backend class for interfacing with the resource estimator target"""
121
+
122
+ backend_names = ("microsoft.estimator",)
123
+
124
+ @classmethod
125
+ def _default_options(cls):
126
+ return Options(
127
+ target_profile=TargetProfile.Adaptive_RI,
128
+ errorBudget=1e-3,
129
+ qubitParams={"name": "qubit_gate_ns_e3"},
130
+ qecScheme={"name": "surface_code"}
131
+ )
132
+
133
+ def __init__(self, name: str, provider: "AzureQuantumProvider", **kwargs):
134
+ """Constructor for class to interface with the resource estimator target"""
135
+ default_config = BackendConfiguration.from_dict(
136
+ {
137
+ "backend_name": name,
138
+ "backend_version": __version__,
139
+ "simulator": True,
140
+ "local": False,
141
+ "coupling_map": None,
142
+ "description": "Resource estimator on Azure Quantum",
143
+ "basis_gates": QIR_BASIS_GATES,
144
+ "memory": False,
145
+ "n_qubits": 0xFFFFFFFFFFFFFFFF, # NOTE: maximum 64-bit unsigned value
146
+ "conditional": True,
147
+ "max_shots": 1,
148
+ "max_experiments": 1,
149
+ "open_pulse": False,
150
+ "gates": [
151
+ {"name": "TODO", "parameters": [], "qasm_def": "TODO"}
152
+ ], # NOTE: copied from other backends
153
+ "azure": self._azure_config(),
154
+ "is_default": True,
155
+ }
156
+ )
157
+ logger.info("Initializing MicrosoftResourceEstimationBackend")
158
+ configuration: BackendConfiguration = kwargs.pop(
159
+ "configuration", default_config
160
+ )
161
+ super().__init__(configuration=configuration, provider=provider, **kwargs)
@@ -3,7 +3,7 @@
3
3
  # Licensed under the MIT License.
4
4
  ##
5
5
 
6
- from typing import TYPE_CHECKING, Dict
6
+ from typing import TYPE_CHECKING, Dict, List
7
7
  from azure.quantum.version import __version__
8
8
  from azure.quantum.qiskit.job import AzureQuantumJob
9
9
  from abc import abstractmethod
@@ -14,6 +14,8 @@ from .backend import (
14
14
 
15
15
  from qiskit.providers.models import BackendConfiguration
16
16
  from qiskit.providers import Options, Provider
17
+ from qsharp import TargetProfile
18
+
17
19
 
18
20
  if TYPE_CHECKING:
19
21
  from azure.quantum.qiskit import AzureQuantumProvider
@@ -43,7 +45,7 @@ class QCIBackend(AzureQirBackend):
43
45
  **{
44
46
  cls._SHOTS_PARAM_NAME: _DEFAULT_SHOTS_COUNT,
45
47
  },
46
- targetCapability="AdaptiveExecution",
48
+ target_profile=TargetProfile.Adaptive_RI,
47
49
  )
48
50
 
49
51
  def _azure_config(self) -> Dict[str, str]:
@@ -54,9 +56,12 @@ class QCIBackend(AzureQirBackend):
54
56
  }
55
57
  )
56
58
  return config
57
-
59
+
60
+ def _basis_gates(self) -> List[str]:
61
+ return super()._basis_gates() + ["barrier"]
62
+
58
63
  def run(
59
- self,
64
+ self,
60
65
  run_input=None,
61
66
  shots: int = None,
62
67
  **options,
@@ -15,7 +15,7 @@ from qiskit.providers.models import BackendConfiguration
15
15
  from qiskit.providers import Options
16
16
  from qiskit.providers import Provider
17
17
  from qiskit.qasm2 import dumps
18
-
18
+ from qsharp import TargetProfile
19
19
  import logging
20
20
 
21
21
  logger = logging.getLogger(__name__)
@@ -50,23 +50,6 @@ QUANTINUUM_BASIS_GATES = [
50
50
  "reset",
51
51
  ]
52
52
 
53
- QUANTINUUM_QIR_BASIS_GATES = [
54
- "x",
55
- "y",
56
- "z",
57
- "rx",
58
- "ry",
59
- "rz",
60
- "h",
61
- "cx",
62
- "cz",
63
- "reset",
64
- "s",
65
- "sdg",
66
- "t",
67
- "tdg",
68
- "measure",
69
- ]
70
53
 
71
54
  QUANTINUUM_PROVIDER_ID = "quantinuum"
72
55
  QUANTINUUM_PROVIDER_NAME = "Quantinuum"
@@ -101,7 +84,7 @@ class QuantinuumQirBackendBase(AzureQirBackend):
101
84
  **{
102
85
  cls._SHOTS_PARAM_NAME: _DEFAULT_SHOTS_COUNT
103
86
  },
104
- targetCapability="BasicExecution",
87
+ target_profile=TargetProfile.Adaptive_RI,
105
88
  )
106
89
 
107
90
  def _azure_config(self) -> Dict[str, str]:
@@ -112,9 +95,6 @@ class QuantinuumQirBackendBase(AzureQirBackend):
112
95
  }
113
96
  )
114
97
  return config
115
-
116
- def _basis_gates(self) -> List[str]:
117
- return QUANTINUUM_QIR_BASIS_GATES
118
98
 
119
99
  def _get_n_qubits(self, name):
120
100
  return _get_n_qubits(name)
@@ -11,6 +11,7 @@ from .backend import AzureQirBackend
11
11
 
12
12
  from qiskit.providers.models import BackendConfiguration
13
13
  from qiskit.providers import Options, Provider
14
+ from qsharp import TargetProfile
14
15
 
15
16
  if TYPE_CHECKING:
16
17
  from azure.quantum.qiskit import AzureQuantumProvider
@@ -40,7 +41,7 @@ class RigettiBackend(AzureQirBackend):
40
41
  other_options = {
41
42
  cls._SHOTS_PARAM_NAME: _DEFAULT_SHOTS_COUNT,
42
43
  }
43
- return Options(targetCapability="BasicExecution", **other_options)
44
+ return Options(target_profile=TargetProfile.Base, **other_options)
44
45
 
45
46
  def _azure_config(self) -> Dict[str, str]:
46
47
  config = super()._azure_config()
@@ -212,7 +212,7 @@ class AzureQuantumJob(JobV1):
212
212
 
213
213
  @staticmethod
214
214
  def _qir_to_qiskit_bitstring(obj):
215
- """Convert the data structure from Azure into the "schema" used by Qiskit """
215
+ """Convert the data structure from Azure into the "schema" used by Qiskit"""
216
216
  if isinstance(obj, str) and not re.match(r"[\d\s]+$", obj):
217
217
  obj = ast.literal_eval(obj)
218
218
 
@@ -220,7 +220,12 @@ class AzureQuantumJob(JobV1):
220
220
  # the outermost implied container is a tuple, and each item is
221
221
  # associated with a classical register. Azure and Qiskit order the
222
222
  # registers in opposite directions, so reverse here to match.
223
- return " ".join([AzureQuantumJob._qir_to_qiskit_bitstring(term) for term in reversed(obj)])
223
+ return " ".join(
224
+ [
225
+ AzureQuantumJob._qir_to_qiskit_bitstring(term)
226
+ for term in obj
227
+ ]
228
+ )
224
229
  elif isinstance(obj, list):
225
230
  # a list is for an individual classical register
226
231
  return "".join([str(bit) for bit in obj])
@@ -59,12 +59,16 @@ class IonQ(Target):
59
59
  name: str = "ionq.simulator",
60
60
  input_data_format: str = "ionq.circuit.v1",
61
61
  output_data_format: str = "ionq.quantum-results.v1",
62
- capability: str = "BasicExecution",
62
+ capability: str = "",
63
63
  provider_id: str = "IonQ",
64
64
  content_type: str = "application/json",
65
65
  encoding: str = "",
66
- **kwargs
66
+ target_profile: Union[str, "TargetProfile"] = "Base",
67
+ **kwargs,
67
68
  ):
69
+ if capability:
70
+ msg = "The 'capability' parameter is not used for the Quantinuum target."
71
+ warn(msg, DeprecationWarning)
68
72
  super().__init__(
69
73
  workspace=workspace,
70
74
  name=name,
@@ -74,7 +78,8 @@ class IonQ(Target):
74
78
  provider_id=provider_id,
75
79
  content_type=content_type,
76
80
  encoding=encoding,
77
- **kwargs
81
+ target_profile=target_profile,
82
+ **kwargs,
78
83
  )
79
84
 
80
85
  def submit(
@@ -392,6 +392,7 @@ class MicrosoftEstimator(Target):
392
392
  output_data_format="microsoft.resource-estimates.v1",
393
393
  provider_id="microsoft-qc",
394
394
  content_type=ContentType.json,
395
+ target_profile="Adaptive_RI",
395
396
  **kwargs
396
397
  )
397
398
 
@@ -422,14 +423,32 @@ class MicrosoftEstimator(Target):
422
423
  warnings.warn("The 'shots' parameter is ignored in resource estimation job.")
423
424
 
424
425
  try:
425
- from qiskit import QuantumCircuit, transpile
426
- from qiskit_qir import to_qir_module
427
- from qiskit_qir.visitor import SUPPORTED_INSTRUCTIONS
426
+ from qiskit import QuantumCircuit
427
+ from qsharp import TargetProfile
428
+ from qsharp.interop.qiskit import ResourceEstimatorBackend
429
+ from pyqir import Context, Module
430
+
428
431
  if isinstance(input_data, QuantumCircuit):
429
- input_data = transpile(input_data,
430
- basis_gates=SUPPORTED_INSTRUCTIONS,
431
- optimization_level=0)
432
- (module, _) = to_qir_module(input_data, record_output=False)
432
+ backend = ResourceEstimatorBackend()
433
+ target_profile = TargetProfile.from_str(self.target_profile)
434
+ qir_str = backend.qir(input_data, target_profile=target_profile)
435
+ context = Context()
436
+ module = Module.from_ir(context, qir_str)
437
+ # Add NOOP for recording output tuples
438
+ # the service isn't set up to handle any output recording calls
439
+ # and the Q# compiler will always emit them.
440
+ noop_tuple_record_output = """; NOOP the extern calls to recording output tuples
441
+ define void @__quantum__rt__tuple_record_output(i64, i8*) {
442
+ ret void
443
+ }"""
444
+ noop_tuple_record_output_module = Module.from_ir(
445
+ context, noop_tuple_record_output
446
+ )
447
+ module.link(noop_tuple_record_output_module)
448
+
449
+ err = module.verify()
450
+ if err is not None:
451
+ raise Exception(err)
433
452
  input_data = module.bitcode
434
453
  finally:
435
454
  return super().submit(