# required imports:
from qiskit.visualization import array_to_latex
from qiskit.quantum_info import Statevector, random_statevector
from qiskit.quantum_info.operators import Operator, Pauli
from qiskit import QuantumCircuit
from qiskit.circuit.library import HGate, CXGate
import numpy as np

ket0 = [[1],[0]]

array_to_latex(ket0)

bra0 = [1,0]
array_to_latex(bra0)

ket1 = # put your answer answer here for |1⟩
bra1 = # put answer here for ⟨1|

from qc_grader.challenges.qgss_2023 import grade_lab1_ex1 

grade_lab1_ex1([ket1, bra1])

sv_bra0 = Statevector(bra0)

sv_bra0

sv_bra0.draw('latex')

sv_eq = Statevector([1/2, 3/4, 4/5, 6/8])

sv_eq.draw('latex')

sv_eq.is_valid()

sv_valid = # create your statevector here

from qc_grader.challenges.qgss_2023 import grade_lab1_ex2 

grade_lab1_ex2(sv_valid)

op_bra0 = Operator(bra0)

op_bra0

op_ket0 = Operator(ket0)
op_bra0.tensor(op_ket0)

braket = np.dot(op_bra0,op_ket0)
array_to_latex(braket)

ketbra = np.outer(ket0,bra0)
array_to_latex(ketbra)

braket = np.dot(op_bra0,op_ket0)
array_to_latex(braket)

bra1ket0 = # put your answer for ⟨1|0⟩ here

bra0ket1 = # put your answer for ⟨0|1⟩ here

bra1ket1 = # put your answer for ⟨1|1⟩ here

ket1bra0 = # put your answer for |1⟩⟨0| here

ket0bra1 = # put your answer for |0⟩⟨1| here

ket1bra1 = # put your answer for |1⟩⟨1| here

from qc_grader.challenges.qgss_2023 import grade_lab1_ex3 

grade_lab1_ex3([bra1ket0, bra0ket1, bra1ket1, ket1bra0, ket0bra1, ket1bra1])

# add or remove your answer from this list
answer = ['a', 'b', 'c']

from qc_grader.challenges.qgss_2023 import grade_lab1_ex4 

grade_lab1_ex4(answer)

m1 = Operator([[1,1],[0,0]])
array_to_latex(m1)

m3 = Operator([[0,1],[1,0]])
array_to_latex(m3)

array_to_latex(m1@ket0)

m2 = # create an operator for m2 here
m4 = # create and operator for m4 here

from qc_grader.challenges.qgss_2023 import grade_lab1_ex5

grade_lab1_ex5([m2, m4])

cnot = CXGate()

array_to_latex(cnot)

m3.is_unitary()

random = Operator(np.array([[ 0.50778085-0.44607116j, -0.1523741 +0.14128434j,  0.44607116+0.50778085j,
  -0.14128434-0.1523741j ],
 [ 0.16855994+0.12151822j,  0.55868196+0.38038841j, -0.12151822+0.16855994j,
  -0.38038841+0.55868196j],
 [ 0.50778085-0.44607116j, -0.1523741 +0.14128434j, -0.44607116-0.50778085j,
   0.14128434+0.1523741j ],
 [ 0.16855994+0.12151822j,  0.55868196+0.38038841j,  0.12151822-0.16855994j,
   0.38038841-0.55868196j]]))

random.is_unitary()

non_unitary_op = # create your operator here

from qc_grader.challenges.qgss_2023 import grade_lab1_ex6

grade_lab1_ex6(non_unitary_op)

pauli_x = Pauli('X')

array_to_latex(pauli_x)

pauli_y = Pauli('Y')

array_to_latex(pauli_y)

pauli_z = Pauli('Z')

array_to_latex(pauli_z)

op_x = Operator(pauli_x)

op_x

op_new = np.dot(op_x,ket0)

array_to_latex(op_new)

result = # do your operations here

from qc_grader.challenges.qgss_2023 import grade_lab1_ex7

grade_lab1_ex7(result)

hadamard = HGate()

array_to_latex(hadamard)

hop = Operator(hadamard)
hop.is_unitary()

bell = QuantumCircuit(2)

bell.h(0) # apply an H gate to the circuit
bell.cx(0,1) # apply a CNOT gate to the circuit

bell.draw(output="mpl")

bell_op = Operator(bell)

array_to_latex(bell_op)

ghz = QuantumCircuit(3)

##############################
# add gates to your circuit here



##############################

ghz.draw(output='mpl')

from qc_grader.challenges.qgss_2023 import grade_lab1_ex8

grade_lab1_ex8(ghz)

plus_state = Statevector.from_label("+")

plus_state.draw('latex')

plus_state

plus_state.probabilities_dict()

# run this cell multiple times to show collapsing into one state or the other
res = plus_state.measure()

res

qc = QuantumCircuit(1,1)
qc.h(0)
qc.measure(0, 0)

qc.draw(output="mpl")

sv_bell = Statevector([np.sqrt(1/2), 0, 0, np.sqrt(1/2)])

sv_bell.draw('latex')

sv_bell.probabilities_dict()

sv_psi_plus = # create a statevector for |𝜓+⟩ here
prob_psi_plus = # find the measurement probabilities for |𝜓+⟩ here

sv_psi_minus = # create a statevector for |𝜓−⟩ here
prob_psi_minus = # find the measurement probabilities for |𝜓−⟩ here

sv_phi_minus = # create a statevector for |𝜙−⟩ here
prob_phi_minus = # find the measurement probabilities for |𝜙−⟩ here

from qc_grader.challenges.qgss_2023 import grade_lab1_ex9

grade_lab1_ex9([prob_psi_plus, prob_psi_minus, prob_phi_minus])

qft = QuantumCircuit(2)

##############################
# add gates to your circuit here



##############################

qft.draw(output='mpl')

from qc_grader.challenges.qgss_2023 import grade_lab1_ex10

grade_lab1_ex10(qft)

U = Operator(qft)

array_to_latex(U)