import sys
import os
import pennylane as qml
from pennylane import numpy as np
import tensorflow as tf
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder
import matplotlib

matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from tensorflow.python.keras.layers import Dense

# Redirect stdout to capture print outputs
class Tee(object):
    def __init__(self, *files):
        self.files = files

    def write(self, obj):
        for f in self.files:
            f.write(obj)
            f.flush()

    def flush(self):
        for f in self.files:
            f.flush()

output_file = open('output.log', 'w', encoding='utf-8')
original_stdout = sys.stdout
sys.stdout = Tee(sys.stdout, output_file)

def save_plot(fig, filename):
    fig.savefig(filename)
    plt.close(fig)

def plot_history(history):
    # Plot training and validation accuracy
    fig, ax = plt.subplots(figsize=(10, 5))
    ax.plot(history.history['accuracy'])
    ax.plot(history.history['val_accuracy'])
    ax.set_title('Model Accuracy')
    ax.set_ylabel('Accuracy')
    ax.set_xlabel('Epoch')
    ax.legend(['Train', 'Validation'], loc='upper left')
    save_plot(fig, 'accuracy_plot.png')

    # Plot training and validation loss
    fig, ax = plt.subplots(figsize=(10, 5))
    ax.plot(history.history['loss'])
    ax.plot(history.history['val_loss'])
    ax.set_title('Model Loss')
    ax.set_ylabel('Loss')
    ax.set_xlabel('Epoch')
    ax.legend(['Train', 'Validation'], loc='upper left')
    save_plot(fig, 'loss_plot.png')

# Define the quantum device with 11 qubits
dev = qml.device("default.qubit", wires=11)

@qml.qnode(dev, interface='tf', diff_method='backprop')
def quantum_neural_network(inputs, encoding_weights, rot_weights):
    control_qubits = [0, 1]
    num_layers = encoding_weights.shape[0]

    # Define quantum qubit indices
    data_qubits_per_layer = []
    swap_control_qubits = []
    qubit_idx = 2  # Start from the 3rd qubit

    for layer in range(num_layers):
        data_qubits = [qubit_idx, qubit_idx + 1]  # 2 qubits per layer
        qubit_idx += 2
        data_qubits_per_layer.append(data_qubits)
        swap_control_qubit = qubit_idx
        swap_control_qubits.append(swap_control_qubit)
        qubit_idx += 1  # Add 1 for the swap control qubit

    # Process each layer
    for layer_idx, data_qubits in enumerate(data_qubits_per_layer):
        swap_control_qubit = swap_control_qubits[layer_idx]

        # Encode each feature
        for cv_idx, cv in enumerate([[0, 0], [0, 1], [1, 0], [1, 1]]):
            feature_value = inputs[cv_idx]
            angle_weight = encoding_weights[layer_idx, cv_idx]

            # Flip control qubits
            for qubit, val in zip(control_qubits, cv):
                if val == 0:
                    qml.PauliX(wires=qubit)

            # Apply controlled RY gates with feature values and weights
            for data_qubit in data_qubits:
                qml.ctrl(qml.RY, control=control_qubits)(feature_value, wires=data_qubit)
                qml.ctrl(qml.RY, control=control_qubits)(angle_weight, wires=data_qubit)

            # Restore control qubits
            for qubit, val in zip(control_qubits, cv):
                if val == 0:
                    qml.PauliX(wires=qubit)

        # Apply swap gate
        qml.Hadamard(wires=swap_control_qubit)
        qml.CSWAP(wires=[swap_control_qubit, data_qubits[0], data_qubits[1]])
        qml.Hadamard(wires=swap_control_qubit)

    # Apply rotation layers
    total_qubits = qubit_idx
    for layer in range(rot_weights.shape[0]):
        for qubit in range(total_qubits):
            rot_angles = rot_weights[layer, qubit, :]
            qml.Rot(rot_angles[0], rot_angles[1], rot_angles[2], wires=qubit)

    # Measure swap control qubits
    results = []
    for swap_control_qubit in swap_control_qubits:
        results.append(qml.expval(qml.PauliZ(wires=swap_control_qubit)))

    return results

# Define a quantum neural network layer
class QuantumNeuralNetworkLayer(tf.keras.layers.Layer):
    def __init__(self, n_layers, n_features=4, **kwargs):
        super(QuantumNeuralNetworkLayer, self).__init__(**kwargs)
        self.n_layers = n_layers
        self.n_features = n_features

        # Define encoding weights
        self.encoding_weights = self.add_weight(
            shape=(n_layers, n_features),
            initializer=tf.keras.initializers.GlorotUniform(),
            trainable=True,
            name='encoding_weights',
            dtype=tf.float64
        )

        # Calculate total qubits = 2 control qubits + n_layers * (2 data qubits + 1 swap control qubit)
        total_qubits = 2 + n_layers * (2 + 1)

        self.rot_weights = self.add_weight(
            shape=(n_layers, total_qubits, 3),
            initializer=tf.keras.initializers.GlorotUniform(),
            trainable=True,
            name='rot_weights',
            dtype=tf.float64
        )

    def call(self, inputs):
        def apply_qnode(x):
            x = tf.cast(x, dtype=tf.float64)
            result = quantum_neural_network(x, self.encoding_weights, self.rot_weights)
            return tf.cast(result, dtype=tf.float32)

        # Reshape inputs to be compatible with tf.map_fn
        inputs = tf.reshape(inputs, (-1, self.n_features))
        outputs = tf.map_fn(
            apply_qnode,
            inputs,
            fn_output_signature=tf.float32
        )
        return tf.reshape(outputs, (-1, self.n_layers))

# Define a deep quantum neural network model
class DeepQuantumNeuralNetwork(tf.keras.Model):
    def __init__(self, n_quantum_layers, n_layers_per_qnn, num_classes, n_features=4, **kwargs):
        super(DeepQuantumNeuralNetwork, self).__init__(**kwargs)
        self.n_quantum_layers = n_quantum_layers

        # Stack multiple quantum layers
        self.quantum_layers = [
            QuantumNeuralNetworkLayer(n_layers=n_layers_per_qnn, n_features=n_features)
            for _ in range(n_quantum_layers)
        ]

        # Final classical dense layer
        self.dense = Dense(num_classes, activation='softmax')

    def call(self, inputs):
        # Pass through each quantum layer
        x = inputs
        for layer in self.quantum_layers:
            x = layer(x)
        # Apply the final dense layer
        return self.dense(x)

# Create an instance of the deep quantum neural network
n_quantum_layers = 3  # Number of quantum layers to stack
n_layers_per_qnn = 2  # Number of rotation layers per quantum neural network

model = DeepQuantumNeuralNetwork(
    n_quantum_layers=n_quantum_layers,
    n_layers_per_qnn=n_layers_per_qnn,
    num_classes=3
)

# Compile and train the model
learning_rate = 0.1
epochs = 100
batch_size = 8

model.compile(
    optimizer=tf.keras.optimizers.SGD(learning_rate=learning_rate),
    loss='categorical_crossentropy',
    metrics=['accuracy']
)

# Load and preprocess data
iris = load_iris()
X = iris['data'].astype(np.float32)
y = iris['target'].reshape(-1, 1)

# One-hot encode the labels
encoder = OneHotEncoder(sparse_output=False)
y = encoder.fit_transform(y).astype(np.float32)

# Split the data into training and testing sets
x_train, x_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=116
)

# Train the model
history = model.fit(
    x_train, y_train,
    batch_size=batch_size,
    epochs=epochs,
    verbose=1,
    validation_data=(x_test, y_test)
)

# Evaluate the model
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

plot_history(history)

# Close the output file and restore stdout
sys.stdout = original_stdout
output_file.close()

print("脚本执行完成。查看 'output.log' 获取打印输出，查看当前目录获取保存的图表。")
代码出现报错
Traceback (most recent call last):
  File "G:\Hellyc\yuanweihua-NewQNN-default-layers=4_4feature _AngCode\examples\yuanweihua_renew_usesoftmax_NQNN_default_4feature_AngCode_Layers=5.py", line 223, in <module>
    history = model.fit(
  File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\utils\traceback_utils.py", line 70, in error_handler
    raise e.with_traceback(filtered_tb) from None
  File "G:\anaconda3\envs\pennylane2\lib\site-packages\tensorflow\python\eager\execute.py", line 54, in quick_execute
    tensors = pywrap_tfe.TFE_Py_Execute(ctx._handle, device_name, op_name,
tensorflow.python.framework.errors_impl.InvalidArgumentError: Graph execution error:

Detected at node 'categorical_crossentropy/softmax_cross_entropy_with_logits' defined at (most recent call last):
    File "G:\Hellyc\yuanweihua-NewQNN-default-layers=4_4feature _AngCode\examples\yuanweihua_renew_usesoftmax_NQNN_default_4feature_AngCode_Layers=5.py", line 223, in <module>
      history = model.fit(
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\utils\traceback_utils.py", line 65, in error_handler
      return fn(*args, **kwargs)
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\engine\training.py", line 1564, in fit
      tmp_logs = self.train_function(iterator)
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\engine\training.py", line 1160, in train_function
      return step_function(self, iterator)
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\engine\training.py", line 1146, in step_function
      outputs = model.distribute_strategy.run(run_step, args=(data,))
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\engine\training.py", line 1135, in run_step
      outputs = model.train_step(data)
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\engine\training.py", line 994, in train_step
      loss = self.compute_loss(x, y, y_pred, sample_weight)
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\engine\training.py", line 1052, in compute_loss
      return self.compiled_loss(
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\engine\compile_utils.py", line 265, in __call__
      loss_value = loss_obj(y_t, y_p, sample_weight=sw)
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\losses.py", line 152, in __call__
      losses = call_fn(y_true, y_pred)
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\losses.py", line 272, in call
      return ag_fn(y_true, y_pred, **self._fn_kwargs)
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\losses.py", line 1990, in categorical_crossentropy
      return backend.categorical_crossentropy(
    File "G:\anaconda3\envs\pennylane2\lib\site-packages\keras\backend.py", line 5535, in categorical_crossentropy
      return tf.nn.softmax_cross_entropy_with_logits(
Node: 'categorical_crossentropy/softmax_cross_entropy_with_logits'
logits and labels must be broadcastable: logits_size=[2,3] labels_size=[8,3]
	 [[{{node categorical_crossentropy/softmax_cross_entropy_with_logits}}]] [Op:__inference_train_function_251364]

如何进行解决