import pandas as pd
import time
import numpy as np
import matplotlib.pyplot as plt
import os
import torch
from torch import nn
from torch.utils.data import Dataset, DataLoader
from collections import Counter
import torch.nn.functional
import pennylane as qml
from pennylane import numpy as np
from datasets import load_dataset
from tqdm import tqdm  # 添加进度条
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
import re
from sklearn.model_selection import train_test_split
from qiskit import QuantumCircuit
from qiskit.visualization import circuit_drawer
from sklearn.metrics import f1_score, recall_score, accuracy_score
from torch.nn.utils.rnn import pad_sequence
from torch.optim.lr_scheduler import StepLR
import warnings
import random
seed = 42
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)


min_freq = 1

sequence_length = 10

embedding_dim = 100  # 词嵌入维度 与mat1有关

batch_size = 128

hidden_units = 32

n_qlayers = 1

dropout_rate = 0.3

lr = 0.001

epoch = 40

weight_decay = 0.00001

# 读取数据文件
def load_data(file_path):
    data = []
    with open(file_path, 'r', encoding='utf-8') as file:
        for line in file:
            text, label = line.strip().split('\t')
            data.append((text, int(label)))
    return pd.DataFrame(data, columns=['text', 'label'])

# 文本清洗函数
def clean_text(text):
    # 转换为小写
    text = text.lower()
    # 移除 HTML 标签
    text = re.sub(r'<.*?>', '', text)
    # 移除 URL
    text = re.sub(r'http\S+|www\S+|https\S+', '', text, flags=re.MULTILINE)
    # 移除标点符号和数字
    text = re.sub(r'\d+', '', text)
    text = re.sub(r'[^\w\s]', '', text)
    # 分词
    words = word_tokenize(text)
    # 移除停用词
    stop_words = set(stopwords.words('english'))- {'not', 'no', 'nor', 'but'}
    words = [word for word in words if word not in stop_words]
    return ' '.join(words)


# 加载数据
file_path = 'amazon_cells_labelled.txt'
dataset = load_data(file_path)

# 随机抽取一个新的训练集（800条）、验证集（100条）和测试集（100条）
train_val_set, test_set = train_test_split(dataset, train_size=900, test_size=100, random_state=42, stratify=dataset['label'])
train_set, val_set = train_test_split(train_val_set, train_size=800, test_size=100, random_state=42, stratify=train_val_set['label'])

# 清洗所有数据集的文本
train_set['text'] = train_set['text'].apply(clean_text)
val_set['text'] = val_set['text'].apply(clean_text)
test_set['text'] = test_set['text'].apply(clean_text)

# 定义一个函数来标记和编码句子
def tokenize_and_encode(sentences, vocab, seq_length):
    token_ids = [
        [vocab.get(token, vocab['<UNK>']) for token in sentence.split()]
        for sentence in sentences
    ]
    return token_ids

def collate_fn(batch):
    # batch = [(sequence, label), (sequence, label), ...]
    sequences, labels = zip(*batch)
    # Convert sequences and labels to tensors
    sequences = [torch.tensor(seq, dtype=torch.long) for seq in sequences]
    labels = torch.tensor(labels, dtype=torch.long)
    # Get sequence lengths
    lengths = torch.tensor([len(seq) for seq in sequences], dtype=torch.long)
    # Pad sequences
    padded_sequences = pad_sequence(sequences, batch_first=True, padding_value=vocabulary['<PAD>'])
    return padded_sequences, labels, lengths

# 从训练数据集创建词汇表
all_train_tokens = [token for sentence in train_set['text'] for token in sentence.split()]

# 计算所有训练数据中单词的频率
word_counts = Counter(all_train_tokens)

# 打印词汇表中每个单词的频率，按照频率从高到低排序
for word, count in word_counts.most_common():
    print(f"{word}: {count}")

# 只保留出现次数大于等于阈值的单词

filtered_words = [word for word, count in word_counts.items() if count >= min_freq]
vocabulary = {word: i + 2 for i, word in enumerate(filtered_words)}
vocabulary['<UNK>'] = 1
vocabulary['<PAD>'] = 0

# 打印词汇表大小
print(f"真实Vocabulary size: {len(vocabulary)}")

# 对数据集进行标记和编码

train_token_ids = tokenize_and_encode(train_set['text'], vocabulary, sequence_length)
val_token_ids = tokenize_and_encode(val_set['text'], vocabulary, sequence_length)
#test_token_ids = tokenize_and_encode(test_set['text'], vocabulary, sequence_length)

# 创建自定义 PyTorch 数据集
class SentimentDataset(Dataset):
    def __init__(self, token_ids, labels):
        self.token_ids = token_ids
        self.labels = labels

    def __len__(self):
        return len(self.token_ids)

    def __getitem__(self, idx):
        return self.token_ids[idx], self.labels[idx]

# 创建自定义 Dataset 实例

train_dataset = SentimentDataset(train_token_ids, train_set['label'].tolist())
val_dataset = SentimentDataset(val_token_ids, val_set['label'].tolist())
#test_dataset = SentimentDataset(test_token_ids, test_set['label'].tolist())

# 打印标记和编码后的数据样本
print("\n标记和编码后的数据样本:")
for sample in train_token_ids[:500]:
     print(" ".join(map(str, sample)))



# 创建 DataLoader
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, collate_fn=collate_fn)
val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False, collate_fn=collate_fn)
#test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, collate_fn=collate_fn)


# 打印训练集、验证集和测试集的标签统计信息
train_positive_count = train_set[train_set['label'] == 1].shape[0]
train_negative_count = train_set[train_set['label'] == 0].shape[0]
print(f"Train Positive count: {train_positive_count}")
print(f"Train Negative count: {train_negative_count}")

val_positive_count = val_set[val_set['label'] == 1].shape[0]
val_negative_count = val_set[val_set['label'] == 0].shape[0]
print(f"Validation Positive count: {val_positive_count}")
print(f"Validation Negative count: {val_negative_count}")

test_positive_count = test_set[test_set['label'] == 1].shape[0]
test_negative_count = test_set[test_set['label'] == 0].shape[0]
print(f"Test Positive count: {test_positive_count}")
print(f"Test Negative count: {test_negative_count}")



# 量子LSTM
class QLSTM(nn.Module):
    def __init__(self,
                 input_size,
                 hidden_size,
                 n_qubits=4,
                 n_qlayers=n_qlayers,
                 n_vrotations=3,
                 batch_first=True,
                 return_sequences=False,
                 return_state=False,
                 backend="default.qubit",
                 dropout_rate=dropout_rate):
        super(QLSTM, self).__init__()
        self.n_inputs = input_size
        self.hidden_size = hidden_size
        self.concat_size = self.n_inputs + self.hidden_size
        self.n_qubits = n_qubits
        self.n_qlayers = n_qlayers
        self.n_vrotations = n_vrotations
        self.backend = backend

        self.batch_first = batch_first
        self.return_sequences = return_sequences
        self.return_state = return_state

        self.wires_forget = [f"wire_forget_{i}" for i in range(self.n_qubits)]
        self.wires_input = [f"wire_input_{i}" for i in range(self.n_qubits)]
        self.wires_update = [f"wire_update_{i}" for i in range(self.n_qubits)]
        self.wires_output = [f"wire_output_{i}" for i in range(self.n_qubits)]
        self.wires_output_h = [f"wire_output_h_{i}" for i in range(self.n_qubits)]
        # 定义线性层
        self.fc = nn.Linear(self.hidden_size, 2)
        # 初始化权重形状
        self.weight_shapes = {"weights": (self.n_qlayers, self.n_vrotations, self.n_qubits)}
        # 定义量子设备
        # self.dev = qml.device('default.qubit', wires=4)
        self.dev_forget = qml.device(self.backend, wires=self.wires_forget)
        self.dev_input = qml.device(self.backend, wires=self.wires_input)
        self.dev_update = qml.device(self.backend, wires=self.wires_update)
        self.dev_output = qml.device(self.backend, wires=self.wires_output)
        self.dev_output_h = qml.device(self.backend, wires=self.wires_output_h)
        # 定义 ansatz 方法
        self.ansatz = self.ansatz
        # 初始化dropout层
        self.dropout = nn.Dropout(dropout_rate)

        # QNode实例化
        self.qlayer_forget = qml.QNode(self._circuit_forget, self.dev_forget, interface="torch")
        self.qlayer_input = qml.QNode(self._circuit_input, self.dev_input, interface="torch")
        self.qlayer_update = qml.QNode(self._circuit_update, self.dev_update, interface="torch")
        self.qlayer_output = qml.QNode(self._circuit_output, self.dev_output, interface="torch")
        self.qlayer_output_h = qml.QNode(self._circuit_output_h, self.dev_output_h, interface="torch")
        # 定义权重形状
        weight_shapes = {"weights": (self.n_qlayers, self.n_vrotations, self.n_qubits)}

        # print(f"weight_shapes = (n_qlayers, n_vrotations, n_qubits) = ({self.n_qlayers}, {self.n_vrotations}, {self.n_qubits})")

        # 定义线性层
        self.clayer_in = nn.Linear(self.concat_size, self.n_qubits)
        self.clayer_out = nn.Linear(self.n_qubits, self.hidden_size)
        self.clayer_out_f = nn.Linear(self.n_qubits, self.hidden_size)
        self.clayer_out_i = nn.Linear(self.n_qubits, self.hidden_size)
        self.clayer_out_g = nn.Linear(self.n_qubits, self.hidden_size)
        self.clayer_out_o = nn.Linear(self.n_qubits, self.hidden_size)
        self.TorchLayers = {
            'forget': qml.qnn.TorchLayer(self.qlayer_forget, self.weight_shapes),
            'input': qml.qnn.TorchLayer(self.qlayer_input, self.weight_shapes),
            'update': qml.qnn.TorchLayer(self.qlayer_update, self.weight_shapes),
            'output': qml.qnn.TorchLayer(self.qlayer_output, self.weight_shapes),
            'output_h': qml.qnn.TorchLayer(self.qlayer_output_h, self.weight_shapes)
        }

    def ansatz(self, params, wires_type):

        # Entangling layer.
        for i in range(1, 3):
            for j in range(self.n_qubits):
                if j + i < self.n_qubits:
                    qml.CNOT(wires=[wires_type[j], wires_type[j + i]])
                else:
                    qml.CNOT(wires=[wires_type[j], wires_type[j + i - self.n_qubits]])

            # Variational layer.
            for i in range(self.n_qubits):
                qml.RX(params[0][i], wires=wires_type[i])
                qml.RY(params[1][i], wires=wires_type[i])
                qml.RZ(params[2][i], wires=wires_type[i])

    def vqc(self, features, weights, wires_type):
        # 将features转换为PyTorch张量（如果它是一个NumPy数组）
        if isinstance(features, np.ndarray):
            features = torch.tensor(features, dtype=torch.float32)
        # 检查features是否为一维张量，如果是，则添加一个新的批次维度
        if features.dim() == 1:
            features = features.unsqueeze(0)  # 将其变为二维张量，形状为[1, 特征数]
        if not isinstance(features, torch.Tensor):
            features = torch.tensor(features, dtype=torch.float32)
        # print("features形状:", features.shape)
        # print("Weights shape:", weights.shape)

        # 确保 features 的长度等于量子位的数量
        features = features[:, :self.n_qubits]
        ry_params = torch.atan2(features, torch.ones_like(features))
        rz_params = torch.atan2(features ** 2, torch.ones_like(features))

        # ry_params = [torch.arctan(feature) for feature in features]
        # rz_params = [torch.arctan(feature ** 2) for feature in features]
        # 应用Hadamard门到每个量子位上
        for i in range(self.n_qubits):
            qml.Hadamard(wires=wires_type[i])

        # 对量子位进行RY和RZ旋转
        for i in range(self.n_qubits):
            qml.RY(ry_params[:, i], wires=wires_type[i])
            qml.RZ(rz_params[:, i], wires=wires_type[i])

        # 创建量子位之间的纠缠
        for i in range(1, 3):
            for j in range(self.n_qubits):
                if j + i < self.n_qubits:
                    qml.CNOT(wires=[wires_type[j], wires_type[j + i]])
                else:
                    qml.CNOT(wires=[wires_type[j], wires_type[j + i - self.n_qubits]])

        # 再次对量子位进行RX、RY、RZ旋转
        for layer in range(self.n_qlayers):
            for i in range(self.n_qubits):
                qml.RX(weights[layer, 0, i], wires=wires_type[i])
                qml.RY(weights[layer, 1, i], wires=wires_type[i])
                qml.RZ(weights[layer, 2, i], wires=wires_type[i])
    # 定义量子电路，模拟LSTM中的门控机制
    def _circuit_forget(self, inputs, weights):
        self.vqc(inputs, weights, self.wires_forget)
        return [qml.expval(qml.PauliZ(wires=i)) for i in self.wires_forget]

    def _circuit_input(self, inputs, weights):
        self.vqc(inputs, weights, self.wires_input)
        return [qml.expval(qml.PauliZ(wires=i)) for i in self.wires_input]

    def _circuit_update(self, inputs, weights):
        self.vqc(inputs, weights, self.wires_update)
        return [qml.expval(qml.PauliZ(wires=i)) for i in self.wires_update]

    def _circuit_output(self, inputs, weights):
        self.vqc(inputs, weights, self.wires_output)
        return [qml.expval(qml.PauliZ(wires=i)) for i in self.wires_output]
    # 计算隐藏状态输出

    def _circuit_output_h(self, inputs, weights):
        self.vqc(inputs, weights, self.wires_output_h)
        return [qml.expval(qml.PauliZ(wires=i)) for i in self.wires_output_h]

    # 利用qiskit可视化电路图
    def to_qiskit_circuit(self, inputs, weights, wires_type):
        # 添加经典位用于存储测量结果
        circuit = QuantumCircuit(self.n_qubits, self.n_qubits)
        features = torch.tensor(inputs[:, :self.n_qubits], dtype=torch.float32)
        ry_params = torch.atan2(features, torch.ones_like(features))
        rz_params = torch.atan2(features ** 2, torch.ones_like(features))

        # 应用Hadamard门到每个量子位上
        for i in range(self.n_qubits):
            circuit.h(i)

        # 对量子位进行RY和RZ旋转
        for i in range(self.n_qubits):
            circuit.ry(ry_params[:, i].item(), i)
            circuit.rz(rz_params[:, i].item(), i)

        # 创建量子位之间的纠缠
        for i in range(1, 3):
            for j in range(self.n_qubits):
                if j + i < self.n_qubits:
                    circuit.cx(j, j + i)
                else:
                    circuit.cx(j, (j + i) % self.n_qubits)

        # 再次对量子位进行RX、RY、RZ旋转
        for layer in range(self.n_qlayers):
            for i in range(self.n_qubits):
                circuit.rx(weights[layer, 0, i].item(), i)
                circuit.ry(weights[layer, 1, i].item(), i)
                circuit.rz(weights[layer, 2, i].item(), i)

        # 对每个量子位进行测量，并将结果存储到对应的经典位中
        for i in range(self.n_qubits):
            circuit.measure(i, i)

        return circuit

    def visualize_qiskit_circuit(self):
        example_inputs = np.random.random((1, self.n_qubits))
        example_weights = np.random.random((self.n_qlayers, self.n_vrotations, self.n_qubits))
        qiskit_circuit = self.to_qiskit_circuit(example_inputs, example_weights, self.wires_forget)
        circuit_drawer(qiskit_circuit, output='mpl').show()

    def forward(self, x, lengths, init_states=None):

        batch_size, seq_length, _ = x.size()

        if init_states is None:
            h_t = torch.zeros(batch_size, self.hidden_size, dtype=torch.float32)  # hidden state (output)
            c_t = torch.zeros(batch_size, self.hidden_size, dtype=torch.float32)  # cell state
        else:
            h_t, c_t = init_states
        # Pack the sequence
        x_packed = nn.utils.rnn.pack_padded_sequence(x, lengths.cpu(), batch_first=True, enforce_sorted=False)

        max_length = max(lengths)
        outputs = []
        # 批处理整个序列
        for t in range(seq_length):
            mask = (lengths > t).float().unsqueeze(1)

            x_t = x[:, t, :]  # 获取当前时间步的特征
            # 选择 h_t 的最后一层，以匹配 x_t 的维度
            h_t_last_layer = h_t  # 假设 h_t 的形状是 [num_layers, batch_size, hidden_size]

            # 现在 h_t_last_layer 的形状是 [batch_size, hidden_size]，可以和 x_t 连接
            combined = torch.cat((h_t_last_layer, x_t), dim=1)

            # 将拼接后的数据通过一个线性层以匹配量子位的维度
            combined = self.clayer_in(combined)

            # 用量子层处理整个批次的数据
            f_t_intermediate = self.TorchLayers['forget'](combined)
            i_t_intermediate = self.TorchLayers['input'](combined)
            g_t_intermediate = self.TorchLayers['update'](combined)
            o_t_intermediate = self.TorchLayers['output'](combined)

            # 将中间结果通过另一个线性层转换回隐藏状态的维度
            f_t = torch.sigmoid(self.clayer_out_f(f_t_intermediate))
            i_t = torch.sigmoid(self.clayer_out_i(i_t_intermediate))
            g_t = torch.tanh(self.clayer_out_g(g_t_intermediate))
            o_t = torch.sigmoid(self.clayer_out_o(o_t_intermediate))

            # 根据 LSTM 的更新规则更新隐藏状态和细胞状态
            c_t = f_t * c_t + i_t * g_t
            h_t = o_t * torch.tanh(c_t)
            # print("h_t shape:", h_t.shape)
            # 使用最后的隐藏状态通过一个线性层以得到最终输出
            h_t = h_t * mask  # 将dropout应用到隐藏状态

            outputs.append(h_t.unsqueeze(1))  # Append for each time step

        outputs = torch.cat(outputs, dim=1)

        last_outputs = outputs[torch.arange(batch_size), lengths - 1]

        last_outputs = self.dropout(last_outputs)
        output = self.fc(last_outputs)
        return output

# 电路可视化实现
qlstm_instance = QLSTM(input_size=10, hidden_size=64, n_qubits=4, n_qlayers=1, n_vrotations=3, backend="default.qubit")
qlstm_instance.visualize_qiskit_circuit()
class QShallowClassificationLSTM(nn.Module):
    def __init__(self, num_sensors, embedding_dim, hidden_units, n_qubits=4, n_qlayers=1, num_classes=2, dropout_rate=dropout_rate):
        super().__init__()
        self.num_sensors = num_sensors
        self.hidden_units = hidden_units
        self.num_layers = 1
        self.num_classes = num_classes
        self.embedding = nn.Embedding(vocab_size, embedding_dim)

        # 添加自注意力层

        # 添加 Dropout 层
        self.dropout = nn.Dropout(dropout_rate)
        self.lstm = QLSTM(
            # input_size=num_sensors,
            # 使用embedding_dim 作为 LSTM 的输入维度
            input_size=embedding_dim,
            hidden_size=hidden_units,
            batch_first=True,
            n_qubits=n_qubits,
            n_qlayers=n_qlayers,

        )
        self.linear = nn.Linear(in_features=2, out_features=self.num_classes)


    def forward(self, x, lengths):
        batch_size = x.shape[0]

        x = self.embedding(x)
        # print(f"Embedding layer output shape: {x.shape}")
        # 应用自注意力层


        # 应用 Dropout
        x = self.dropout(x)

        # h0 and c0 are handled inside QLSTM
        outputs = self.lstm(x, lengths)

        return outputs  # Already includes the output from self.fc

#  计算模型分类准确率
def calculate_accuracy_and_scores(data_loader, Qmodel):
    all_labels = []
    all_predictions = []

    Qmodel.eval()
    with torch.no_grad():
        for X, y, lengths in data_loader:
            outputs = Qmodel(X, lengths)
            _, predicted = torch.max(outputs.data, 1)
            all_labels.extend(y.cpu().numpy())
            all_predictions.extend(predicted.cpu().numpy())

    # Compute metrics using all labels and predictions
    accuracy = 100 * accuracy_score(all_labels, all_predictions)
    recall = recall_score(all_labels, all_predictions, pos_label=1)
    f1 = f1_score(all_labels, all_predictions, pos_label=1)

    return accuracy, recall, f1

# 词汇表大小
vocab_size = len(vocabulary)




# 实例化分类模型和量子分类模型

Qmodel = QShallowClassificationLSTM(num_sensors=len(vocabulary),
                                    embedding_dim=embedding_dim,
                                    hidden_units=hidden_units,
                                    n_qubits=4,
                                    n_qlayers=1,
                                    num_classes=2)

# 定义损失函数和优化器
loss_function = nn.CrossEntropyLoss()  # 更新为分类任务的损失函数

Qoptimizer = torch.optim.Adam(Qmodel.parameters(), lr=lr,weight_decay=weight_decay)

# 定义学习率调度器
# scheduler = StepLR(Qoptimizer, step_size=34, gamma=0.2)

#  训练函数
def train_model(data_loader, Qmodel, loss_function, optimizer, progress_bar):
    total_loss = 0
    Qmodel.train()

    for X, y, lengths in data_loader:
        optimizer.zero_grad()
        output = Qmodel(X, lengths)
        loss = loss_function(output, y)
        loss.backward()
        optimizer.step()

        total_loss += loss.item()
        progress_bar.update(1)  # 更新进度条

    avg_loss = total_loss / len(data_loader)
    return avg_loss

#  测试函数
def test_model(data_loader, Qmodel, loss_function, progress_bar):
    total_loss = 0
    Qmodel.eval()
    with torch.no_grad():
        for X, y, lengths in data_loader:
            output = Qmodel(X, lengths)
            loss = loss_function(output, y)
            total_loss += loss.item()
            progress_bar.update(1)  # 更新进度条

    avg_loss = total_loss / len(data_loader)
    return avg_loss

# 初始化训练、测试、验证损失，验证集准确率
quantum_loss_train = []
quantum_loss_test = []
quantum_loss_val = []
quantum_accuracy_val = []
print("Quantum Untrained test\n--------")

# 初始化存储准确率的列表
train_accuracy_list = []
train_recall_list = []
train_f1_list = []

val_accuracy_list = []
val_recall_list = []
val_f1_list = []

# test_accuracy_list = []
# test_recall_list = []
# test_f1_list = []

for ix_epoch in range(epoch):
    #  print(f"Epoch {ix_epoch+1}\n---------")
    total_steps = len(train_loader) + len(val_loader)
    progress_bar = tqdm(total=total_steps, desc=f"Epoch {ix_epoch + 1}")

    # 训练损失
    train_loss = train_model(train_loader, Qmodel, loss_function, Qoptimizer, progress_bar)

    # 测试损失
    # test_loss = test_model(test_loader, Qmodel, loss_function, progress_bar)

    # 验证损失
    val_loss = test_model(val_loader, Qmodel, loss_function, progress_bar)

    # 计算量子模型的准确率、召回率和F1分数
    quantum_train_accuracy, train_recall, train_f1 = calculate_accuracy_and_scores(train_loader, Qmodel)
    # quantum_test_accuracy, test_recall, test_f1 = calculate_accuracy_and_scores(test_loader, Qmodel)

    # 计算验证集准确率、召回率和F1分数
    val_accuracy, val_recall, val_f1 = calculate_accuracy_and_scores(val_loader, Qmodel)

    # 关闭进度条
    progress_bar.close()

    train_accuracy, train_recall, train_f1 = calculate_accuracy_and_scores(train_loader, Qmodel)
    val_accuracy, val_recall, val_f1 = calculate_accuracy_and_scores(val_loader, Qmodel)
    # test_accuracy = calculate_accuracy(test_loader, Qmodel)

    # 将准确率添加到相应的列表中
    train_accuracy_list.append(train_accuracy)
    train_recall_list.append(train_recall)
    train_f1_list.append(train_f1)

    val_accuracy_list.append(val_accuracy)
    val_recall_list.append(val_recall)
    val_f1_list.append(val_f1)

    # test_accuracy_list.append(test_accuracy)
    # test_recall_list.append(test_recall)
    # test_f1_list.append(test_f1)

    # 打印损失和评估指标信息
    print(f"\nTrain Loss: {train_loss:.4f}")
    # print(f"Test Loss: {test_loss:.4f}")
    print(f"Validation Loss: {val_loss:.4f}")

    print(f"Train Accuracy: {quantum_train_accuracy:.2f}%")
    # print(f"Test Accuracy: {quantum_test_accuracy:.2f}%")
    print(f"Validation Accuracy: {val_accuracy:.2f}%\n")

    print(f"Train Recall: {train_recall:.2f}")
    # print(f"Test Recall: {test_recall:.2f}")
    print(f"Train F1 Score: {train_f1:.2f}")

    print(f"Validation Recall: {val_recall:.2f}")
    # print(f"Test F1 Score: {test_f1:.2f}")
    print(f"Validation F1 Score: {val_f1:.2f}\n")

    # 记录训练、测试、验证损失
    quantum_loss_train.append(train_loss)
    # quantum_loss_test.append(test_loss)
    quantum_loss_val.append(val_loss)
    quantum_accuracy_val.append(val_accuracy)
train_eval_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=False)

# 绘制量子 QLSTM 模型的损失图表

plt.figure(figsize=(12, 6))
plt.plot(quantum_loss_train, label='Quantum Train Loss')
plt.plot(quantum_loss_test, label='Quantum Test Loss')
plt.plot(quantum_loss_val, label='Validation Loss')
plt.title('Quantum LSTM Model Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Validation Loss across Folds')
plt.xlabel('Epoch')
plt.ylabel('Validation Loss')
plt.legend()
plt.show()

# 绘制准确率图表
plt.figure(figsize=(12, 6))
plt.plot(train_accuracy_list, label='Train Accuracy')
plt.plot(val_accuracy_list, label='Validation Accuracy')
# plt.plot(test_accuracy_list, label='Test Accuracy')

plt.plot(train_recall_list, label='Train Recall')
plt.plot(val_recall_list, label='Validation Recall')
# plt.plot(test_recall_list, label='Test Recall')

plt.plot(train_f1_list, label='Train F1 Score')
plt.plot(val_f1_list, label='Validation F1 Score')
# plt.plot(test_f1_list, label='Test F1 Score')

# 模型性能指标
plt.title('Model Evaluation Metrics Across Epochs')
plt.xlabel('Epoch')
plt.ylabel('Metrics')
plt.legend()
plt.show()
在我的代码设计的量子电路中，我先设置了一个哈达马门，然后是RY和RZ旋转门，如果我将这两个旋转门修改为RX何RY对我的量子电路有什么影响，会提高我的模型的效果吗