Bengali
Languages
English
Bengali
French
German
Japanese
Korean
Portuguese
Spanish
Tamil
  • Qiskit documentation >
  • Tutorials >
  • ধাপে ধাপে কোয়ান্টাম দশা অনুমানকারী অ্যালগরিদম

নোট

এই পৃষ্ঠাটি tutorials/algorithms/08_factorizers.ipynb থেকে নেয়া হয়েছে।

ধাপে ধাপে কোয়ান্টাম দশা অনুমানকারী অ্যালগরিদম

এই টিউটোরিয়ালগুলোর লক্ষ্য হলো কিভাবে ইটারেটিভ ফেজ এস্টিমেশন (আইপিই) অ্যালোগরিদম কাজ করে, কোয়ান্টাম ফেজ এস্টিমেশন (কিউপিই) এর বদলে কেন আমরা আইপিই ব্যবহার করব এবং Qiskit এর সাহায্যে একই (সার্কিটে পুনঃস্থাপন (রিসেট) যুক্তিবর্তনী (গেইট) এবং c_if পদ্ধতির সাহায্যে ক্লাসিক্যাল রেজিস্টারে থাকা আগের পরিমাপের মান শর্ত হিসেবে নিয়ে গেট প্রয়োগ করা যায়) কাজে লাগিয়ে কিভাবে আইপিই নির্মাণ (বিল্ড) করা যায়।

তথ্যসূত্র (রেফারেন্স)

[1]:
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister, execute, assemble, Aer
from qiskit.tools.visualization import plot_histogram
from math import pi
import matplotlib.pyplot as plt

Conditioned gates: the c_if method

আইপিই ধারাক্রম (অ্যালোগরিদম) বোঝার আগে আমাদের Qiskit -এর শর্তসাপেক্ষ পদ্ধতি c_if এর ব্যাপারে জানতে হবে, কারণ আইপিই বর্তনী বানাতে এটা কাজে লাগবে।

c_if হল gate ক্লাসের একটা পদ্ধতি যা পূর্বে প্রথাগত (ক্লাসিক্যাল) রেজিস্টারে সঞ্চিত মানের উপর নির্ভর করে শর্তাধীন ক্রিয়াকলাপ (অপারেশন) করে। এর সাহায্যে একই বর্তনীতে একবার পরিমাপের পর তার ফলাফল বিচার করে আরো গেট যোগ করতে পারি।

নিচের উদাহরণের কোডে \(X\) যুক্তিবর্তনী (গেইট) চালাবে যদি প্রথাগত (ক্লাসিক্যাল) রেজিস্টারের মান \(0\) হয়।

[2]:
q = QuantumRegister(1,'q')
c = ClassicalRegister(1,'c')
qc = QuantumCircuit(q, c)
qc.h(0)
qc.measure(0,0)
qc.x(0).c_if(c, 0)
qc.draw(output='mpl')
[2]:
../../_images/tutorials_textbook_01_IQPE_4_0.png

উল্লেখ্য: c_if পদ্ধতি প্রথম আর্গুমেন্ট হিসেবে সম্পূর্ণ প্রথাগত (ক্লাসিক্যাল) রেজিস্টার নেয়, একটা প্রথাগত (ক্লাসিক্যাল) বিট বা বিটের তালিকা নয় এবং দ্বিতীয় আর্গুমেন্ট হিসেবে একটা ধনাত্মক অখণ্ড দশমিক সংখ্যা নয়, কোনো একটা বিট (০ বা ১) বা বিটের তালিকা নয়।

Let’s make another example. Consider that we want to perform a bit flip on the third qubit after the measurements in the following circuit, when the results of the measurement of \(q_0\) and \(q_1\) are both \(1\).

[3]:
q = QuantumRegister(3,'q')
c = ClassicalRegister(3,'c')
qc = QuantumCircuit(q, c)
qc.h(q[0])
qc.h(q[1])
qc.h(q[2])
qc.barrier()
qc.measure(q,c)
qc.draw('mpl')
[3]:
../../_images/tutorials_textbook_01_IQPE_6_0.png

We want to apply the \(X\) gate, only if both the results of the measurement of \(q_0\) and \(q_1\) are \(1\). We can do this using the c_if method, conditioning the application of \(X\) depending on the value passed as argument to c_if.

We will have to encode the value to pass to the c_if method such that it will check the values 011 and 111 (in binary representation), since it does not matter what \(q_2\) is measured as.

এই ২টি পূর্ণসংখ্যা দশমিক সংখ্যা রূপে:

caf810206997478bbc1489bd3d26b1f2

সমাধান দেখার জন্য আমরা পাইথনের bin() পদ্ধতি কাজে লাগাতে পারি (0b উপসর্গ বোঝায় যে ফলটা বাইনারি)।

[4]:
print(bin(3))
print(bin(7))
0b11
0b111

সেজন্য আমরা দুবার c_if ব্যবহার করে \(q_2\) এর উপর \(X\) প্রয়োগ করবো, 011 এবং 111 প্রত্যেক মানের জন্য একবার করে।

[5]:
q = QuantumRegister(3,'q')
c = ClassicalRegister(3,'c')
qc = QuantumCircuit(q, c)
qc.h(0)
qc.h(1)
qc.h(2)
qc.barrier()
qc.measure(q,c)

qc.x(2).c_if(c, 3) # for the 011 case
qc.x(2).c_if(c, 7) # for the 111 case

qc.draw(output='mpl')
[5]:
../../_images/tutorials_textbook_01_IQPE_12_0.png

আইপিই

The motivation for using the IPE algorithm is that QPE algorithm works fine for short depth circuits but when the circuit starts to grow, it doesn’t work properly due to gate noise and decoherence times.

ধারাক্রম (অ্যালগরিদম) কিভাবে কাজ করে বিস্তারিত জানতে ইটারেটিভ ফেজ এস্টিমেশন (আইপিই) ধারাক্রম (অ্যালগরিদম) দেখো। কিউপিই ব্যাপারে জানতে অধ্যায় ৩.৬ কোয়ান্টাম ফেজ এস্টিমেশন দেখো।

\(U\) -এর জন্য ১-কিউবিট গেইট সম্পন্ন আইপিই এর উদাহরণ

আমরা আইপিই অ্যালগরিদম প্রয়োগ করে ১-কিউবিট অপারেটরের \(U\) দশা অনুমান করব। উদাহরণরূপে এখানে আমরা \(S\) -গেট ব্যবহার করব।

Let’s apply the IPE algorithm to estimate the phase for \(S\)-gate. Its matrix is

\[\begin{split} S = \begin{bmatrix} 1 & 0\\ 0 & e^\frac{i\pi}{2}\\ \end{bmatrix}\end{split}\]

অর্থাৎ \(|0\rangle অবস্থার দশা অপরিবর্তিত রেখে :math:\)- গেট, \(|1\rangle\) অবস্থায় \(\pi/2\) দশা যোগ করা হল।

\[S|1\rangle = e^\frac{i\pi}{2}|1\rangle\]

নিচে আমরা Section 2 of lab 4 <https://qiskit.org/textbook/ch-labs/Lab04_IterativePhaseEstimation.html#2-iterative-phase-estimation-ipe-algorithm> __ এর নামকরণ ও পদ ব্যবহার করব।

Let’s consider to estimate the phase \(\phi=\frac{\pi}{2}\) for the eigenstate \(|1\rangle\), we should find \(\varphi=\frac{1}{4}\) (where \(\phi = 2 \pi \varphi\)). Therefore to estimate the phase we need exactly 2 phase bits, i.e. \(m=2\), since \(1/2^2=1/4\). So \(\varphi=0.\varphi_1\varphi_2\).

আইপিই অ্যালগরিদম এর থেকে মনে থাকবে, \(m\) হলো পুনরাবৃত্তির সংখ্যা, অর্থাৎ আমাদের \(2\) বার পুনরাবৃত্তি করতে হবে।

প্রথমে আমরা সার্কিট চালু করব। আইপিই কেবল একটা সহায়ক কিউবিট নিয়ে কাজ করে, যেখানে কিউপিই অ্যালগরিদম \(m\) গুলো গণনাকারী কিউবিট ব্যবহার করে। সেজন্য আমাদের ২টি কিউবিট, ১ টা সহায়ক কিউবিট, \(U\) -গেটের আইজেনস্টেটের জন্য ১ টা কিউবিট এবং ২ বিটের একটা ক্লাসিক্যাল রেজিস্টার (দশা বিট \(\varphi_1\), \(\varphi_2\) -এর জন্য) লাগবে।

[6]:
nq = 2
m = 2
q = QuantumRegister(nq,'q')
c = ClassicalRegister(m,'c')

qc_S = QuantumCircuit(q,c)

প্রথম ধাপ

Now we build the quantum circuit for the first step, that is, the first iteration of the algorithm, to estimate the least significant phase bit \(\varphi_m\), in this case \(\varphi_2\). For the first step we have 3 sub-steps: - initialization - application of the Controlled-\(U\) gates - measure of the auxiliary qubit in x-basis

আরম্ভ

আরম্ভের জন্য আমরা আইজেনস্টেট \(|1\rangle\) -এর প্রস্তুতি ও সহায়ক কিউবিটে হ্যাডামার্ড যুক্তিবর্তনী প্রয়োগ করতে পারি ।

[7]:
qc_S.h(0)
qc_S.x(1)
qc_S.draw('mpl')
[7]:
../../_images/tutorials_textbook_01_IQPE_16_0.png

Application of the Controlled-\(U\) gates

Then we have to apply \(2^t\) times the Controlled-\(U\) operators (see also in the docs Two qubit gates), that, in this example, is the Controlled-\(S\) gate (\(CS\) for short).

সার্কিট \(CS\) বাস্তবায়নের জন্য আমরা \(\theta=\pi/2\) -এর সাথে নিয়ন্ত্রিত দশা গেইট \(\text{CP}(\theta)\) ব্যবহার করতে পারি, যেহেতু \(S\) একটা দশা গেট।

[8]:
cu_circ = QuantumCircuit(2)
cu_circ.cp(pi/2,0,1)
cu_circ.draw('mpl')
[8]:
../../_images/tutorials_textbook_01_IQPE_18_0.png

Let’s apply \(2^t\) times \(\text{CP}(\pi/2)\). Since for the first step \(t=m-1\), and \(m=2\), we have \(2^t=2\).

[9]:
for _ in range(2**(m-1)):
    qc_S.cp(pi/2,0,1)
qc_S.draw('mpl')
[9]:
../../_images/tutorials_textbook_01_IQPE_20_0.png

x -ভিত্তিতে পরিমাপ

অবশেষে আমরা সহায়ক কিউবিট - এর ওপর এক্স বেসিসে পরিমাপ করি। তাই এক্স পরিমাপ করার জন্য আমরা একটি ফাংশান গঠন করব এবং তারপর সেটি প্রয়োগ করব।

[10]:
def x_measurement(qc, qubit, cbit):
    """Measure 'qubit' in the X-basis, and store the result in 'cbit'"""
    qc.h(qubit)
    qc.measure(qubit, cbit)

এভাবে আমরা দশা বিট \(\varphi_2\) পাই এবং সেটা ক্লাসিক্যাল বিট \(c_0\) -এ সঞ্চয় করি।

[11]:
x_measurement(qc_S, q[0], c[0])
qc_S.draw('mpl')
[11]:
../../_images/tutorials_textbook_01_IQPE_24_0.png

পরবর্তী ধাপসমূহ (২য় ধাপ)

Now we build the quantum circuit for the other remaining steps, in this example, only the second one. In these steps we have 4 sub-steps: the 3 sub-steps as in the first step and, in the middle, the additional step of the phase correction - initialization with reset - phase correction - application of the Controlled-\(U\) gates - measure of the auxiliary qubit in x-basis

রিসেট দিয়ে আরম্ভ

যেহেতু আমরা এই সার্কিটেই একটা ইটারেটিভ এলগোরিদম চালাবো, গেট পরিমাপের পর কিউবিট পুনর্ব্যবহারের জন্য সহায়ক কিউবিট \(q0\) আমাদের রিসেট করতে হবে।

[12]:
qc_S.reset(0)
qc_S.h(0)
qc_S.draw('mpl')
[12]:
../../_images/tutorials_textbook_01_IQPE_26_0.png

দ্বিতীয় ধাপের জন্য দশা সংশোধন

As seen in the theory, in order to extract the phase bit \(\varphi_{1}\), we perform a phase correction of \(-\pi\varphi_2/2\). Of course, we need to apply the phase correction in the circuit only if the phase bit \(\varphi_2=1\), i.e. we have to apply the phase correction of \(-\pi/2\) only if the classical bit \(c_0\) is 1.

সেজন্য রিসেটের পর c_if পদ্ধতি ব্যবহার করে ক্লাসিক্যাল বিট \(c_0\) (\(=\varphi_2\)) -এর শর্তাধীনে \(\theta=-\pi/2\) দশাসহ \(P(\theta)\) দশা গেট প্রয়োগ করব। এই টিউটোরিয়ালের শুরুতে দেখানো ১ মান নিয়ে c_if পদ্ধতি ব্যবহার করব, যেহেতু \(1_{10} = 001_{2}\) (সাবস্ক্রিপ্ট \(_{10}\) and \(_2\) দশমিক ও বাইনারি রূপ চিহ্নিত করে)।

[13]:
qc_S.p(-pi/2,0).c_if(c,1)
qc_S.draw('mpl')
[13]:
../../_images/tutorials_textbook_01_IQPE_28_0.png

Application of the Controlled-\(U\) gates and x-measurement (for step 2)

We apply the \(CU\) operations as we did in the first step. For the second step we have \(t=m-2\), hence \(2^t=1\). So we apply \(\text{CP}(\pi/2)\) once. And then we perform the x-measurement of the qubit \(q_0\), storing the result, the phase bit \(\varphi_1\), in the bit \(c_1\) of classical register.

[14]:
## 2^t c-U operations (with t=m-2)
for _ in range(2**(m-2)):
    qc_S.cp(pi/2,0,1)

x_measurement(qc_S, q[0], c[1])

আমরা অন্তিম সার্কিট পেলাম

[15]:
qc_S.draw('mpl')
[15]:
../../_images/tutorials_textbook_01_IQPE_32_0.png

Let’s execute the circuit with the qasm_simulator, the simulator without noise that run locally.

[16]:
sim = Aer.get_backend('qasm_simulator')
count0 = execute(qc_S, sim).result().get_counts()

key_new = [str(int(key,2)/2**m) for key in list(count0.keys())]
count1 = dict(zip(key_new, count0.values()))

fig, ax = plt.subplots(1,2)
plot_histogram(count0, ax=ax[0])
plot_histogram(count1, ax=ax[1])
plt.tight_layout()

এই ছবিতে একই হিস্টোগ্রাম পেলেও লক্ষ্য করো বাঁ দিকে x-অক্ষে \(\varphi_1\), \(\varphi_2\) দশা বিটদুটো এবং ডানদিকে আসল দশা \(\varphi\) দশমিকরূপে আছে।

আশানুরূপভাবে আমরা \(100\%\) সম্ভাবনায় \(\varphi=\frac{1}{4}=0.25\) পেয়েছি।

২-কিউবিট গেইট সম্পন্ন আইপিই এর উদাহরণ

Now, we want to apply the IPE algorithm to estimate the phase for a 2-qubit gate \(U\). For this example, let’s consider the controlled version of the \(T\) gate, i.e. the gate \(U=\textrm{Controlled-}T\) (that from now we will express more compactly with \(CT\)). Its matrix is

\[\begin{split} CT = \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 0 & 0 & e^\frac{i\pi}{4}\\ \end{bmatrix}\end{split}\]

অর্থাৎ \(CT\) গেট \(|11\rangle\) অবস্থায় \(\pi/4\) দশা যোগ করে। এই অবস্থায় অন্যান্য গণনার ভিত্তি অবস্থা \(|00\rangle\), \(|01\rangle\), \(|10\rangle\) -এর দশা অপরিবর্তিত থাকে।

Let’s consider to estimate the phase \(\phi=\pi/4\) for the eigenstate \(|11\rangle\), we should find \(\varphi=1/8\), since \(\phi = 2 \pi \varphi\). Therefore to estimate the phase we need exactly 3 classical bits, i.e. \(m=3\), since \(1/2^3=1/8\). So \(\varphi=0.\varphi_1\varphi_2\varphi_3\).

১-কিউবিট \(U\) অপারেটরের উদাহরণের মতো আমরা একই ধাপ অনুসরণ করব কিন্তু এবার আমাদের \(3\) গুলো ধাপ থাকবে কারণ \(m=3\)। এই ব্যাপারে বিস্তারিত জানতে ১-কিউবিট \(U\) গেটের উদাহরণ দেখুন।

প্রথমে আমরা ৩টি কিউবিট নিয়ে সার্কিট চালু করবো, ১টা সহায়ক কিউবিট, ২-কিউবিট গেটের জন্য ২টো। এছাড়াও আমরা ৩টি ক্লাসিক্যাল বিট নেবো যাতে \(\varphi_1\), \(\varphi_2\), \(\varphi_3\) দশা বিটের মান সঞ্চয় হবে।

[17]:
nq = 3    # number of qubits
m = 3    # number of classical bits
q = QuantumRegister(nq,'q')
c = ClassicalRegister(m,'c')

qc = QuantumCircuit(q,c)

প্রথম ধাপ

এবার আমরা কম তাৎপর্যপূর্ণ দশা বিট \(\varphi_m=\varphi_3\) অনুমানের জন্য আমরা কোয়ান্টাম সার্কিট বানাবো।

আরম্ভ

We initialize the auxiliary qubit and the other qubits with the eigenstate \(|11\rangle\).

[18]:
qc.h(0)
qc.x([1,2])
qc.draw('mpl')
[18]:
../../_images/tutorials_textbook_01_IQPE_39_0.png

Application of the Controlled-\(U\) gates

Then we have to apply multiple times the \(CU\) operator, that, in this example, is the Controlled-\(CT\) gate (\(CCT\) for short).

বর্তনীতে (সার্কিট) \(CCT\) বাস্তবায়নের জন্য আমরা \(\theta=\pi/4\) -এর সাথে বহুদ্বারা নিয়ন্ত্রিত দশা গেট \(\text{MCP}(\theta)\) ব্যবহার করতে পারি, যেহেতু \(T\) একটা দশা গেট।

[19]:
cu_circ = QuantumCircuit(nq)
cu_circ.mcp(pi/4,[0,1],2)
cu_circ.draw('mpl')
[19]:
../../_images/tutorials_textbook_01_IQPE_41_0.png

Let’s apply \(2^t\) times \(\text{MCP}(\pi/4)\). Since for the first step \(t=m-1\) and \(m=3\), we have \(2^t=4\).

[20]:
for _ in range(2**(m-1)):
    qc.mcp(pi/4,[0,1],2)
qc.draw('mpl')
[20]:
../../_images/tutorials_textbook_01_IQPE_43_0.png

x -ভিত্তিতে পরিমাপ

Finally, we perform the measurement of the auxiliary qubit in x-basis. We can use the x_measurement function defined above in the example for 1-qubit gate. In this way we have obtained the phase bit \(\varphi_3\) and stored it in the classical bit \(c_0\).

[21]:
x_measurement(qc, q[0], c[0])
qc.draw('mpl')
[21]:
../../_images/tutorials_textbook_01_IQPE_45_0.png

ক্রমানুসারে (২য় ও ৩য় ধাপ)

এখন বাকি ধাপের (২য় ও ৩য়) জন্য কোয়ান্টাম সার্কিট বানাবো। প্রথম উদাহরণের মতো এখানেও দশা সংশোধনের অতিরিক্ত ধাপ আছে।

রিসেট দিয়ে আরম্ভ

[22]:
qc.reset(0)
qc.h(0)
qc.draw('mpl')
[22]:
../../_images/tutorials_textbook_01_IQPE_47_0.png

দ্বিতীয় ধাপের জন্য দশা সংশোধন

দশা বিট \(\varphi_{2}\) নিষ্কাশনের জন্য আমরা \(-\pi\varphi_3/2\) -এর ত্রুটি সংশোধন করব।

রিসেটের পর আমরা \(\theta=-\pi/2\) দশা সম্পন্ন দশা গেট \(P(\theta)\) প্রয়োগ করবো, শর্ত হিসেবে ক্লাসিক্যাল বিট \(c_0\) (\(=\varphi_3\))।

[23]:
qc.p(-pi/2,0).c_if(c,1)
qc.draw('mpl')
[23]:
../../_images/tutorials_textbook_01_IQPE_49_0.png

Application of the Controlled-\(U\) gates and x-measurement (for step 2)

We apply the \(CU\) operations as we did in the first step. For the second step we have \(t=m-2\), hence \(2^t=2\). So we apply \(\text{MCP}(\pi/4)\) \(2\) times. And then we perform the x-measurement of the qubit \(q_0\), storing the phase bit \(\varphi_2\) in the bit \(c_1\).

[24]:
for _ in range(2**(m-2)):
    qc.mcp(pi/4,[0,1],2)
x_measurement(qc, q[0], c[1])
qc.draw('mpl')
[24]:
../../_images/tutorials_textbook_01_IQPE_51_0.png

তৃতীয় ধাপের সব আংশিক ধাপ

৩য় এবং শেষ ধাপের জন্য আমরা ২য় ধাপের মতো করে সহায়ক কিউবিট রিসেট এবং আরম্ভ করব।

Then at the 3rd step we have to perform the phase correction of \(-2\pi 0.0\varphi_{2}\varphi_{3}= -2\pi \left(\frac{\varphi_2}{4}+\frac{\varphi_3}{8}\right)=-\frac{\varphi_2\pi}{2}-\frac{ \varphi_3\pi}{4}\), thus we have to apply 2 conditioned phase corrections, one conditioned by \(\varphi_3\) (\(=c_0\)) and the other by \(\varphi_2\)(\(=c_1\)). To do this we have to apply the following: - gate \(P(-\pi/4)\) conditioned by \(c_0=1\), that is, by \(c=001\) (c_if with value \(1\)) - gate \(P(-\pi/2)\) conditioned by \(c_1=1\), that is, the gate is applied when \(c=010\) (c_if with values \(2\)) - gate \(P(-3\pi/4)\) conditioned by \(c_1=1\) and \(c_0=1\) that is, the gate is applied when \(c=011\) (c_if with values \(3\))

এরপর, \(CU\) অপারেশনে: আমরা \(2^t\) বার \(\text{MCP}(\pi/4)\) গেট প্রয়োগ করব , যেহেতু ৩য় ধাপে \(t=m-3=0\), গেটটা আবারো একবার প্রয়োগ করতে পারবো।

[25]:
# initialization of qubit q0
qc.reset(0)
qc.h(0)

# phase correction
qc.p(-pi/4,0).c_if(c,1)

qc.p(-pi/2,0).c_if(c,2)
qc.p(-3*pi/4,0).c_if(c,3)

# c-U operations
for _ in range(2**(m-3)):
    qc.mcp(pi/4,[0,1],2)

# X measurement
qc.h(0)
qc.measure(0,2)

qc.draw('mpl')
[25]:
../../_images/tutorials_textbook_01_IQPE_53_0.png

এবার আমরা ত্রুটি ছাড়া সার্কিট সিমুলেটরে চালাবো।

[26]:
count0 = execute(qc, sim).result().get_counts()

key_new = [str(int(key,2)/2**m) for key in list(count0.keys())]
count1 = dict(zip(key_new, count0.values()))

fig, ax = plt.subplots(1,2)
plot_histogram(count0, ax=ax[0])
plot_histogram(count1, ax=ax[1])
fig.tight_layout()

আমরা অনুমানমতো \(\varphi=0.125\) (বা \(1/8\)) পাওয়ার সম্ভাবনা \(100\%\) পেয়েছি।

[27]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
/opt/miniconda3/envs/qiskit/lib/python3.9/site-packages/qiskit/aqua/operators/operator_globals.py:48: DeprecationWarning: `from_label` is deprecated and will be removed no earlier than 3 months after the release date. Use Pauli(label) instead.
  X = make_immutable(PrimitiveOp(Pauli.from_label('X')))

Version Information

Qiskit SoftwareVersion
Qiskit0.24.1
Terra0.17.3
Aer0.7.6
Ignis0.5.2
Aqua0.8.2
IBM Q Provider0.13.1
System information
Python3.9.5 (default, May 18 2021, 12:31:01) [Clang 10.0.0 ]
OSDarwin
CPUs4
Memory (Gb)16.0
Fri Jul 02 06:38:27 2021 EDT

This code is a part of Qiskit

© Copyright IBM 2017, 2021.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.