Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RubyKaigiに参加したら何かやりたくなった

 RubyKaigiに参加したら何かやりたくなった

2025/5/10 三浦半島.rb #2
LT

Avatar for ito-koichi

ito-koichi

May 11, 2025
Tweet

More Decks by ito-koichi

Other Decks in Programming

Transcript

  1. やってみよう • 結合文字列を文字の重ね合わせとして量子ビットで表現する (2文字固定) ◦ コードポイントは16進4桁(16bit=2byte)とし、16量子ビットを使う ◦ コードポイントをそのまま基底エンコードする • 測定して確率が高いものから順に

    Unicodeで出力する (2文字固定) |Å> = α|A> + β| ̊ > (文字の重ね合わせで表現) = α|U+0041> + β|U+030A> (コードポイントを基底エンコード) =√(3/5)|U+0041> + √(2/5)|U+030A> (Aの測定確率を高くする) 測定するとU+0041の方が高確率なので、U+0041、U+030Aの順に表示 → Å
  2. うーん、 • 重ね合わせ状態をどうやって作る? ◦ A(U+0041) = 0000 0000 0100 0001

    ◦ ̊ (U+030A) = 0000 0011 0000 1010 作りたい状態は √(3/5)|0000 0000 0100 0001> + √(2/5)|0000 0011 0000 1010> この状態を簡単に作る方法がわからなかった。。。
  3. コード from qiskit import QuantumCircuit,QuantumRegister, ClassicalRegister from qiskit_aer.primitives import SamplerV2

    # コードポイント 2個を量子回路としてエンコードする def encodeToCircuit(qc, codepoints): qc.h(qr_addr) # アドレスビットを均等重ね合わせにする for addr, code in enumerate(codepoints): if addr == 0: qc.x(qr_addr) # アドレスに対応する制御ビットを作る code_bin = format(code, '016b') # コードポイントを 2進数に変換して下位から上位に進める for i, value in enumerate(list(reversed(code_bin))): if value == '1': qc.cx(qr_addr, qr_code[i]) # 2進数が1のとき量子ビットを 1にする if addr == 0: qc.x(qr_addr) # 制御ビットを戻す qc.measure_all() # 測定をセットする # 量子回路を測定し、測定結果ビットと回数の辞書を返す def measureCircuit(qc): sampler = SamplerV2() job = sampler.run([qc], shots=100) result = job.result() counts = result[0].data.meas.get_counts() return counts # 測定結果ビットを Unicodeにデコードする def decodeToUnicode(counts): result = "" for i in range(2): addr = str(i) for data in counts.keys(): if data[-1:] == addr: result += chr(int(data[0:16], 2)) return result 言語はPython。 Qiskit SDKを使用。
  4. 実行 一応できた。 qr_addr = QuantumRegister(1, 'address') qr_code = QuantumRegister(16, 'code')

    qc = QuantumCircuit(qr_addr, qr_code) # 2つのUnicodeコードポイントを量子回路にエンコード codepoints = [0x0041, 0x030A] print(codepoints) # => [65, 778] encodeToCircuit(qc, codepoints) # qc.draw('mpl', scale=0.5) # 量子回路を測定 counts = measureCircuit(qc) print(counts) # => {'00000000010000010': 45, '00000011000010101': 55} # 測定結果をユニコード文字列にデコード unicode = decodeToUnicode(counts) print(unicode) # => Å
  5. できた? • 一応QRAMをシミュレーションできた • 今回はノイズなしシミュレーションで、本物はこんなにきれいにならない • Unicodeのコードポイント2個にしてはリソースの使用量が多すぎ ◦ 古典:ビット数:コードポイント 16

    x 2文字 = 32ビット    サイズ:32bit ◦ 量子:ビット数:コードポイント 16 + アドレス 1 = 17量子ビット    シミュレーションサイズ:基底 2^17 x 振幅 16byte = 2MB ▪ 量子ビットは基底の線形結合で表せる。結合の重み(振幅)は複素数。 ▪ 複素数は「a+ib, aとbは実数」で各実数が Double(64bit)だと、振幅は128bit(=16byte) • 構成も複雑になる
  6. 量子の場合 ストレージ 量子回路の プログラム メモリ 量子回路の プログラム ディスプレイ Unicode 文字

    量子コンピュータ 量子回路の 実行結果 コードポイント のデータ 量子回路 を実行 ※今回はPCでシミュレート
  7. ちょっと修正 from qiskit import QuantumCircuit,QuantumRegister, ClassicalRegister from qiskit_aer.primitives import SamplerV2

    # コードポイントを量子回路としてエンコードする def encodeToCircuit(qc, codepoints): qc.h(qr_addr) # アドレスビットを均等重ね合わせにする addr_size = qr_addr.size code_size = qr_code.size for addr, code in enumerate(codepoints): addr_bit_list = [int(i) for i in list(reversed(format(addr, f'0{addr_size}b')))] qc.barrier() # アドレスに対応する制御ビットを作る for i in range(addr_size): if addr_bit_list[i] == 0: qc.x(i) # コードポイントを 2進数に変換して下位から上位に進めながら、アドレスに対応する ビットを1にする code_bit_list = [int(i) for i in list(reversed(format(code, f'0{code_size}b')))] for i in range(code_size): if code_bit_list[i] == 1: qc.mcx(list(range(addr_size)), addr_size + i) # 制御ビットを戻す for i in range(addr_size): if addr_bit_list[i] == 0: qc.x(i) qc.measure_all() # 測定をセットする # 量子回路を測定し、測定結果ビットと回数の辞書を返す def measureCircuit(qc): sampler = SamplerV2() job = sampler.run([qc], shots=1000) result = job.result() counts = result[0].data.meas.get_counts() return counts # 測定結果ビットを Unicodeにデコードする def decodeToUnicode(codes_len, code_size, addr_size, counts): data_dict = {} for data in counts.keys(): data_dict[int(data[-1 * addr_size:], 2)] = chr(int(data[0:code_size], 2)) result = "" for i in range(codes_len): result += data_dict[i] return result
  8. コードポイントを量子状態にエンコードする量子回路を作る [U+1F468, U+0200D, U+1F469, U+0200D, U+1F467, U+0200D, U+1F466] 回路を実行すると量子状態ができる √(1/8)|U+1F468>|0>

    + √(1/8)|U+0200D>|1> + √(1/8)|U+1F469>|2> + √(1/8)|U+0200D>|3> + √(1/8)|U+1F467>|4> + √(1/8)|U+0200D>|5> + √(1/8)|U+1F466>|6> + √(1/8)|U+00000>|7> 回路を測定すると確率的にビット列(コード +アドレス)が取得できる (右端は出現回数 ) {'U+00000 7': 141, 'U+1F466 6': 114, 'U+0200D 5': 124, 'U+1F469 2': 121, 'U+1F467 4': 130, U+0200D 3': 122, 'U+0200D 1': 115, 'U+1F468 0': 133} 文字数ぶん、アドレスの順に Unicodeで出力する U+1F468, U+0200D, U+1F469, U+0200D, U+1F467, U+0200D, U+1F466 # => 󰔡 古典:ビット数:コードポイント 20 x 7文字 = 140ビット    サイズ:140bit 量子:ビット数:コードポイント 20 + アドレス 3 = 23量子ビット    シミュレーションサイズ:基底 2^23 x 振幅 16byte = 134MB 家族の絵文字 qr_addr = QuantumRegister(3, 'address') qr_code = QuantumRegister(20, 'code') qc = QuantumCircuit(qr_addr, qr_code) # Unicodeコードポイントの配列を量子回路にエンコード codepoints = [0x1F468, 0x200D, 0x1F469, 0x200D, 0x1F467, 0x200D, 0x1F466] print([format(code, 'X') for code in codepoints]) # => ['1F468', '200D', '1F469', '200D', '1F467', '200D', '1F466'] encodeToCircuit(qc, codepoints) # qc.draw('mpl', scale=0.2) # 量子回路を測定 counts = measureCircuit(qc) print(counts) # => {'00000000000000000000111': 141, '00011111010001100110110': 114, '00000010000000001101101': 124, '00011111010001101001010': 121, '00011111010001100111100': 130, '00000010000000001101011': 122, '00000010000000001101001': 115, '00011111010001101000000': 133} # 測定結果をユニコード文字列にデコード unicode = decodeToUnicode(len(codepoints), qr_code.size, qr_addr.size, counts) print(unicode) # => 󰔡