!pip install qiskit

!pip install pennylane


import pennylane as qml
from pennylane import numpy as np

#Create a basic default Quantum circuit

#First , create a device to use the qubits 
def create_device():
  return qml.device("default.qubit",wires=1)
dev=create_device()

#Create an instance of Qnode() class which takes as parameters: the device name  
@qml.qnode(dev)
def create_circuit(inputs):
  qml.RX(inputs[0],wires=0)
  qml.RY(inputs[1],wires=0)
  #qml.CNOT(wires=[0,1])
  return qml.expval(qml.PauliZ(0))#,qml.expval(qml.PauliZ(1))

d_circuit=qml.grad(create_circuit,argnum=0)

#Create a cost function to optimize
def cost_function(x):
  return create_circuit(x)

#Creating an optimizer for gradient descent
def optimize(inputs):
  grad_list=[]
  opt=qml.AdagradOptimizer(stepsize=0.6,eps=1e-8)
  steps=100

  for i in range(steps):
    inputs=opt.step(cost_function,inputs)
    if (i + 1) % 5 == 0:
        print("Cost after step {:5d}: {: .7f}".format(i + 1, cost_function(inputs)))
        grad_list.append(cost_function(inputs))

  print("Optimized rotation angles: {}".format(inputs))
  return inputs,grad_list


inp=[0.011,0.012]
print("Cost Function values")
print(create_circuit(inp))
print(cost_function(inp))
print("Computing Adagrad Gradients")
inputs = np.array([0.011, 0.012])
angles,point=optimize(inputs)
print("Finalized gradients")
print(point[-1])


from qiskit.visualization import plot_bloch_vector
%matplotlib inline
rot_x=[0,0,point[-1]]
plot_bloch_vector(rot_x, title="Bloch Sphere")

dev = qml.device('default.qubit.tf', wires=["a","b"])

@qml.qnode(dev)
def dual_circuit(a):
    qml.Hadamard("a")
    qml.RX(a[0], wires=["a"])
    qml.RY(a[1],wires=["b"])
    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

def cost_fun(x):
  return dual_circuit(x)

def plotter(circuit):
  return qml.draw(circuit)
print("Input states to the Circuit")
inputs=[0.011,0.012]
print("Results after convergence")
results=optimize(inputs)
print("Drawing the circuit")
drawer=plotter(dual_circuit)
print(drawer(inputs))


