Skip to main content
IBM Quantum Platform

プロバイダーインターフェース

qiskit.providers

このモジュールには、Qiskit用の外部プロバイダーを構築するために使用されるクラスが含まれています。 プロバイダーとは、Qiskitに対して外部サービスを提供するあらゆるものを指します。 その典型的な例として、オブジェクトの実行 QuantumCircuit に使用できるオブジェクトを提供 Backend するバックエンドプロバイダーが挙げられます。 このモジュールには、プロバイダーとQiskit間のインターフェースを定義するために使用される抽象クラスが含まれています。


バージョン・サポート

プロバイダー・インターフェースの抽象クラスは、それぞれ個別にバージョン管理されている。 インターフェイスを変更する必要がある場合、新しいインターフェイスを定義するために新しい抽象クラスが作成される。 これらのインターフェイスの変更は、バージョン間の後方互換性を保証するものではありません。

バージョン変更

qiskit の各マイナーバージョンリリースは、バックエンドインターフェースのバージョンを1つのバージョン番号でインクリメントすることができる。 これは、そのインターフェイスにおける、そのリリースのすべてのインターフェイスの変更の集約となる。

バージョン・サポート・ポリシー

プロバイダーがこのインターフェイスの変更に適応する時間を持てるようにするため、Qiskitは各クラスの複数のバージョンを一度にサポートします。 リリースごとに1バージョンという性質を考えると、バージョンの非推奨方針は標準的な非推奨方針よりも少し保守的だ。 Qiskitは、最低3回のマイナーリリース、またはバージョンを導入したリリースから6ヶ月後の最初のリリースのいずれか長い方の期間、非推奨になる可能性がある前にプロバイダインターフェースのバージョンをサポートします。 それ以降は、標準の非推奨ポリシーがそのインターフェイスのバージョンに適用される。 これにより、プロバイダーとユーザーは、インターフェイスの変更に対応するための十分な時間を得ることができる。 例えば、 0.19.0 BackendV2 。 0.19.0 のリリースの3ヶ月後に、 0.20.0、 0.21.0、 0.22.0 をリリースし、 0.19.0 の7ヶ月後に、 0.23.0 をリリースするとする。 0.23.0 では、 BackendV2 を非推奨とすることができる。非推奨ポリシーが完了するまでは、まだサポートされる必要があり、削除することはできない。

Qiskitのバージョンサポート方針は、プロバイダー自身が同じサポートストーリーを持つことを意味するものではなく、プロバイダーはできる限り早く新しいバージョンにアップデートすることができる(そして間違いなくそうすべきです)。 非推奨化の前にこの長い期間を設けるのは、プロバイダーがバージョンを上げる前に、エンドユーザーに影響を与える可能性のあるインターフェイスの変更を、自ら非推奨化するのに十分な時間を与えるためである。 例えば、 BackendV34 、後方互換性のない方法でシグネチャーを Backend.run() に変更したとしよう。 Aerがその AerSimulator クラスをバージョン34をベースにしたものに更新する前に、古いシグネチャを非推奨にする必要がある。 そのため、バージョン33を削除する(つまりバージョン34を必須/最小バージョンとする)前に、Aerが非推奨サイクルを完了するのに十分な時間を確保する必要があります。


抽象クラス

バックエンド

コラム「 1 」
コラム「 2 」
Backend()すべてのバージョン管理された Backend 抽象クラスの基本共通型。
BackendV2( [プロバイダー、名前、説明、……] )バックエンドの抽象クラス
QubitProperties( [t1、 t2、frequency] )QubitProperties オブジェクトの表現。

オプション

コラム「 1 」
コラム「 2 」
Options(**kwargs)ベース・オプション・オブジェクト

ジョブ

コラム「 1 」
コラム「 2 」
Job()すべてのバージョン管理されたジョブ抽象クラスの基本共通型。
JobV1(backend, job_id, **kwargs)ジョブを処理するクラス

ジョブ ステータス

コラム「 1 」
コラム「 2 」
JobStatus(*値)ジョブ・ステータス列挙型のクラス。

例外

QiskitBackendNotFoundError

exception qiskit.providers.QiskitBackendNotFoundError(*message)

GitHub

ベース: QiskitError

バックエンドを探す際に発生するエラーの基底クラス。

エラーメッセージを設定する。

JobError

exception qiskit.providers.JobError(*message)

GitHub

ベース: QiskitError

ジョブによって発生するエラーの基本クラス。

エラーメッセージを設定する。

JobTimeoutError

exception qiskit.providers.JobTimeoutError(*message)

GitHub

ベース: JobError

ジョブが発生させるタイムアウトエラーの基底クラス。

エラーメッセージを設定する。


新しいバックエンドの記述

Qiskitと連携させたい量子デバイスやシミュレータをお持ちの場合は、バックエンドを作成する必要があります。 プロバイダーとは、バックエンドの集合体であり、Qiskitに対して利用 BackendV2 可能なオブジェクトを取得する方法を用意するものです。 この BackendV2 オブジェクトは、バックエンドに関する情報と、その動作に関する情報を transpiler 提供することで、回路が最適化され、バックエンド上で実行可能な形式にコンパイルされるようにします。 また、この QuantumCircuit オブジェクトを実行できるメソッドも run() 提供しています。 これにより、ユーザーやその他のQiskit APIは、バックエンドがどのように実装されているかに関係なく、デバイス上で回路を実行した結果を一貫した方法で取得できるようになります。 大まかに言えば、プロバイダを作成するための基本的な手順は次のとおりです:

  • バックエンドへのアクセスを処理する Provider クラスを実装する。

  • サブクラス BackendV2 とその run() メソッドを実装してください。

    • バックエンドの基底に対するカスタムゲートを、セッション EquivalenceLibrary インスタンスに追加します。
  • JobV1 実行中のジョブとのやり取りを処理するサブクラスを実装してください。

プロバイダの簡単な例については、 qiskit-aqt-provider

プロバイダー

プロバイダ・クラスの目的はただ一つ、デバイスやシミュレータ上で回路を実行するためのバックエンド・オブジェクトを取得することです。 期待されるのは、必要とされるクレデンシャルや認証は、プロバイダ・オブジェクトの初期化で処理されることである。 プロバイダオブジェクトは、バックエンドのリストと、バックエンドをフィルタリングして取得するメソッドを提供します(必要であれば、提供された認証情報を使用します)。 プロバイダー・クラスの例は次のようになる:

from qiskit.providers.providerutils import filter_backends

from .backend import MyBackend

class MyProvider:

    def __init__(self, token=None):
        super().__init__()
        self.token = token
        self.backends = [MyBackend(provider=self)]

    def backends(self, name=None, **kwargs):
        if name:
            backends = [
                backend for backend in backends if backend.name() == name]
        return filter_backends(backends, filters=filters, **kwargs)

(必要な場合)認証に必要な情報がクラス内に含まれていること、およびバックエンドのメソッドが要求されるインターフェースに準拠していることを確認してください。 具体的な実装方法については、各プロバイダーの判断に委ねられます。

バックエンド

バックエンドクラスは、プロバイダーの中核をなすものです。 これらのクラスは、Qiskitと、回路を実行するハードウェアやシミュレータとの間のインターフェースを提供するものです。 これには、コンパイラがバックエンド向けの任意の回路を組み込み、最適化できるよう、バックエンドを記述するために必要な情報をコンパイラに提供することも含まれます。 すべてのバックエンドオブジェクトには、4つの必須要素があります。コンパイラに対してバックエンドのモデルを定義するプロパティ target 、バックエンドが1回のバッチジョブで実行できる回路数の制限を定義するプロパティ max_circuits (制限 None がない場合は を使用できます)、ジョブの送信を受け付けるメソッド run() 、およびユーザーが設定可能なオプションとそのデフォルト値を定義するメソッドです _default_options 。 たとえば、最低限の動作するサンプルとしては、次のようなものになります:

from qiskit.providers import BackendV2 as Backend
from qiskit.transpiler import Target
from qiskit.providers import Options
from qiskit.circuit import Parameter, Measure
from qiskit.circuit.library import PhaseGate, SXGate, UGate, CXGate, IGate


class Mybackend(Backend):

    def __init__(self):
        super().__init__()

        # Create Target
        self._target = Target("Target for My Backend")
        # Instead of None for this and below instructions you can define
        # a qiskit.transpiler.InstructionProperties object to define properties
        # for an instruction.
        lam = Parameter("λ")
        p_props = {(qubit,): None for qubit in range(5)}
        self._target.add_instruction(PhaseGate(lam), p_props)
        sx_props = {(qubit,): None for qubit in range(5)}
        self._target.add_instruction(SXGate(), sx_props)
        phi = Parameter("φ")
        theta = Parameter("ϴ")
        u_props = {(qubit,): None for qubit in range(5)}
        self._target.add_instruction(UGate(theta, phi, lam), u_props)
        cx_props = {edge: None for edge in [(0, 1), (1, 2), (2, 3), (3, 4)]}
        self._target.add_instruction(CXGate(), cx_props)
        meas_props = {(qubit,): None for qubit in range(5)}
        self._target.add_instruction(Measure(), meas_props)
        id_props = {(qubit,): None for qubit in range(5)}
        self._target.add_instruction(IGate(), id_props)

        # Set option validators
        self.options.set_validator("shots", (1, 4096))
        self.options.set_validator("memory", bool)

    @property
    def target(self):
        return self._target

    @property
    def max_circuits(self):
        return 1024

    @classmethod
    def _default_options(cls):
        return Options(shots=1024, memory=False)

    def run(self, circuits, **kwargs):
        # serialize circuits submit to backend and create a job
        for kwarg in kwargs:
            if not hasattr(self.options, kwarg):
                warnings.warn(
                    "Option %s is not used by this backend" % kwarg,
                    UserWarning, stacklevel=2)
        options = {
            'shots': kwargs.get('shots', self.options.shots),
            'memory': kwargs.get('memory', self.options.memory),
        }
        job_json = convert_to_wire_format(circuit, options)
        job_handle = submit_to_backend(job_json)
        return MyJob(self.job_handle, job_json, circuit)

バックエンドのトランスパイラインターフェース

この Backend オブジェクトの重要な点は、コンパイラに対して自分自身をどのように記述するかという点にある。 これは、トランスパイラのバックエンドのモデルを定義するクラス Target によって処理されます。 バックエンドオブジェクトは、属性 target から``オブジェクトを Target 返す必要があります。このオブジェクトは、関数によって transpile() コンパイル用のバックエンドターゲットのモデルとして使用されます。

カスタムベースゲート

  1. バックエンドがQiskit回路ライブラリ(qiskit.circuit.library)のゲートを使用していない場合は、プロバイダにこの機能のサポートを組み込むことができます。 これを行う基本的な方法は、まず基底セットに含まれる各カスタムゲートに対してサブ Gate クラスを定義することです。 例:

    import numpy as np
    
    from qiskit.circuit import Gate
    from qiskit.circuit import QuantumCircuit
    
    class SYGate(Gate):
        def __init__(self, label=None):
            super().__init__("sy", 1, [], label=label)
    
        def _define(self):
            qc = QuantumCircuit(1)
            qc.ry(np.pi / 2, 0)
            self.definition = qc

    重要なことは、バックエンドの基本設定にあるカスタム・ゲートのname属性(上記の __init__ 定義の super().__init__() の最初のパラメータ)が、他のゲートの名前と衝突しないようにすることです。 name属性は、トランスパイラの基底セットでゲートを識別するために使用されます。 もし競合があれば、トランスパイラーはどちらのゲートを使うべきかわからなくなる。

  2. バックエンドのターゲットにカスタムゲートを追加します。 これは メソッド Target.add_instruction() を使って行うことができます。 トランスパイラーがその存在を認識できるように、ターゲットに の SYGate インスタンスとそのパラメータを追加する必要があります。 BackendV2 たとえば、これがバックエンドの実装の一部であると仮定すると:

    from qiskit.transpiler import InstructionProperties
    
    sy_props = {
        (0,): InstructionProperties(duration=2.3e-6, error=0.0002),
        (1,): InstructionProperties(duration=2.1e-6, error=0.0001),
        (2,): InstructionProperties(duration=2.5e-6, error=0.0003),
        (3,): InstructionProperties(duration=2.2e-6, error=0.0004),
    }
    self.target.add_instruction(SYGate(), sy_props)

    sy_props のキーは、バックエンド SYGate が使用できる量子ビットを定義し、値はその量子ビット上の SYGate のプロパティを定義する。 マルチクビット・ゲートの場合、タプル・キーはゲートが動作するすべての量子ビットの組み合わせを含む(順序は重要である。 (0, 1) は (1, 0) と異なる。)

  3. バックエンドの基底セットに使用するカスタムゲートを定義したら、標準の等価性ライブラリに等価性ルールを追加する必要があります。これにより、関数および transpiler モジュールが transpile() 、そのカスタム基底セットを使用して任意の回路を変換できるようになります。 これは、標準ゲートについて、カスタムゲートを用いて等価回路を定義することで実現できます。 通常、(基底に標準的な2量子ビットゲートが含まれていない場合)と、 UGate や HGate といった一般的に使用される単一量子ビット回転ゲートから変換できれば、トランスパイラーが任意の回路をカスタム基底ゲートに変換するにはそれで CXGate 十分であるはずです。 しかし、標準ゲートからその基底への等価規則が定義されればされるほど、任意の回路から対象の基底への変換は効率的になります(ただし、常にそうであるとは限らず、効率向上の効果は次第に小さくなっていきます)。

    HGateたとえば、上記のカスタム SYGate に対していくつかのルールを追加する場合、と U2Gate を次のように定義することができます:

    from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary
    from qiskit.circuit.library import HGate
    from qiskit.circuit.library import ZGate
    from qiskit.circuit.library import RZGate
    from qiskit.circuit.library import U2Gate
    
    
    # H => Z SY
    q = qiskit.QuantumRegister(1, "q")
    def_sy_h = qiskit.QuantumCircuit(q)
    def_sy_h.append(ZGate(), [q[0]], [])
    def_sy_h.append(SYGate(), [q[0]], [])
    SessionEquivalenceLibrary.add_equivalence(
        HGate(), def_sy_h)
    
    # u2 => Z SY Z
    phi = qiskit.circuit.Parameter('phi')
    lam = qiskit.circuit.Parameter('lambda')
    q = qiskit.QuantumRegister(1, "q")
    def_sy_u2 = qiskit.QuantumCircuit(q)
    def_sy_u2.append(RZGate(lam), [q[0]], [])
    def_sy_u2.append(SYGate(), [q[0]], [])
    def_sy_u2.append(RZGate(phi), [q[0]], [])
    SessionEquivalenceLibrary.add_equivalence(
        U2Gate(phi, lam), def_sy_u2)

    これはインポート時に実行されるように設定しておくとよいでしょう。そうすれば、プロバイダーのパッケージがインポートされるとすぐに実行されます。 これにより、カスタムゲートを使用してパスが BasisTranslator 実行されるたびに、等価ルールが確実に定義されるようになります。

    Optimize1qGatesDecompositionまた、使用している基底によっては、トランスパイラ内の最適化処理(例:)の一部が、カスタム基底では実行できない場合がある点にも留意する必要があります。 この SYGate 例では、単一量子ビットゲートの連続操作をSY基底に簡略化することは Optimize1qGatesDecomposition できない。 これは、この OneQubitEulerDecomposer クラスがSY基底での処理方法を認識していないためです。 SYGateこの問題を解決するには、その SYGate クラスをQiskitに追加し、 OneQubitEulerDecomposer への分解に対応するように更新する必要があります。 長期的には、カスタムベースのゲートにとっては、それがより適切な方向性であると考えられます。また、トランスパイラーに定義やサポート機能を組み込むことで、今後もQiskitによる十分なサポートが継続されることが保証されます。

カスタムトランスパイラパス

このトランスパイラーは、ハードウェア固有の最適化や回路変換を容易にするため、バックエンドがカスタムなトランスパイラーステージの実装を提供できる機能をサポートしています。 現在、2つのステージがサポートされており、 get_translation_stage_plugin() および get_scheduling_stage_plugin() により、バックエンドは、それぞれデフォルトの翻訳ステージおよびスケジューリングステージとして使用する文字列プラグイン名を指定することができます。 クラス BackendV2 内のこれらのフックポイントは、現在のバックエンドやTarget インターフェースでは満たされないコンパイル要件がバックエンドに存在する場合に利用できます。 また、これらのインターフェースを改善し、より多くのハードウェアアーキテクチャについてより詳細に記述できるようにすることに関心が寄せられているため、ご自身のユースケースを記載したGitHubのイシューを提出することもご検討ください。

これらのフックポイントを活用するには、実装 BackendV2 にメソッドを追加し、そのメソッドから文字列形式のプラグイン名を返すようにするだけで済みます。 例:

class Mybackend(BackendV2):

    def get_scheduling_stage_plugin(self):
        return "SpecialDD"

    def get_translation_stage_plugin(self):
        return "BasisTranslatorWithCustom1qOptimization"

このバックエンド実装のスニペットは、ターゲットが に設定されているときに transpile() 関数は、ターゲットが Mybackend に設定されている場合、デフォルトでスケジューリングステージに SpecialDD プラグインを使い、翻訳ステージに BasisTranslatorWithCustom1qOptimization プラグインを使います。 ユーザーは、別のプラグイン名を明示的に選択することで、これらの選択肢を上書きすることができることに注意してください。 このインターフェイスが機能するためには、返されたプラグイン名に対してトランスパイラ・ステージ・プラグインが実装されていなければならない。 プラグインの実装方法の詳細については qiskit.transpiler.preset_passmanagers.plugin モジュールのドキュメントを参照してください。 バックエンドがコンパイル・ステージの一部としてカスタム・パスを必要とする場合、プロバイダー・パッケージには、それらのパスを使用するトランスパイラー・ステージのプラグインが含まれるというのが一般的な予想です。 しかし、これは必須ではなく、(組み込みメソッドや外部プラグインの)有効なメソッドを使用することができます。

こうすることで、 Mybackend で実行したり、効率的な出力を提供するために、これら2つのコンパイル・ステップが必要になった場合、トランスパイラーは、ユーザーによる手動入力なしに、これらのカスタム・ステップを実行できるようになる。

リアルタイム変数

トランスパイラーは、リアルタイムに型付けされた古典変数を自動的に処理し ( qiskit.circuit.classical参照)を処理し Store 命令を組み込みの「指令」として扱います。 Barrier. これを許可するために、バックエンドが特別な処理をする必要はない。

バックエンドが従来の変数やストレージを処理できない場合は、ドキュメントにその旨を明記し、メソッド run() 内にチェック処理を挿入して( Backend.run メソッドを参照)、それらを含む回路を即座に拒否することをお勧めします。 トップレベルに変数が存在するかどうかを確認 QuantumCircuit.num_vars できます。 QuantumCircuit.num_declared_vars制御フロー操作を受け入れる場合、各の内部 blocks を再帰的に検索して、スコープ局所変数を特定する必要があるかもしれません。

例えば、手動で記憶している場所があるかどうかをチェックする機能や、メモリに手動で記憶している場所があるかどうかをチェックする機能などである:

from qiskit.circuit import Store, ControlFlowOp, QuantumCircuit

def has_realtime_logic(circuit: QuantumCircuit) -> bool:
    if circuit.num_vars:
        return True
    for instruction in circuit.data:
        if isinstance(instruction.operation, Store):
            return True
        elif isinstance(instruction.operation, ControlFlowOp):
            for block in instruction.operation.blocks:
                if has_realtime_logic(block):
                    return True
    return False

ゲイツの角度境界

Targetターゲット内のいずれかのゲートについて、バックエンドで許容されるパラメータ値に制約がある場合は、これに対応する角度の制限を に設定することでモデル化できます。 この命令を追加する際、ゲートのパラメータの上限と下限を表すタプルのリストを受け取るキーワード引数 add_instruction() angle_bounds を使用できます。

たとえば、上記の例で を追加 PhaseGate する代わりに、次のようなコードスニペットがあります:

lam = Parameter("λ")
p_props = {(qubit,): None for qubit in range(5)}
self._target.add_instruction(PhaseGate(lam), p_props, angle_bounds=[(0, math.pi)])

これにより、の PhaseGate 範囲が 0 から π\pi (両端を含む)に設定されます。 PhaseGateこれは、の Target 角度値に対する角度制約を、の lam パラメータについてモデル化したものです。 トランスパイラー・パスは WrapAngles 、指定された角度の範囲外にあるものを PhaseGate 変換するために使用されます。 DAGCircuitゲートの角度値を受け取り、を返す関数を作成する必要があります。 例:

from qiskit.transpiler.passes import WrapAngles

def fold_phase(angles: List[float], qubits: List[int]) -> DAGCircuit:
    angle = angles[0]
    if angle > 0:
        number_of_gates = angle / math.pi
    else:
        number_of_gates = (6.28 - angle) / math.pi
    dag = DAGCircuit()
    dag.add_qubits([Qubit()])
    for _ in range(int(number_of_gates)):
        dag.apply_operation_back(PhaseGate(math.pi), [dag.qubits[0]])
    return dag

WrapAngles.DEFAULT_REGISTRY.add_wrapper("phase", fold_phase)

この関数は、アウトオブバウンズのゲートを、ターゲットの角度境界とターゲットの他の制約を(特にうまくはないが)尊重するものに変換する。

Backend.run 方法

特に重要なのは、回路をデバイスやシミュレータに実際に送信するために用いられる手法 run() である。 run メソッドは、実行のために回路をバックエンドに送信し、オブジェクトを Job 返す処理を行います。 バックエンドの種類によっては、通常、回路オブジェクトをバックエンドで使用されるAPI形式にシリアライズする必要があります。 バックエンドごとのシリアライゼーションの要件は異なる可能性があるため(また、ローカルシミュレータの場合は、シリアライゼーション自体が必要ない場合もある)、この変換はバックエンドの run メソッドで処理されることが想定されています。

実行メソッドの例は次のようなものだ:

def run(self, circuits, **kwargs):
    for kwarg in kwargs:
        if not hasattr(self.options, kwarg):
            warnings.warn(
                "Option %s is not used by this backend" % kwarg,
                UserWarning, stacklevel=2)
    options = {
        'shots': kwargs.get('shots', self.options.shots),
        'memory': kwargs.get('memory', self.options.memory),
    }
    job_json = convert_to_wire_format(circuit, options)
    job_handle = submit_to_backend(job_json)
    return MyJob(self.job_handle, job_json, circuit)

バックエンドオプション

回路の動作方法を制御するバックエンドには、多くの場合、いくつかの選択肢があります。 その典型的な例としては、回路が何回実行されるかを表す「回数」 shots などが挙げられます。 バックエンドで利用可能なオプションは、オブジェクト Options を使用して定義されます。 このオブジェクトは、当初、Backendクラスの メソッドによって _default_options 作成されます。 デフォルトのオプションを指定すると、バックエンドがサポートするすべてのオプションについて、デフォルト値が設定された初期化 Options 済みのオブジェクトが返されます。 たとえば、バックエンドが のみをサポート shots している場合、その _default_options メソッドは次のようになります:

@classmethod
def _default_options(cls):
    return Options(shots=1024)

また、オブジェクト Options にバリデータを設定することで、バックエンドで許容される範囲に基づいて、ユーザーが指定した値に制限や検証を行うこともできます。 たとえば、上記で定義されたオプションを "shots" 1 から 4096 までの任意の値に設定できる場合、バックエンドのオプションオブジェクトに対してバリデータは次のように設定できます:

self.options.set_validator("shots", (1, 4096))

検証オプションの完全な一覧については、ドキュメントを set_validator() 参照してください。

ジョブ

この run メソッドの出力は オブジェクト JobV1 です。 各プロバイダは、そのプロバイダの動作を定義するカスタムジョブサブクラスを実装することが求められます。 バックエンドの実行方法によって、ジョブには「同期」と「非同期」の2種類があります。 Backend.run()デフォルトでは、ジョブは非同期とみなされ、これは . で送信された回路の非同期実行へのハンドルを表すものと想定されています。 非同期ジョブオブジェクトを使用すると、ユーザーは実行状況を照会したり、実行中のジョブをキャンセルしたり、実行が完了するまで待機したりすることができます。 これは result 、ユーザー向けの主要なメソッドであり、実行が完了するまで待機し、その後、ジョブの結果を含む オブジェクトを Result 返します。

一部のバックエンド(主にローカルシミュレータ)では、回路の実行は同期処理であるため、実行中のジョブのハンドルを他の場所に返す必要はありません。 同期ジョブの場合、バックエンドの メソッドは run 、 オブジェクトが Result 生成されるまでブロックし、その内部の Result オブジェクトを伴って同期ジョブが返されることが想定されています。

非同期APIベースのバックエンドのジョブクラスの例は以下のようになる:

from qiskit.providers import JobV1 as Job
from qiskit.providers import JobError
from qiskit.providers import JobTimeoutError
from qiskit.providers.jobstatus import JobStatus
from qiskit.result import Result


class MyJob(Job):
    def __init__(self, backend, job_id, job_json, circuits):
        super().__init__(backend, job_id)
        self._backend = backend
        self.job_json = job_json
        self.circuits = circuits

    def _wait_for_result(self, timeout=None, wait=5):
        start_time = time.time()
        result = None
        while True:
            elapsed = time.time() - start_time
            if timeout and elapsed >= timeout:
                raise JobTimeoutError('Timed out waiting for result')
            result = get_job_status(self._job_id)
            if result['status'] == 'complete':
                break
            if result['status'] == 'error':
                raise JobError('Job error')
            time.sleep(wait)
        return result

    def result(self, timeout=None, wait=5):
        result = self._wait_for_result(timeout, wait)
        results = [{'success': True, 'shots': len(result['counts']),
                    'data': result['counts']}]
        return Result.from_dict({
            'results': results,
            'backend_name': self._backend.configuration().backend_name,
            'backend_version': self._backend.configuration().backend_version,
            'job_id': self._job_id,
            'success': True,
        })

    def status(self):
        result = get_job_status(self._job_id)
        if result['status'] == 'running':
            status = JobStatus.RUNNING
        elif result['status'] == 'complete':
            status = JobStatus.DONE
        else:
            status = JobStatus.ERROR
        return status

    def submit(self):
        raise NotImplementedError

そして同期の仕事だ:

class MySyncJob(Job):
    _async = False

    def __init__(self, backend, job_id, result):
        super().__init__(backend, job_id)
        self._result = result

    def submit(self):
        return

    def result(self):
        return self._result

    def status(self):
        return JobStatus.DONE

プリミティブ

プロバイダー・インターフェースの直接の一部ではないが、モジュールはプロバイダーと緊密に結合している。 qiskit.primitives モジュールはプロバイダと緊密に結合している。 具体的には、 BaseSampler や BaseEstimator のようなプリミティブなインターフェイスは、プロバイダの実装が、プロバイダのバックエンドに最適化されたカスタム実装を提供できるように設計されている。 これには、回路変換、追加の前後処理、バッチ処理、キャッシング、エラー緩和などのカスタマイズが含まれる。 モジュールのコンセプトは qiskit.primitives プリミティブオブジェクトは、処理されたより高いレベルの出力(確率分布や期待値など)を生成するためのより高いレベルの抽象化であり、効率的に最良の結果を得るための仕組みを抽象化し、これらの出力を使用したより高いレベルのアプリケーションに集中するためである。

例えば、バックエンドが mthreeの測定緩和を活用して結果の質を向上させるのに適している場合、 M3Mitigation クラスを内部的に活用して回路を実行し、mthreeから直接準確率を結果に返すプロバイダ固有の Sampler 実装を実装することができる。 こうすることで、バックエンドから直接適用される軽減措置によって、アルゴリズムが最良の結果を得ることができる。 カスタム実装の書き方については qiskit.primitives のドキュメントを参照されたい。 また、組み込みの実装もある: Sampler Estimator, BackendSampler, BackendEstimator も、これらの実装方法のリファレンス/モデルとして役立つ。

このページは役に立ちましたか?
バグや誤字の報告、またはコンテンツの要求はGitHubで行ってください。