シングルトンに関する指示
qiskit.circuit.singleton
のサブクラスを定義するためのものです。 Instruction そして Gate のサブクラスを定義するためのものです。 を例にとると XGateを例にとると、最終的なユーザー向けの結果はこうなる:
- から派生した
XGateというクラスがある。Gate. XGate(label="my_gate")のようにすると、型がまさにXGateであるオブジェクトが生成される。XGate,Gateまたはparentsで定義されたものに解決される。XGate()を実行すると、合成_SingletonXGateクラスを型とするシングルトンオブジェクトが生成される。XGateを継承するが__setattr__()をオーバーライドする。 オブジェクト自体は、シングルトン処理がない場合にXGate()が持つインスタンス属性とまったく同じ属性を持つ。 このオブジェクトはcopy(),deepcopy()を往復します。pickle.
例えば、同じことが言える、 Measureのサブクラスであって Instruction のサブクラスであり Gate.
このモジュールのクラスは上級者向けで、Qiskitの回路データモデルの核心と密接に結びついているからです。
図書館と著者の観点からすれば、以下のような強化が最低限必要である。 Gate または Instruction を強化するために最低限必要なことは SingletonGate (SingletonInstruction)を継承することである。 Gate (Instruction) を継承し、 __init__ メソッドがすべての引数にデフォルトを持つようにすることである(これらはシングルトンインスタンスの状態になる)。 例:
class XGate(SingletonGate):
def __init__(self, label=None):
super().__init__("x", 1, [], label=label)
assert XGate() is XGate()インターフェース
パブリック・クラスは標準クラス Instruction と Gateにそれぞれ対応し、これらのサブクラスです。
SingletonInstruction
class qiskit.circuit.singleton.SingletonInstruction(*args, _force_mutable=False, **kwargs)
ベース: Instruction, _SingletonBase
デフォルトではシングルトン・インスタンスである Instruction デフォルトではシングルトン・インスタンスです。
このクラスは、固定された定義を持ち、固有の状態を含まない命令クラスに使用されるべきである。 このようなものの典型的な例は Measure です。 Measure のどのインスタンスも同じである。 この種のゲートクラスの基本クラスとしてシングルトン命令を使用することで、複数命令のメモリフットプリントにおいて大きな利点が得られる。
しかし、このクラスで注意しなければならない例外がある。 Instruction 属性 label であり、ゲートの特定のインスタンスに対して異なる設定をすることができる。 そのため SingletonInstruction これらの属性は、作成時に設定するか、あるいは to_mutable(). これらの属性のいずれかが作成中に使用された場合、同じゲートの単一の共有グローバル・インスタンスを使用する代わりに、新しい個別のインスタンスが作成されます。
SingletonGate
class qiskit.circuit.singleton.SingletonGate(*args, _force_mutable=False, **kwargs)
ベース: Gate, _SingletonBase
デフォルトではシングルトン・インスタンスである Gate デフォルトではシングルトン・インスタンスです。
このクラスは SingletonInstructionによく似ている。 Gate を意味する。 このクラスで属性を設定する際の注意点は、ここでも同様に適用される。
SingletonControlledGate
class qiskit.circuit.singleton.SingletonControlledGate(*args, _force_mutable=False, **kwargs)
ベース: ControlledGate, _SingletonBase
デフォルトのシングルトン・インスタンス ControlledGate デフォルトではシングルトン・インスタンスである
このクラスは SingletonInstructionによく似ている。 ControlledGate を意味する。 このクラスで属性を設定する際の注意点は、ここでも同様に適用される。
これらのクラスのいずれかを継承する場合、生成されるクラスは、シングルトンになるように定義された引数でクラスが構築されるたびに返される、eagerlyに作成されたシングルトンインスタンスを持つことになります。 通常、これがデフォルトとなる。 これらのインスタンスは不変です。 TypeError.
のサブクラスは*すべて *Instruction には mutable プロパティを持ちます。 ほとんどのインストラクションの場合、これは True であり、シングルトン・インスタンスの場合は False である。 メソッドを使うことができる。 to_mutable() メソッドを使って、所有権があり、変異させても安全な命令のバージョンを取得することができる。
シングルトン・インスタンスはベース・クラスの正確なインスタンスではなく、新しいオブジェクトを構築できない特別なサブクラスである。 つまり、以下のようになります。
type(XGate()) is not XGate正確な値 type 代わりに isinstance() を使う。 からベース・クラスを確実に取得する必要がある場合は Instructionから基底クラスを確実に取得する必要がある場合は Instruction.base_class 属性を参照してください。シングルトンインスタンスはこれを正しく設定します。 Qiskitを使用するほとんどの場合 Instruction.name は、回路における命令の「意味」をより適切に決定します。
新しいシングルトンの導出
新しいシングルトン命令を派生させる最も単純な例は、単に正しいベースから継承し、引数に対して不変のデフォルトを持つ __init__() メソッドを提供することである。 例:
from qiskit.circuit.singleton import SingletonInstruction
class MyInstruction(SingletonInstruction):
def __init__(self, label=None):
super().__init__("my_instruction", 1, 0, label=label)
assert MyInstruction() is MyInstruction()
assert MyInstruction(label="some label") is not MyInstruction()
assert MyInstruction(label="some label").mutableシングルトンインスタンスは、コンストラクタのデフォルトをすべて使用する。
また、それ自体がシングルトンである命令から派生することもできる。 クラスのシングルトン性は継承されるが、2つのクラスのシングルトン・インスタンスは異なる:
class MyOtherInstruction(MyInstruction):
pass
assert MyOtherInstruction() is MyOtherInstruction()
assert MyOtherInstruction() is not MyInstruction()何らかの理由で SingletonInstructionから派生させたいが、新しい抽象基底クラスを定義する場合など、デフォルトのシングルトン・インスタンスを生成させたくない場合は、クラス定義でキーワード引数 create_default_singleton=False を設定することができる:
class NotASingleton(SingletonInstruction, create_default_singleton=False):
def __init__(self):
return super().__init__("my_mutable", 1, 0, [])
assert NotASingleton() is not NotASingleton()コンストラクタのすべての引数にデフォルトがない場合は、 create_default_singleton=False を設定する必要があります。
および SingletonInstruction その他の関連クラスのサブクラスは、コンストラクタの引数の解釈方法を制御することで、オプションの引数が明示的にデフォルト値に設定された場合でも、シングルトン機構がシングルトンを返せるようにすることができます。
_singleton_lookup_key
static SingletonInstruction._singleton_lookup_key(*_args, **_kwargs)
コンストラクタの引数が与えられた場合、取得するシングルトンインスタンスを特定するキータプルを返します。引数がミュータブルオブジェクトを作成しなければならないことを意味する場合は、 None 。
パフォーマンスのため、特別なケースとして、クラス・コンストラクタにゼロ引数が与えられた場合、このメソッドは呼び出されず(例えば、コンストラクション XGate() はこのメソッドを呼び出さないが、 XGate(label=None) は呼び出す)、デフォルトのシングルトンが即座に返される。
この静的メソッドはサブクラスでオーバーライドすることができる(そしておそらくそうすべきである)。 派生シグネチャは、そのクラスの __init__ と一致しなければならない。このメソッドは次に、引数を調べて、それがミュータビリティを必要とするかどうか、あるいは(もしあれば)キャッシュ・キーがどうあるべきかを判断しなければならない。
この関数は、 None または有効な dict キー(すなわち、ハッシュ可能で等式を実装している)のいずれかを返す必要があります。 None を返すということは、生成されたインスタンスはミュータブルでなければならないということだ。 それ以降のシングルトンベースの処理は行われず、クラスの作成はシングルトン処理がなかったかのように進行する。 そうでなければ、返されるキーはハッシュ可能なものであれば何でもよく、特別な意味はない。 このメソッドが同じキーを返すたびに、同じシングルトンインスタンスが返される。 シングルトン性を維持しつつ、設定可能なすべての引数の値のタプルを使用することをお勧めする。
デフォルトの引数や、クラス作成時に additional_singletons に与えられた引数にマッチするキーのみが、実際にシングルトンを返します。その他の値は、標準的なミュータブル・インスタンスを返します。
シングルトンマシナリーは、この関数からのハッシュ不可能なリターンを、ミュータブルなインスタンスを返すことで潔く処理する。 サブクラスは、そのキーがハッピーパスでハッシュ可能であることを保証しなければならないが、ユーザーが提供する引数がハッシュ可能であることを手動で検証する必要はない。 例えば、このように実装するのが無難だ:
@staticmethod
def _singleton_lookup_key(*args, **kwargs):
return None if kwargs else argsたとえユーザーが args。
これはすべてのQiskit標準ライブラリゲートによって設定され、 label および類似のキーワード引数がデフォルトの場合はキー計算で無視され、そうでない場合はミュータブルインスタンスが返されます。
クラス定義の additional_singletons 引数を使えば、シングルトン・インスタンスを生成するコンストラクタ引数の他の組み合わせを指定することもできる。 これは、 (args, kwargs) タプルのイテラブルを受け取り、 cls(*args, **kwargs) と同等のシングルトンを構築する。 この場合、デフォルトの引数のケースを処理する必要はない。 例えば、クラスの定義があるとする:
class MySingleton(SingletonGate, additional_singletons=[((2,), {"label": "two"})]):
def __init__(self, n=1, label=None):
super().__init__("my", n, [], label=label)
@staticmethod
def _singleton_lookup_key(n=1, label=None):
return (n, label)の2つのシングルトンインスタンスがインスタンス化される。 一つは n=1 と label=None に対応し、もう一つは n=2 と label="two" に対応する。これら2つのケースのどちらかに一致する引数で MySingleton。 例:
assert MySingleton() is MySingleton(1, label=None)
assert MySingleton(2, "two") is MySingleton(n=2, label="two")引数がゼロのクラスがインスタンス化された場合は、特別に処理され、内部ループのパフォーマンスを絶対的に高速にすることができる(ただし、一般的な機械はいずれにせよ絶望的に遅いわけではない)。
実装
このセクションは、主に開発者向けのコード説明である。ここで説明されている機械はどれも公開されておらず、そのいずれかを直接継承することは安全ではない。
ここで取り組まなければならないことがいくつかある。 持つという行動 XGate() (不正確な)インスタンスであるシングルトンオブジェクトを返す XGate しかし電話*せずに *__init__ 上書きする必要がある type.__call__。 つまり XGate はシングルトンインスタンスを返す __call__ 。
次に、 XGate() が返すシングルトンインスタンスがあることを確認する必要がある。 これは呼び出しのたびに動的に行うこともできるが(つまり、インスタンスが存在するかどうかをチェックし、存在しない場合はインスタンスを作成する)、インスタンスを非常に特別なものにしたいので、 XGate 型オブジェクトの定義中にフックして作成する方が簡単である。 これはまた、シングルトン・オブジェクトをピックル可能にする必要がないという利点もある。ベース・タイプ・オブジェクトの生成によってシングルトンが再作成されるため、ピックル解除時にそれをどこから取り出すかを指定するだけでよい。
シングルトン・インスタンスにさせたい:
- 自分自身を変異させようとする試みはすべて拒否しなければならない。
- は、シングルトンを扱わない場合の
XGate()とまったく同じ状態になる。
これを3つのステップで行う:
- シングルトンを作成する前に、別途オーバーライドを定義します。
InstructionとGateを不変にするために必要なオーバーライドを別途定義する。 これは_SingletonInstructionOverrides、その他の_*Overrides。 XGate、 そのサブクラスを動的に作成する。このサブクラスは、メソッド解決順序の不変オーバーライドを適切な場所に配置する。 これらは、ミュータブルゲートで定義されている標準的なメソッドやプロパティをオーバーライドします(作成する型オブジェクトに余分なインプレースメソッドがある場合は、オーバーライドしようとしません)。- この新しいサブクラスをインスタンス化することはできない。というのも、このサブクラスが
XGate.__init__。 その代わりに、まず完全に通常のXGateインスタンスを作成し、その型を動的にシングルトン・クラスに変更して凍結させる。
これを完全にメタクラスの仕組みの中で行うこともできるが、その場合は XGate :
class XGate(Gate, metaclass=_SingletonMeta, overrides=_SingletonGateOverrides): ..._SingletonMeta 、もろもろの内省をさせなければならない)。 代わりに abc.ABC/abc.ABCMeta パターンを使って具体的な中間層(SingletonGate を定義する XGate の場合) を定義する / パターンを使用します。 __init_subclass__() を持ち、上記のシングルトン・サブクラスの作成手順を適用します。 オーバーライドは別のクラスにあるので、 ミュータブル・インスタンスは独自のメソッド解決順序を持たない。 XGate これは実装が簡単ですが、インスタンスの変更が許可されているかどうかを検証するために、すべてのセッターとチェッカーが実行時に動き回る必要があります。
最後に、このすべての機械を実際に構築するために、ベースとなるメタクラスは _SingletonMeta です。 Instruction. これは __call__() これは type.__call__ をオーバーライドしてシングルトンインスタンスを返す機構を定義します。 もうひとつの構成要素は __new__()の作成時に(自明でない限り)呼び出される。 SingletonGate そして SingletonInstruction の生成時に(自明ではありませんが)呼び出されます。 overrides キーワード引数が設定され、上記のプロパティを持つクラスの __init_subclass__ を定義します。 メタクラスを使ってこのメソッドを動的に追加する。 __init_subclass__()overrides というのも、機械は抽象的でありたいからである。 super. これを動的に行うには、目的のクラス変数の上で閉じ、2引数形式の super引数ゼロの形式は、その関数を含む関数がどこで定義されたかに基づいてマジック・イントロスペクションを行うからです。
複数のシングルトンを扱うには、初期化引数を何らかの形で保存し、メソッドとピックリングを定義できるようにする必要がある。 to_mutable() メソッドと pickling を定義できるようにするためです。 これはシングルトン・ タイプ・オブジェクトのルックアップ辞書として行う。 これは、論理的にはインスタンス属性ですが、動的な˶_singleton型をベース型のインスタンスに動的に切り替える必要があるため、かなり複雑になります。ベースがすでにインスタンス辞書を持っていることを要求するか、切り替え中に __slots__ レイアウトが壊れる危険性があります。 シングルトンは、ベース・クラスのタイプ・オブジェクトのガベージ・コレクションまで存続するので、インスタンス・ポインターを格納したいデータにマッピングするタイプ・オブジェクト辞書を使って、このインスタンス辞書をフェイクアウトすることができる。 別の方法としては、イニシャライザーの引数をクローズする(あるいは格納する)個々のシングルトンごとに新しいタイプ・オブジェクトを作ることもできるが、タイプ・オブジェクトはかなり重く、原理はほとんど同じである。