import numpy as np

import matplotlib.pyplot as plt



from qiskit import Aer, QuantumCircuit

from qiskit.circuit import Parameter

from qiskit.circuit.library import RealAmplitudes, ZZFeatureMap

from qiskit.opflow import StateFn, PauliSumOp, AerPauliExpectation, Gradient

from qiskit.utils import QuantumInstance

from qiskit.algorithms.optimizers import COBYLA

from qiskit_machine_learning.algorithms.classifiers import NeuralNetworkClassifier

expval = AerPauliExpectation()

gradient = Gradient()

qi_sv = QuantumInstance(Aer.get_backend('statevector_simulator'))

qi_qasm = QuantumInstance(Aer.get_backend('qasm_simulator'), shots=1000)

from qiskit_machine_learning.neural_networks import CircuitQNN

num_qubits = 3

qc = RealAmplitudes(num_qubits, entanglement='linear', reps=1)

qc.draw(output='mpl')

# specify circuit QNN

qnn = CircuitQNN(qc, [], qc.parameters, sparse=True, sampling=False, quantum_instance=qi_qasm)

# define (random) input and weights

input = np.random.rand(qnn.num_inputs)

weights = np.random.rand(qnn.num_weights)

# QNN forward pass

# sampling=True: sample

# sampling=False: probability

qnn.forward(input, weights).todense()  # returned as ab sparse matrix

meas = QuantumCircuit(num_qubits)

meas.measure_all()



qc.assign_parameters(weights, inplace=True)

qc_sampling = meas.compose(qc, front=True) # frontをTrueにしないと測定が先に来てしまう

qi_qasm.execute(qc_sampling).get_counts()

# QNN backward pass, returns a tuple of sparse matrices

# sampling=True: None

# sampling=False: probability gradient

result = qnn.backward(input, weights)

result[1].todense()

# specify circuit QNN

parity = lambda x: '{:b}'.format(x).count('1') % 2 # バイナリ表現で1の数/2

output_shape = 2  # this is required in case of a callable with dense output

qnn6 = CircuitQNN(qc, [], qc.parameters, sparse=False, interpret=parity, output_shape=output_shape,

                  quantum_instance=qi_qasm)

# define (random) input and weights

input6 = np.random.rand(qnn6.num_inputs)

weights6 = np.random.rand(qnn6.num_weights)

# QNN forward pass

qnn6.forward(input6, weights6)

# QNN backward pass

qnn6.backward(input6, weights6)









num_inputs = 2

num_samples = 20

X = 2*np.random.rand(num_samples, num_inputs) - 1 # num_sample x num_inpuutsの配列

y01 = 1*(np.sum(X, axis=1) >= 0)  # in { 0,  1}

y = 2*y01-1                       # in {-1, +1}

y_one_hot = np.zeros((num_samples, 2))

for i in range(num_samples):

    y_one_hot[i, y01[i]] = 1



for x, y_target in zip(X, y):

    if y_target == 1:

        plt.plot(x[0], x[1], 'bo')

    else:

        plt.plot(x[0], x[1], 'go')

plt.plot([-1, 1], [1, -1], '--', color='black')

plt.show()

# 量子回路の準備

num_inputs = 2

feature_map = ZZFeatureMap(num_inputs)



ansatz = RealAmplitudes(num_inputs, reps=1)



qc = QuantumCircuit(num_inputs)

qc.append(feature_map, range(num_inputs))

qc.append(ansatz, range(num_inputs))

qc.decompose().draw(output='mpl')

# parity maps bitstrings to 0 or 1

def parity(x):

    return '{:b}'.format(x).count('1') % 2

output_shape = 2  # corresponds to the number of classes, possible outcomes of the (parity) mapping.

# construct QNN

circuit_qnn = CircuitQNN(circuit=qc,

                         input_params=feature_map.parameters,

                         weight_params=ansatz.parameters,

                         interpret=parity,

                         output_shape=output_shape,

                         quantum_instance=qi_qasm)

# construct classifier

circuit_classifier = NeuralNetworkClassifier(neural_network=circuit_qnn,

                                             optimizer=COBYLA())

circuit_classifier.fit(X, y01)

circuit_classifier.score(X, y01)

# 評価用のデータを生成

num_samples_test = 100

X_test = 2*np.random.rand(num_samples_test, num_inputs) - 1 # num_sample x num_inpuutsの配列

y01_test = 1*(np.sum(X_test, axis=1) >= 0)  # in { 0,  1}

y_test = 2*y01_test-1                       # in {-1, +1}

# evaluate data points

y_predict = circuit_classifier.predict(X_test)



# plot results

for x, y_target, y_p in zip(X_test, y01_test, y_predict):

    if y_p == 1:

        plt.plot(x[0], x[1], 'bo')

    else:

        plt.plot(x[0], x[1], 'go')

    if y_target != y_p:

        plt.scatter(x[0], x[1], s=200, facecolors='none', edgecolors='r', linewidths=2)

plt.plot([-1, 1], [1, -1], '--', color='black')

plt.show()

import qiskit.tools.jupyter

%qiskit_version_table