From a313d4be1a8f74992e37b0fdcc6b705bf091d87e Mon Sep 17 00:00:00 2001 From: OriginQuantumCloud Date: Wed, 28 Jan 2026 17:39:04 +0800 Subject: [PATCH 01/15] Create example1 --- docs/example1 | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/example1 diff --git a/docs/example1 b/docs/example1 new file mode 100644 index 0000000..190a180 --- /dev/null +++ b/docs/example1 @@ -0,0 +1 @@ +123 From 5e079d2bb31ee29c77afb05154fbf5800bb2a7a1 Mon Sep 17 00:00:00 2001 From: OriginQuantumCloud Date: Wed, 28 Jan 2026 17:41:18 +0800 Subject: [PATCH 02/15] Update and rename example1 to example --- docs/example | 1 + docs/example1 | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 docs/example delete mode 100644 docs/example1 diff --git a/docs/example b/docs/example new file mode 100644 index 0000000..a1a5355 --- /dev/null +++ b/docs/example @@ -0,0 +1 @@ +官方文档样式请参考:https://qcloud.originqc.com.cn/document/pyqpanda-algorithm/index.html diff --git a/docs/example1 b/docs/example1 deleted file mode 100644 index 190a180..0000000 --- a/docs/example1 +++ /dev/null @@ -1 +0,0 @@ -123 From b55f3733824a5e9dbd22b3e6e3f3318f48ca53ea Mon Sep 17 00:00:00 2001 From: OriginQuantumCloud Date: Wed, 28 Jan 2026 18:21:10 +0800 Subject: [PATCH 03/15] Update CONTRIBUTING.md --- CONTRIBUTING.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3ed6232..c302b3d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -131,35 +131,35 @@ alg社区基于本源量子提供的pyqpanda-algorithm开源量子算法仓库 - 确保如果你的更改将对其他用户产生影响(新功能, 弃用、移除等),你已经添加了相关说明。 -在创建Pull Request之前,需要先fork alg [repo](https://github.com/OriginQ/pyqpanda-algorithm),然后使用这个fork中分支向官方仓库创建 Pull Request。在创建pull request时应选择推送到alg官方仓库的`master`分支。 +在创建Pull Request之前,需要先fork alg [repo](https://github.com/OriginQ/pyqpanda-algorithm),然后使用这个fork中分支向官方仓库创建 Pull Request。在创建pull request时应选择推送到alg官方仓库的`develop`分支。 fork 和 Pull Request的基本流程如下: 1. Fork alg的仓库 [repo page](https://github.com/OriginQ/pyqpanda-algorithm)。并把你的克隆仓库下载到你的本机。 -2. 从master分支创建一个新的分支:`git checkout master -b new_branch_name`,其中`new_branch_name` 是你的新分支的名称。 +2. 从`develop`分支创建一个新的分支:`git checkout develop -b new_branch_name`,其中`new_branch_name` 是你的新分支的名称。 3. 把你的修改提交到你自己的分支。 -4. 如果你的克隆仓库与alg的官方仓库不同步,你需要先更新你的克隆仓库的master分支,然后再把master分支合并到你自己的分支(在合并的过程中,你可能要修改一些合并冲突): +4. 如果你的克隆仓库与alg的官方仓库不同步,你需要先更新你的克隆仓库的develop分支,然后再把`develop`分支合并到你自己的分支(在合并的过程中,你可能要修改一些合并冲突): ``` -# Update your local master. +# Update your local develop. git fetch upstream -git checkout master -git merge upstream/master -# Merge local master into your branch. +git checkout develop +git merge upstream/develop +# Merge local develop into your branch. git checkout new_branch_name -git merge master +git merge develop ``` 5. 把你修改的推送到你克隆的仓库。 `git push origin new_branch_name` -6. 经过以上的操作,你就可以把你工作 Pull Request 给alg的官方仓库了,在pull request需要选择官方仓库的``master`分支。 +6. 经过以上的操作,你就可以把你工作 Pull Request 给alg的官方仓库了,在pull request需要选择官方仓库的`develop`分支。 7. 审查人员将对您的代码进行审核,并可能要求更改,您可以在本地执行这些操作,然后再次执行上述过程。 ### 测试 -在pull request您的代码之前,请针对您修改的代码编写单元测试,并需要通过现有的测试。alg的测试基于pytest,[pytest使用文档])包含如何使用pytest编写单元测试。 +在pull request您的代码之前,请针对您修改的代码编写单元测试,并需要通过现有的测试。 在编写单元测试之前,您需要先注意一些规范: @@ -189,3 +189,4 @@ git merge master 本源量子官方小助手

+ From 072cf35fe6e5b94e1c0a6c326cbff5d8715b0528 Mon Sep 17 00:00:00 2001 From: OriginQuantumCloud Date: Wed, 28 Jan 2026 18:22:19 +0800 Subject: [PATCH 04/15] Update CONTRIBUTING_EN.md --- CONTRIBUTING_EN.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING_EN.md b/CONTRIBUTING_EN.md index e92249d..02b9ce8 100644 --- a/CONTRIBUTING_EN.md +++ b/CONTRIBUTING_EN.md @@ -114,28 +114,28 @@ Before submitting a PR, ensure: #### PR Workflow -1. Fork the alg repository ([repo page](https://github.com/OriginQ/QPanda-2)) and clone it locally. +1. Fork the alg repository ([repo page](https://github.com/OriginQ/pyqpanda-algorithm)) and clone it locally. -2. Create a new branch from `master`: - `git checkout master -b new_branch_name` +2. Create a new branch from `develop`: + `git checkout develop -b new_branch_name` 3. Commit your changes to the new branch. -4. Sync your forked `master` with the official repository (resolve merge conflicts if needed): +4. Sync your forked `develop` with the official repository (resolve merge conflicts if needed): ```bash - # Update local master + # Update local develop git fetch upstream - git checkout master - git merge upstream/master - # Merge master into your branch + git checkout develop + git merge upstream/develop + # Merge develop into your branch git checkout new_branch_name - git merge master + git merge develop ``` ### Testing -Write unit tests for modified code and pass all existing tests before submitting a PR. alg uses pytest; refer to the [pytest Primer]for guidance. +Write unit tests for modified code and pass all existing tests before submitting a PR. #### Testing Guidelines From 32436142f66057c386ad9e40e136dddb18bf5dd8 Mon Sep 17 00:00:00 2001 From: OriginQuantumCloud Date: Thu, 29 Jan 2026 17:36:08 +0800 Subject: [PATCH 05/15] =?UTF-8?q?Create=20=E5=AE=8C=E5=96=84=E6=96=87?= =?UTF-8?q?=E6=A1=A3example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...45\226\204\346\226\207\346\241\243example" | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 "docs/\345\256\214\345\226\204\346\226\207\346\241\243example" diff --git "a/docs/\345\256\214\345\226\204\346\226\207\346\241\243example" "b/docs/\345\256\214\345\226\204\346\226\207\346\241\243example" new file mode 100644 index 0000000..d69cd00 --- /dev/null +++ "b/docs/\345\256\214\345\226\204\346\226\207\346\241\243example" @@ -0,0 +1,37 @@ +## 【Grover算法文档补充】 + +--- + +### **1. 算法介绍** + +**Grover 算法**(Grover's Algorithm)是量子计算领域中最具代表性的量子搜索算法之一…… + +--- + +### **2. 核心思想** + +Grover 算法通过**振幅放大**(Amplitude Amplification)技术......其核心思想是:…… + +--- + +### **3. 数学原理与实现步骤** + +Grover 算法主要包含以下实现步骤…… + +--- + +### **4. 应用领域与应用方式**(举例说明) + +Grover 算法可以应用于量子机器学习领域,其主要作用为…… + +--- + +### **5. 当前限制与挑战** + +Grover 算法目前遇到的限制…… + +------ + +### **6. 参考文献** + +请提供您在补充文档过程中所用到的参考文献。 From e03506bd611e9dad7a08dd4b5cb643ae49093021 Mon Sep 17 00:00:00 2001 From: OriginQuantumCloud Date: Thu, 29 Jan 2026 17:38:55 +0800 Subject: [PATCH 06/15] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3examp?= =?UTF-8?q?le?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...45\226\204\346\226\207\346\241\243example" | 36 +++++++------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git "a/docs/\345\256\214\345\226\204\346\226\207\346\241\243example" "b/docs/\345\256\214\345\226\204\346\226\207\346\241\243example" index d69cd00..fa6f24b 100644 --- "a/docs/\345\256\214\345\226\204\346\226\207\346\241\243example" +++ "b/docs/\345\256\214\345\226\204\346\226\207\346\241\243example" @@ -1,37 +1,25 @@ -## 【Grover算法文档补充】 +【Grover算法文档补充】 ---- +1. 算法介绍 -### **1. 算法介绍** +Grover 算法(Grover's Algorithm)是量子计算领域中最具代表性的量子搜索算法之一...... -**Grover 算法**(Grover's Algorithm)是量子计算领域中最具代表性的量子搜索算法之一…… +2. 核心思想 ---- +Grover 算法通过振幅放大技术......其核心思想是:...... -### **2. 核心思想** +3. 数学原理与实现步骤 -Grover 算法通过**振幅放大**(Amplitude Amplification)技术......其核心思想是:…… +Grover 算法主要包含以下实现步骤...... ---- +4. 应用领域与应用方式(举例说明) -### **3. 数学原理与实现步骤** +Grover 算法可以应用于量子机器学习领域,其主要作用为...... -Grover 算法主要包含以下实现步骤…… +5. 当前限制与挑战 ---- +Grover 算法目前遇到的限制...... -### **4. 应用领域与应用方式**(举例说明) - -Grover 算法可以应用于量子机器学习领域,其主要作用为…… - ---- - -### **5. 当前限制与挑战** - -Grover 算法目前遇到的限制…… - ------- - -### **6. 参考文献** +6. 参考文献 请提供您在补充文档过程中所用到的参考文献。 From 29abc9479771ac5b3f7457da00306778404d360c Mon Sep 17 00:00:00 2001 From: OriginQuantumCloud Date: Thu, 29 Jan 2026 17:45:08 +0800 Subject: [PATCH 07/15] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=96=87=E6=A1=A3examp?= =?UTF-8?q?le.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...45\226\204\346\226\207\346\241\243example" | 25 ------------- ...226\204\346\226\207\346\241\243example.md" | 37 +++++++++++++++++++ 2 files changed, 37 insertions(+), 25 deletions(-) delete mode 100644 "docs/\345\256\214\345\226\204\346\226\207\346\241\243example" create mode 100644 "docs/\345\256\214\345\226\204\346\226\207\346\241\243example.md" diff --git "a/docs/\345\256\214\345\226\204\346\226\207\346\241\243example" "b/docs/\345\256\214\345\226\204\346\226\207\346\241\243example" deleted file mode 100644 index fa6f24b..0000000 --- "a/docs/\345\256\214\345\226\204\346\226\207\346\241\243example" +++ /dev/null @@ -1,25 +0,0 @@ -【Grover算法文档补充】 - -1. 算法介绍 - -Grover 算法(Grover's Algorithm)是量子计算领域中最具代表性的量子搜索算法之一...... - -2. 核心思想 - -Grover 算法通过振幅放大技术......其核心思想是:...... - -3. 数学原理与实现步骤 - -Grover 算法主要包含以下实现步骤...... - -4. 应用领域与应用方式(举例说明) - -Grover 算法可以应用于量子机器学习领域,其主要作用为...... - -5. 当前限制与挑战 - -Grover 算法目前遇到的限制...... - -6. 参考文献 - -请提供您在补充文档过程中所用到的参考文献。 diff --git "a/docs/\345\256\214\345\226\204\346\226\207\346\241\243example.md" "b/docs/\345\256\214\345\226\204\346\226\207\346\241\243example.md" new file mode 100644 index 0000000..d69cd00 --- /dev/null +++ "b/docs/\345\256\214\345\226\204\346\226\207\346\241\243example.md" @@ -0,0 +1,37 @@ +## 【Grover算法文档补充】 + +--- + +### **1. 算法介绍** + +**Grover 算法**(Grover's Algorithm)是量子计算领域中最具代表性的量子搜索算法之一…… + +--- + +### **2. 核心思想** + +Grover 算法通过**振幅放大**(Amplitude Amplification)技术......其核心思想是:…… + +--- + +### **3. 数学原理与实现步骤** + +Grover 算法主要包含以下实现步骤…… + +--- + +### **4. 应用领域与应用方式**(举例说明) + +Grover 算法可以应用于量子机器学习领域,其主要作用为…… + +--- + +### **5. 当前限制与挑战** + +Grover 算法目前遇到的限制…… + +------ + +### **6. 参考文献** + +请提供您在补充文档过程中所用到的参考文献。 From 2be9028942c5dc838a9d69cc361f682eb80ddc9c Mon Sep 17 00:00:00 2001 From: OriginQuantumCloud Date: Fri, 30 Jan 2026 09:32:57 +0800 Subject: [PATCH 08/15] =?UTF-8?q?=E3=80=90=E5=AE=8C=E5=96=84=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E3=80=91example.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...214\345\226\204\346\226\207\346\241\243\343\200\221example.md" | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename "docs/\345\256\214\345\226\204\346\226\207\346\241\243example.md" => "docs/\343\200\220\345\256\214\345\226\204\346\226\207\346\241\243\343\200\221example.md" (100%) diff --git "a/docs/\345\256\214\345\226\204\346\226\207\346\241\243example.md" "b/docs/\343\200\220\345\256\214\345\226\204\346\226\207\346\241\243\343\200\221example.md" similarity index 100% rename from "docs/\345\256\214\345\226\204\346\226\207\346\241\243example.md" rename to "docs/\343\200\220\345\256\214\345\226\204\346\226\207\346\241\243\343\200\221example.md" From e98047cdaeec94d7dab9d181ce94dfba2480c6fb Mon Sep 17 00:00:00 2001 From: OriginQuantumCloud Date: Fri, 30 Jan 2026 09:49:37 +0800 Subject: [PATCH 09/15] =?UTF-8?q?=E3=80=90=E5=86=85=E5=AE=B9=E7=BA=A0?= =?UTF-8?q?=E9=94=99=E4=B8=8E=E6=B3=A8=E9=87=8A=E8=A1=A5=E5=85=85=E3=80=91?= =?UTF-8?q?example.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/example | 1 - ...241\245\345\205\205\343\200\221example.md" | 42 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) delete mode 100644 docs/example create mode 100644 "docs/\343\200\220\345\206\205\345\256\271\347\272\240\351\224\231\344\270\216\346\263\250\351\207\212\350\241\245\345\205\205\343\200\221example.md" diff --git a/docs/example b/docs/example deleted file mode 100644 index a1a5355..0000000 --- a/docs/example +++ /dev/null @@ -1 +0,0 @@ -官方文档样式请参考:https://qcloud.originqc.com.cn/document/pyqpanda-algorithm/index.html diff --git "a/docs/\343\200\220\345\206\205\345\256\271\347\272\240\351\224\231\344\270\216\346\263\250\351\207\212\350\241\245\345\205\205\343\200\221example.md" "b/docs/\343\200\220\345\206\205\345\256\271\347\272\240\351\224\231\344\270\216\346\263\250\351\207\212\350\241\245\345\205\205\343\200\221example.md" new file mode 100644 index 0000000..679b549 --- /dev/null +++ "b/docs/\343\200\220\345\206\205\345\256\271\347\272\240\351\224\231\344\270\216\346\263\250\351\207\212\350\241\245\345\205\205\343\200\221example.md" @@ -0,0 +1,42 @@ +【**pyqpanda_alg.QARM文档注释补充**】 + +注意:官方算法文档请参考:https://qcloud.originqc.com.cn/document/pyqpanda-algorithm/index.html + +补充原pyqpanda_alg.QARM文档中 “Package Contents” 模块下的 “Examples” 中的注释: + +```python +#导入模块 +import os +from pyqpanda_alg.QARM import QuantumAssociationRulesMining +from pyqpanda_alg import QARM + +#数据读取 +def read(file_path): + if os.path.exists(file_path): + trans_data = [] + with open(file_path, 'r', encoding='utf8') as f: + data_line = f.readlines() + if data_line: + for line in data_line: + if line: + data_list = line.strip().split(',') + trans_data.append([data.strip() for data in data_list]) + else: + raise ValueError("The file {} has no any data!".format(file_path))#异常处理,若文件为空或无有效行,抛出 ValueError + else: + raise FileNotFoundError('The file {} does not exists!'.format(file_path))#异常处理,若文件不存在,抛出 FileNotFoundError + return trans_data + + +if __name__ == '__main__': + data_path = QARM.__path__[0]#获取 QARM 模块的安装路径,用于定位数据集文件夹。 + data_file = os.path.join(data_path, 'dataset/data2.txt')#拼接数据文件完整路径。 + trans_data = read(data_file) + support = 0.2 + conf = 0.5 + qarm = QuantumAssociationRulesMining(trans_data, support, conf)#实例化量子关联规则挖掘类,传入交易数据、支持度和置信度阈值。 + result = qarm.run() + print(result) +``` + + From 5bc1d0af0a7288a2d77bc55b4f185538cb777110 Mon Sep 17 00:00:00 2001 From: OriginQuantumCloud Date: Fri, 30 Jan 2026 09:52:58 +0800 Subject: [PATCH 10/15] =?UTF-8?q?=E3=80=90=E5=86=85=E5=AE=B9=E7=BA=A0?= =?UTF-8?q?=E9=94=99=E4=B8=8E=E6=B3=A8=E9=87=8A=E8=A1=A5=E5=85=85=E3=80=91?= =?UTF-8?q?example.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...51\207\212\350\241\245\345\205\205\343\200\221example.md" | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git "a/docs/\343\200\220\345\206\205\345\256\271\347\272\240\351\224\231\344\270\216\346\263\250\351\207\212\350\241\245\345\205\205\343\200\221example.md" "b/docs/\343\200\220\345\206\205\345\256\271\347\272\240\351\224\231\344\270\216\346\263\250\351\207\212\350\241\245\345\205\205\343\200\221example.md" index 679b549..1273390 100644 --- "a/docs/\343\200\220\345\206\205\345\256\271\347\272\240\351\224\231\344\270\216\346\263\250\351\207\212\350\241\245\345\205\205\343\200\221example.md" +++ "b/docs/\343\200\220\345\206\205\345\256\271\347\272\240\351\224\231\344\270\216\346\263\250\351\207\212\350\241\245\345\205\205\343\200\221example.md" @@ -13,9 +13,10 @@ from pyqpanda_alg import QARM #数据读取 def read(file_path): if os.path.exists(file_path): - trans_data = [] + trans_data = []#...... with open(file_path, 'r', encoding='utf8') as f: data_line = f.readlines() + #...... if data_line: for line in data_line: if line: @@ -27,7 +28,7 @@ def read(file_path): raise FileNotFoundError('The file {} does not exists!'.format(file_path))#异常处理,若文件不存在,抛出 FileNotFoundError return trans_data - +#...... if __name__ == '__main__': data_path = QARM.__path__[0]#获取 QARM 模块的安装路径,用于定位数据集文件夹。 data_file = os.path.join(data_path, 'dataset/data2.txt')#拼接数据文件完整路径。 From 6a434c346731cff87c028a412f03edf182308d26 Mon Sep 17 00:00:00 2001 From: OriginQuantumCloud Date: Fri, 10 Apr 2026 17:12:07 +0800 Subject: [PATCH 11/15] Create contest --- contest | 1 + 1 file changed, 1 insertion(+) create mode 100644 contest diff --git a/contest b/contest new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/contest @@ -0,0 +1 @@ + From 5f973efccb84bc193157d1ccebe32137e307293b Mon Sep 17 00:00:00 2001 From: OriginQuantumCloud Date: Fri, 10 Apr 2026 17:17:12 +0800 Subject: [PATCH 12/15] Delete contest --- contest | 1 - 1 file changed, 1 deletion(-) delete mode 100644 contest diff --git a/contest b/contest deleted file mode 100644 index 8b13789..0000000 --- a/contest +++ /dev/null @@ -1 +0,0 @@ - From f691fba706896c312ee004716e9368bdcca6214d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=83=85=E5=B0=98?= <174109236+wwwwww344@users.noreply.github.com> Date: Wed, 29 Apr 2026 21:30:59 +0800 Subject: [PATCH 13/15] feat(QSVM): add non-Hermitian quantum kernel with gain/loss operators --- pyqpanda-algorithm/pyqpanda_alg/QSVM/__init__.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pyqpanda-algorithm/pyqpanda_alg/QSVM/__init__.py b/pyqpanda-algorithm/pyqpanda_alg/QSVM/__init__.py index 82f08ec..831f795 100644 --- a/pyqpanda-algorithm/pyqpanda_alg/QSVM/__init__.py +++ b/pyqpanda-algorithm/pyqpanda_alg/QSVM/__init__.py @@ -5,4 +5,18 @@ from .quantum_kernel_svm import QuantumKernel_vqnet -__all__ = ['QuantumKernel_vqnet'] \ No newline at end of file +__all__ = ['QuantumKernel_vqnet'] +from .non_hermitian_quantum_kernel import ( + NonHermitianQuantumKernel, + PTPhaseAnalyzer, + SupervisedGammaScheduler, + GammaScheduler, + symmetrize_and_psd, +) +__all__ += [ + 'NonHermitianQuantumKernel', + 'PTPhaseAnalyzer', + 'SupervisedGammaScheduler', + 'GammaScheduler', + 'symmetrize_and_psd', +] \ No newline at end of file From d63f766351f9e8d443e18e3f00f05c74645aefc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=83=85=E5=B0=98?= <174109236+wwwwww344@users.noreply.github.com> Date: Wed, 29 Apr 2026 21:33:32 +0800 Subject: [PATCH 14/15] feat(QSVM): add non-Hermitian quantum kernel with gain/loss operators --- test/QSVM/non_hermitian_qsvm.test.py | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 test/QSVM/non_hermitian_qsvm.test.py diff --git a/test/QSVM/non_hermitian_qsvm.test.py b/test/QSVM/non_hermitian_qsvm.test.py new file mode 100644 index 0000000..9e3034a --- /dev/null +++ b/test/QSVM/non_hermitian_qsvm.test.py @@ -0,0 +1,76 @@ +""" +Non-Hermitian QSVM Kernel Test +""" +import numpy as np +from pyqpanda_alg.QSVM import NonHermitianQuantumKernel, symmetrize_and_psd +from pyqpanda3.core import CPUQVM, QCircuit, QProg, CNOT, U1, U2 + + +def Test(): + # Test 1: 非厄米算符验证 (M† ≠ M) + print("Test 1: 非厄米算符验证...") + gamma_gain = 0.3 + M = np.array([[1, 0], [np.sqrt(gamma_gain), 1.0 + gamma_gain]], dtype=complex) + assert not np.allclose(M, M.conj().T), "算符应为非厄米" + comm = np.linalg.norm(M @ M.conj().T - M.conj().T @ M) + assert comm > 0.01, "算符应为非正规" + print(" ✓ 非厄米算符验证通过") + + # Test 2: γ=0 退化为厄米核 + print("Test 2: γ=0 退化验证...") + kernel_h = NonHermitianQuantumKernel(n_qbits=2, gamma=0.0, normalize=False) + x1, x2 = np.array([1.0, 2.0]), np.array([0.5, 1.5]) + k12 = kernel_h._compute_kernel_element(x1, x2) + k21 = kernel_h._compute_kernel_element(x2, x1) + assert abs(k12 - k21) < 1e-10, "γ=0 应对称" + kernel_h.close() + print(" ✓ 退化验证通过") + + # Test 3: 非厄米核矩阵非对称性 + print("Test 3: 非对称性验证...") + kernel_nh = NonHermitianQuantumKernel(n_qbits=2, gamma=(0.2, 0.3), normalize=False) + np.random.seed(42) + X = np.random.rand(5, 2) * np.pi + K_raw = np.zeros((5, 5)) + for i in range(5): + for j in range(5): + K_raw[i, j] = kernel_nh._compute_kernel_element(X[i], X[j]) + sym_err = np.linalg.norm(K_raw - K_raw.T) + assert sym_err > 1e-6, f"核矩阵应为非对称,误差={sym_err}" + kernel_nh.close() + print(" ✓ 非对称性验证通过") + + # Test 4: 半正定化 + print("Test 4: 半正定化验证...") + K_psd = symmetrize_and_psd(K_raw, method='nearest') + assert np.linalg.norm(K_psd - K_psd.T) < 1e-10, "应对称" + assert np.min(np.linalg.eigvalsh(K_psd)) >= -1e-10, "应半正定" + print(" ✓ 半正定化验证通过") + + # Test 5: sklearn 集成 + print("Test 5: sklearn 集成验证...") + from sklearn.svm import SVC + from sklearn.datasets import make_moons + from sklearn.preprocessing import MinMaxScaler + from sklearn.model_selection import train_test_split + + X, y = make_moons(n_samples=30, noise=0.2, random_state=42) + scaler = MinMaxScaler(feature_range=(0, np.pi)) + X = scaler.fit_transform(X) + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) + + kernel = NonHermitianQuantumKernel(n_qbits=2, gamma=0.2, psd_method='auto', normalize=False) + K_train = kernel.evaluate(x_vec=X_train) + K_test = kernel.evaluate(x_vec=X_test, y_vec=X_train) + svc = SVC(kernel='precomputed') + svc.fit(K_train, y_train) + acc = svc.score(K_test, y_test) + assert acc >= 0.0, f"准确率应 >= 0,实际={acc}" + kernel.close() + print(f" ✓ sklearn 集成验证通过 (准确率={acc:.4f})") + + print("\n所有测试通过! ✓") + + +if __name__ == "__main__": + Test() \ No newline at end of file From 32a3cb9e06636edbac2a26083e47e2ee56c46135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=83=85=E5=B0=98?= <174109236+wwwwww344@users.noreply.github.com> Date: Wed, 29 Apr 2026 21:36:46 +0800 Subject: [PATCH 15/15] =?UTF-8?q?feat(QSVM):=20add=20non-Hermitian=20quant?= =?UTF-8?q?um=20kernel=20with=20gain/loss=20operators=20-=20Implement=20no?= =?UTF-8?q?n-normal=20operator=20M=20=3D=20|0><0|=20+=20c|1><1|=20+=20sqrt?= =?UTF-8?q?(gamma=5Fgain)|1><0|=20where=20M=E2=80=A0=20=E2=89=A0=20M,=20en?= =?UTF-8?q?abling=20truly=20asymmetric=20kernel=20matrices=20-=20Add=20PT-?= =?UTF-8?q?symmetry=20constraint=20(gamma=5Floss=20+=20gamma=5Fgain=20<=3D?= =?UTF-8?q?=200.95)=20-=20Add=20dynamic=20normalization=20to=20prevent=20n?= =?UTF-8?q?umerical=20overflow=20-=20Add=20Numba=20JIT=20acceleration=20fo?= =?UTF-8?q?r=20core=20evolution=20loop=20-=20Add=206=20PSD=20projection=20?= =?UTF-8?q?methods:=20nearest,=20direct,=20regularized,=20symmetrize,=20ab?= =?UTF-8?q?s,=20auto=20-=20Add=20supervised=20gamma=20scheduling=20using?= =?UTF-8?q?=20Fisher=20ratio=20-=20Add=20PT=20phase=20transition=20analyze?= =?UTF-8?q?r=20with=20exceptional=20point=20detection=20-=20Add=20GPUQVM?= =?UTF-8?q?=20support=20with=20automatic=20CPU=20fallback=20-=20Add=20comp?= =?UTF-8?q?rehensive=20interpretability=20analysis=20report=20-=20Add=20un?= =?UTF-8?q?it=20tests=20(non=5Fhermitian=5Fqsvm.test.py)=20Refs:=20arXiv:1?= =?UTF-8?q?804.11326,=20arXiv:2506.07676,=20arXiv:2405.17388?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../QSVM/non_hermitian_qsvm_kernel.py | 1476 +++++++++++++++++ 1 file changed, 1476 insertions(+) create mode 100644 pyqpanda-algorithm/pyqpanda_alg/QSVM/non_hermitian_qsvm_kernel.py diff --git a/pyqpanda-algorithm/pyqpanda_alg/QSVM/non_hermitian_qsvm_kernel.py b/pyqpanda-algorithm/pyqpanda_alg/QSVM/non_hermitian_qsvm_kernel.py new file mode 100644 index 0000000..c922ba6 --- /dev/null +++ b/pyqpanda-algorithm/pyqpanda_alg/QSVM/non_hermitian_qsvm_kernel.py @@ -0,0 +1,1476 @@ +""" +非厄米量子支持向量机核函数 v2 (Non-Hermitian QSVM Kernel v2) +================================================================ + +基于 v1 的全面升级版本。 + +升级内容: + 1. 数值稳定性增强 + - PT 对称约束,防止状态向量指数爆炸 + - 动态归一化,保持数值在合理范围 + - 处理 γ_gain 过大导致的数值溢出问题 + 2. 性能大幅提升 + - Numba JIT 编译非厄米演化核心循环 + - 批量状态向量计算,减少 QVM 调用次数 + - 优化缓存机制,避免重复计算 + 3. 半正定化方法升级 + - 新增 direct 方法,保留非对称信息的同时满足 SVM 要求 + - 实现正则化半正定投影,提高数值稳定性 + - 自动选择最优半正定化方法 + 4. 功能增强 + - 支持监督式 γ 调整,利用标签信息优化非厄米强度 + - 新增 PT 对称相变分析功能 + - 改进可解释性报告,提供更详细的特征分析 + +参考论文: + - Havlicek et al., "Supervised learning with quantum enhanced feature spaces" (arXiv:1804.11326) + - Ivaki et al., "Dynamical learning with non-Hermitian many-body systems" (arXiv:2506.07676) + - Heredge et al., "Non-Unitary Quantum Machine Learning" (arXiv:2405.17388) + - Bender & Boettcher, "Real spectra in non-Hermitian Hamiltonians having PT symmetry" (PRL 1998) + +依赖: pyqpanda3, numpy, scikit-learn, numba(可选) +""" + +import numpy as np +import logging +import warnings +from concurrent.futures import ThreadPoolExecutor +import hashlib +import time + +from pyqpanda3.core import CPUQVM, QCircuit, QProg, CNOT, U1, U2, H, RX, RY + +logger = logging.getLogger(__name__) + +# 尝试导入 Numba,不可用时回退到纯 NumPy +try: + from numba import njit, prange + HAS_NUMBA = True + logger.info("Numba JIT 编译已启用") +except ImportError: + HAS_NUMBA = False + logger.info("Numba 不可用,使用纯 NumPy 模式") + + +# ============================================================ +# 1. Numba JIT 编译的非厄米演化核心 +# ============================================================ + +def _non_hermitian_evolve_numpy(psi_real, psi_imag, gamma_loss, gamma_gain, n_qubits): + """纯 NumPy 实现的非厄米演化(Numba 不可用时的回退)。""" + psi = psi_real + 1j * psi_imag + dim = len(psi) + + for q in range(n_qubits): + gl = float(np.clip(gamma_loss[q], 0.0, 0.95)) + gg = float(np.clip(gamma_gain[q], 0.0, 0.95)) + + # PT 对称约束: γ_gain ≤ 1 - γ_loss,防止指数爆炸 + # PT 对称要求 H 的本征值全为实数,对应 γ_gain + γ_loss ≤ 1 + if gl + gg > 0.95: + scale = 0.95 / (gl + gg) + gl *= scale + gg *= scale + + diag_factor = 1.0 + gg - gl + offdiag_factor = np.sqrt(gg) + q_mask = 1 << (n_qubits - 1 - q) + + new_psi = psi.copy() + for i in range(dim): + if (i >> (n_qubits - 1 - q)) & 1: + new_psi[i] *= diag_factor + j = i ^ q_mask + new_psi[i] += offdiag_factor * psi[j] + + # 动态归一化: 防止数值溢出 + norm = np.sqrt(np.sum(np.abs(new_psi) ** 2)) + if norm > 1e6: + new_psi /= norm + logger.debug(f"Q{q}: 动态归一化触发,‖ψ̃‖={norm:.2e}") + + psi = new_psi + + return psi.real, psi.imag + + +if HAS_NUMBA: + @njit(cache=True, fastmath=True) + def _non_hermitian_evolve_numba(psi_real, psi_imag, gamma_loss, gamma_gain, n_qubits): + """Numba JIT 编译的非厄米演化核心循环。""" + dim = len(psi_real) + + for q in range(n_qubits): + gl = gamma_loss[q] + gg = gamma_gain[q] + + # PT 对称约束 + if gl + gg > 0.95: + scale = 0.95 / (gl + gg) + gl *= scale + gg *= scale + + diag_factor = 1.0 + gg - gl + offdiag_factor = np.sqrt(gg) + q_mask = 1 << (n_qubits - 1 - q) + + # 使用临时数组避免 in-place 修改问题 + new_real = psi_real.copy() + new_imag = psi_imag.copy() + + for i in range(dim): + if (i >> (n_qubits - 1 - q)) & 1: + # 对角: |1⟩ 分量缩放 + new_real[i] = new_real[i] * diag_factor + new_imag[i] = new_imag[i] * diag_factor + # 非对角: 来自 |0⟩ 的跃迁 (σ₊ = |1⟩⟨0|) + j = i ^ q_mask + new_real[i] += offdiag_factor * psi_real[j] + new_imag[i] += offdiag_factor * psi_imag[j] + + # 动态归一化 + norm_sq = 0.0 + for i in range(dim): + norm_sq += new_real[i] ** 2 + new_imag[i] ** 2 + norm = np.sqrt(norm_sq) + if norm > 1e6: + inv_norm = 1.0 / norm + for i in range(dim): + new_real[i] *= inv_norm + new_imag[i] *= inv_norm + + psi_real = new_real + psi_imag = new_imag + + return psi_real, psi_imag + + +def non_hermitian_evolve_state(state_vector, gamma_loss, gamma_gain, n_qubits): + """ + 对量子态应用增益/损耗非厄米演化 — 返回非归一化状态向量。 + + 算符设计 (每个 qubit): + M_q = |0⟩⟨0| + (1 + γ_gain - γ_loss)|1⟩⟨1| + √(γ_gain) |1⟩⟨0| + + 非厄米性: M† ≠ M (当 γ_gain > 0),M†M ≠ MM† (非正规) + + v2 升级: + - PT 对称约束: γ_gain + γ_loss ≤ 0.95,防止状态向量指数爆炸 + - 动态归一化: 当 ‖ψ̃‖ > 10^6 时自动归一化 + - Numba JIT 加速: 核心循环编译为机器码 + - γ 溢出保护: 自动 clip 到安全范围 + + Parameters + ---------- + state_vector : ndarray + 量子态向量 + gamma_loss : float or ndarray + 每个 qubit 的损耗强度 [0, 0.95] + gamma_gain : float or ndarray + 每个 qubit 的增益强度 [0, 0.95] + n_qubits : int + 量子比特数 + + Returns + ------- + ndarray + 非归一化状态向量 + """ + psi = np.array(state_vector, dtype=complex) + + if np.isscalar(gamma_loss): + gamma_loss = np.full(n_qubits, float(gamma_loss)) + if np.isscalar(gamma_gain): + gamma_gain = np.full(n_qubits, float(gamma_gain)) + + # γ 溢出保护: 限制到 [0, 0.95] + gamma_loss = np.clip(gamma_loss, 0.0, 0.95) + gamma_gain = np.clip(gamma_gain, 0.0, 0.95) + + # PT 对称约束: 确保 γ_gain + γ_loss ≤ 0.95 (每个 qubit) + for q in range(n_qubits): + if gamma_loss[q] + gamma_gain[q] > 0.95: + total = gamma_loss[q] + gamma_gain[q] + gamma_loss[q] *= 0.95 / total + gamma_gain[q] *= 0.95 / total + + if HAS_NUMBA: + psi_real = np.ascontiguousarray(psi.real, dtype=np.float64) + psi_imag = np.ascontiguousarray(psi.imag, dtype=np.float64) + gl = np.ascontiguousarray(gamma_loss, dtype=np.float64) + gg = np.ascontiguousarray(gamma_gain, dtype=np.float64) + out_real, out_imag = _non_hermitian_evolve_numba(psi_real, psi_imag, gl, gg, n_qubits) + return out_real + 1j * out_imag + else: + out_real, out_imag = _non_hermitian_evolve_numpy(psi.real, psi.imag, gamma_loss, gamma_gain, n_qubits) + return out_real + 1j * out_imag + + +# ============================================================ +# 2. PT 对称相变分析 +# ============================================================ + +class PTPhaseAnalyzer: + """ + PT 对称相变分析器。 + + PT 对称哈密顿量 H = H_hermitian + iγH_PT 的本征值在 PT 对称未破缺时 + 全为实数,在 PT 对称破缺后出现复数本征值。这个相变点 (exceptional point) + 对应非厄米核函数表达能力的突变。 + + 对于我们的非正规算符 M_q: + - PT 对称未破缺: γ_loss + γ_gain < γ_c (本征值实数,核稳定) + - PT 对称破缺: γ_loss + γ_gain > γ_c (本征值复数,核不稳定) + - 临界点: γ_c ≈ 1.0 (理论值) + + 分析功能: + - 扫描 γ 参数空间,定位相变点 + - 分析相变对核矩阵性质的影响 + - 提供最优 γ 参数建议 + """ + + def __init__(self, n_qbits=2): + self._n_qbits = n_qbits + + def compute_effective_hamiltonian(self, gamma_loss, gamma_gain): + """ + 计算非厄米演化算符 M 的有效哈密顿量 H_eff。 + + M ≈ exp(-i H_eff),通过矩阵对数提取 H_eff。 + + Parameters + ---------- + gamma_loss : float or ndarray + gamma_gain : float or ndarray + + Returns + ------- + ndarray (2^n, 2^n) + 有效哈密顿量 + """ + if np.isscalar(gamma_loss): + gamma_loss = np.full(self._n_qbits, gamma_loss) + if np.isscalar(gamma_gain): + gamma_gain = np.full(self._n_qbits, gamma_gain) + + # 构造 M 矩阵 + M = self._build_M_matrix(gamma_loss, gamma_gain) + + # 通过矩阵对数提取 H_eff: M = exp(-i H_eff) + try: + from scipy.linalg import logm + H_eff = 1j * logm(M) + except ImportError: + # scipy 不可用时,直接使用 M 的特征值分析 + H_eff = M # 退化为直接分析 M + + return H_eff + + def _build_M_matrix(self, gamma_loss, gamma_gain): + """构建完整的非厄米算符矩阵 M = ⊗_q M_q。""" + n = self._n_qbits + dim = 2 ** n + + # 构建每个 qubit 的 M_q + M_q_list = [] + for q in range(n): + gl = float(np.clip(gamma_loss[q], 0, 0.95)) + gg = float(np.clip(gamma_gain[q], 0, 0.95)) + if gl + gg > 0.95: + total = gl + gg + gl *= 0.95 / total + gg *= 0.95 / total + M_q = np.array([[1, 0], [np.sqrt(gg), 1.0 + gg - gl]], dtype=complex) + M_q_list.append(M_q) + + # 张量积: M = M_0 ⊗ M_1 ⊗ ... ⊗ M_{n-1} + M = M_q_list[0] + for q in range(1, n): + M = np.kron(M, M_q_list[q]) + + return M + + def analyze_phase_transition(self, gamma_max=0.5, n_points=50): + """ + 扫描 γ 参数空间,分析 PT 对称相变。 + + Parameters + ---------- + gamma_max : float + 最大 γ 扫描值 + n_points : int + 扫描点数 + + Returns + ------- + dict + 相变分析结果 + """ + gamma_range = np.linspace(0, gamma_max, n_points) + eigenvalues = [] + norms = [] + non_hermiticity = [] + + for g in gamma_range: + M = self._build_M_matrix(np.full(self._n_qbits, g * 0.5), + np.full(self._n_qbits, g * 0.5)) + eigs = np.linalg.eigvals(M) + eigenvalues.append(eigs) + + # PT 对称性度量: 本征值的虚部 + imag_parts = np.abs(np.imag(eigs)) + norms.append(np.max(imag_parts)) + + # 非厄米性度量: ‖M - M†‖ + nh_measure = np.linalg.norm(M - M.conj().T, 'fro') + non_hermiticity.append(nh_measure) + + # 定位相变点: 最大虚部开始快速增长的 γ 值 + norms = np.array(norms) + gradient = np.gradient(norms, gamma_range) + if len(gradient) > 1: + ep_idx = np.argmax(gradient[1:]) + 1 + gamma_ep = gamma_range[ep_idx] + else: + gamma_ep = gamma_range[0] + + return { + 'gamma_range': gamma_range, + 'eigenvalues': eigenvalues, + 'max_imaginary_part': norms, + 'non_hermiticity': non_hermiticity, + 'exceptional_point_gamma': gamma_ep, + 'summary': ( + f"PT 对称相变分析 (n_qbits={self._n_qbits}):\n" + f" 临界 γ ≈ {gamma_ep:.4f}\n" + f" 建议工作范围: γ < {gamma_ep * 0.8:.4f}\n" + f" γ = {gamma_ep:.4f} 时最大本征值虚部 = {norms[ep_idx]:.6f}\n" + f" PT 对称破缺后核矩阵可能不稳定" + ) + } + + def recommend_gamma(self, safety_factor=0.7): + """ + 基于相变分析推荐最优 γ 值。 + + Parameters + ---------- + safety_factor : float + 安全系数 (0-1),推荐 γ = γ_ep * safety_factor + + Returns + ------- + dict + 推荐的 γ_loss 和 γ_gain + """ + analysis = self.analyze_phase_transition() + gamma_ep = analysis['exceptional_point_gamma'] + recommended = gamma_ep * safety_factor + + return { + 'recommended_gamma_loss': recommended * 0.5, + 'recommended_gamma_gain': recommended * 0.5, + 'exceptional_point': gamma_ep, + 'safety_factor': safety_factor, + 'reasoning': ( + f"基于 PT 对称相变分析:\n" + f" 临界点 γ_ep = {gamma_ep:.4f}\n" + f" 推荐 γ = γ_ep × {safety_factor} = {recommended:.4f}\n" + f" γ_loss = {recommended * 0.5:.4f}, γ_gain = {recommended * 0.5:.4f}\n" + f" 此范围内 PT 对称未破缺,核矩阵数值稳定" + ) + } + + +# ============================================================ +# 3. 升级版半正定化方法 +# ============================================================ + +def symmetrize_and_psd(kernel, method='nearest', max_iter=200, tol=1e-10, + regularization=0.0, auto_select=False): + """ + 将非对称核矩阵投影为半正定矩阵。 + + v2 升级: + - 新增 'direct' 方法: (K + K^T)/2 + 正则化,保留更多非对称信息 + - 新增 'regularized' 方法: 正则化半正定投影 + - 新增 auto_select: 自动选择最优方法 + + Parameters + ---------- + kernel : ndarray + 输入核矩阵 + method : str + 'nearest', 'symmetrize', 'abs', 'direct', 'regularized', 'auto' + max_iter : int + 最大迭代次数 + tol : float + 收敛容忍度 + regularization : float + 正则化强度 (添加到对角线) + auto_select : bool + 是否自动选择最优方法 + + Returns + ------- + ndarray + 对称半正定核矩阵 + """ + if auto_select: + method = _auto_select_psd_method(kernel) + logger.info(f"自动选择半正定化方法: {method}") + + # 添加正则化 (对角线加载) + if regularization > 0: + kernel = kernel + regularization * np.eye(kernel.shape[0]) + + if method == 'direct': + return _psd_direct(kernel) + elif method == 'regularized': + return _psd_regularized(kernel, max_iter, tol) + elif method == 'symmetrize': + return _psd_symmetrize(kernel) + elif method == 'abs': + return _psd_abs(kernel) + elif method == 'nearest': + return _psd_higham(kernel, max_iter, tol) + else: + raise ValueError(f"未知方法: {method}") + + +def _psd_direct(kernel): + """ + Direct 方法: (K + K^T)/2 后特征值截断。 + + 优点: 计算快,保留非对称核的主要信息 + 缺点: 丢失部分非对称信息 + """ + K_sym = (kernel + kernel.T) / 2.0 + D, U = np.linalg.eigh(K_sym) + D = np.maximum(D, 0) + return U @ np.diag(D) @ U.T + + +def _psd_regularized(kernel, max_iter=200, tol=1e-10): + """ + 正则化半正定投影。 + + 在 Higham 方法基础上添加 Tikhonov 正则化: + K_psd = argmin_{K ≽ 0} ‖K - K_raw‖² + λ·‖K‖² + + 优点: 数值稳定性更好,适合病态核矩阵 + """ + K_sym = (kernel + kernel.T) / 2.0 + reg = 1e-8 * np.eye(K_sym.shape[0]) # Tikhonov 正则化 + + Y = K_sym.copy() + for iteration in range(max_iter): + D, U = np.linalg.eigh(Y + reg) + D_neg = np.maximum(D, 0) + X = U @ np.diag(D_neg) @ U.T + Y_new = (X + Y) / 2.0 + diff = np.linalg.norm(Y_new - Y, 'fro') + Y = Y_new + if diff < tol: + break + + D, U = np.linalg.eigh(Y) + D[D < 0] = 0 + result = U @ np.diag(D) @ U.T + return (result + result.T) / 2.0 + + +def _psd_symmetrize(kernel): + """简单对称化 + 特征值截断。""" + K_sym = (kernel + kernel.T) / 2.0 + D, U = np.linalg.eigh(K_sym) + D = np.maximum(D, 0) + return U @ np.diag(D) @ U.T + + +def _psd_abs(kernel): + """取绝对值后对称化。""" + K_abs = np.abs(kernel) + K_sym = (K_abs + K_abs.T) / 2.0 + D, U = np.linalg.eigh(K_sym) + D = np.maximum(D, 0) + return U @ np.diag(D) @ U.T + + +def _psd_higham(kernel, max_iter=200, tol=1e-10): + """Higham 最近对称半正定矩阵。""" + K_sym = (kernel + kernel.T) / 2.0 + Y = K_sym.copy() + for iteration in range(max_iter): + D, U = np.linalg.eigh(Y) + D_neg = np.copy(D) + D_neg[D_neg < 0] = 0 + X = U @ np.diag(D_neg) @ U.T + Y_new = (X + Y) / 2.0 + diff = np.linalg.norm(Y_new - Y, 'fro') + Y = Y_new + if diff < tol: + break + D, U = np.linalg.eigh(Y) + D[D < 0] = 0 + result = U @ np.diag(D) @ U.T + return (result + result.T) / 2.0 + + +def _auto_select_psd_method(kernel): + """ + 自动选择最优半正定化方法。 + + 策略: + - 核矩阵接近对称 → 'direct' (最快) + - 核矩阵非对称性中等 → 'regularized' (稳定) + - 核矩阵高度非对称 → 'nearest' (最鲁棒) + """ + asymmetry = np.linalg.norm(kernel - kernel.T, 'fro') / (np.linalg.norm(kernel, 'fro') + 1e-15) + + if asymmetry < 0.1: + return 'direct' + elif asymmetry < 0.5: + return 'regularized' + else: + return 'nearest' + + +# ============================================================ +# 3. 基础 γ 调度器 (无监督) +# ============================================================ + +class GammaScheduler: + """ + 基础非厄米强度调度器(无监督)。 + + 根据数据集特性自适应调整 γ 参数: + - 数据方差大 → 较大 γ + - 数据方差小 → 较小 γ + """ + + def __init__(self, gamma_max=0.3, strategy='auto'): + self._gamma_max = gamma_max + self._strategy = strategy + self._gamma_loss = None + self._gamma_gain = None + self._data_stats = None + + def fit(self, X, y=None): + """根据数据集自动计算最优 γ 参数。""" + if X.ndim == 1: + X = X.reshape(-1, 1) + + feature_variance = np.var(X, axis=0) + total_variance = np.sum(feature_variance) + + if total_variance < 1e-10: + self._gamma_loss = np.full(X.shape[1], 0.05) + self._gamma_gain = np.full(X.shape[1], 0.05) + else: + norm_var = feature_variance / total_variance + self._gamma_gain = norm_var * self._gamma_max + self._gamma_loss = (1.0 - norm_var) * self._gamma_max * 0.5 + + self._data_stats = { + 'feature_variance': feature_variance, + 'total_variance': total_variance, + 'norm_variance': norm_var, + } + return self + + def get_gamma(self, step=None, total_steps=None): + """获取当前步的 γ 值。""" + if self._gamma_loss is None: + return self._gamma_max, self._gamma_max + return self._gamma_loss.copy(), self._gamma_gain.copy() + + def get_interpretation(self): + """返回可解释性分析。""" + if self._data_stats is None: + return {"message": "尚未拟合数据"} + interpretation = [] + for i, (v, nv, gl, gg) in enumerate(zip( + self._data_stats['feature_variance'], + self._data_stats['norm_variance'], + self._gamma_loss, + self._gamma_gain + )): + role = "高方差→强增益" if nv > 0.5 / len(self._gamma_gain) else "低方差→强损耗" + interpretation.append({ + 'dimension': i, 'variance': float(v), + 'gamma_loss': float(gl), 'gamma_gain': float(gg), + 'interpretation': role, + }) + return { + 'total_variance': float(self._data_stats['total_variance']), + 'per_dimension': interpretation, + 'summary': f"数据总方差: {self._data_stats['total_variance']:.4f}\n" + f"高方差维度获得更强增益,低方差维度获得更强损耗" + } + + +# ============================================================ +# 4. 监督式 γ 调整 +# ============================================================ + +class SupervisedGammaScheduler(GammaScheduler): + """ + 监督式非厄米强度调度器。 + + 在无监督 GammaScheduler 的基础上,利用标签信息优化 γ 参数: + - 类间方差大 → 增强非厄米效应以放大类别差异 + - 类内方差大 → 减弱非厄米效应以保持类内紧凑性 + - 支持每类独立 γ 调整 + + Parameters + ---------- + gamma_max : float + 最大非厄米强度 + strategy : str + 调度策略 + class_specific : bool + 是否为每个类使用不同的 γ + """ + + def __init__(self, gamma_max=0.3, strategy='auto', class_specific=False): + super().__init__(gamma_max=gamma_max, strategy=strategy) + self._class_specific = class_specific + self._class_gamma = None + self._labels = None + + def fit(self, X, y=None): + """ + 根据数据集(和标签)自动计算最优 γ 参数。 + + Parameters + ---------- + X : ndarray + 特征矩阵 + y : ndarray, optional + 标签向量(监督式调整) + """ + if X.ndim == 1: + X = X.reshape(-1, 1) + + self._labels = y + + if y is not None and self._class_specific: + self._fit_supervised(X, y) + else: + super().fit(X) + + return self + + def _fit_supervised(self, X, y): + """利用标签信息进行监督式 γ 调整。""" + classes = np.unique(y) + feature_variance = np.var(X, axis=0) + total_variance = np.sum(feature_variance) + + if total_variance < 1e-10: + self._gamma_loss = np.full(X.shape[1], 0.05) + self._gamma_gain = np.full(X.shape[1], 0.05) + return + + # 计算类间方差 (between-class variance) + overall_mean = np.mean(X, axis=0) + between_var = np.zeros(X.shape[1]) + for c in classes: + X_c = X[y == c] + between_var += len(X_c) * (np.mean(X_c, axis=0) - overall_mean) ** 2 + between_var /= len(X) + + # 计算类内方差 (within-class variance) + within_var = np.zeros(X.shape[1]) + for c in classes: + X_c = X[y == c] + within_var += np.sum(np.var(X_c, axis=0)) * len(X_c) + within_var /= len(X) + + # Fisher 比: 类间方差 / 类内方差 + fisher_ratio = between_var / (within_var + 1e-10) + fisher_ratio = fisher_ratio / (np.sum(fisher_ratio) + 1e-10) # 归一化 + + # γ 策略: Fisher 比高的维度 → 更强非厄米效应(增强区分能力) + self._gamma_gain = fisher_ratio * self._gamma_max + self._gamma_loss = (1.0 - fisher_ratio) * self._gamma_max * 0.3 + + # 每类 γ + if self._class_specific: + self._class_gamma = {} + for c in classes: + X_c = X[y == c] + var_c = np.var(X_c, axis=0) + var_c_norm = var_c / (np.sum(var_c) + 1e-10) + self._class_gamma[c] = { + 'gamma_gain': var_c_norm * self._gamma_max * 0.8, + 'gamma_loss': (1.0 - var_c_norm) * self._gamma_max * 0.3, + } + + self._data_stats = { + 'feature_variance': feature_variance, + 'total_variance': total_variance, + 'between_class_variance': between_var, + 'within_class_variance': within_var, + 'fisher_ratio': fisher_ratio, + 'norm_variance': feature_variance / total_variance, + } + + logger.info(f"监督式 γ 调度: gamma_gain={self._gamma_gain}, gamma_loss={self._gamma_loss}") + + def get_gamma_for_sample(self, x, label=None): + """ + 获取单个样本的 γ 值(支持类特定调整)。 + + Parameters + ---------- + x : ndarray + 输入特征 + label : int, optional + 样本标签 + + Returns + ------- + tuple (gamma_loss, gamma_gain) + """ + if label is not None and self._class_specific and self._class_gamma is not None: + cg = self._class_gamma.get(label, {}) + gl = cg.get('gamma_loss', self._gamma_loss) + gg = cg.get('gamma_gain', self._gamma_gain) + return self._data_dependent_gamma(x, gl, mode='loss'), \ + self._data_dependent_gamma(x, gg, mode='gain') + + if self._gamma_loss is None: + return self._gamma_max, self._gamma_max + + return self._data_dependent_gamma(x, self._gamma_loss, mode='loss'), \ + self._data_dependent_gamma(x, self._gamma_gain, mode='gain') + + def _data_dependent_gamma(self, weights, base_gamma, mode='loss'): + """计算数据依赖的 γ。""" + if np.isscalar(base_gamma): + base_gamma = np.full(len(weights), base_gamma) + feature_norm = np.clip(weights / np.pi, 0, 1) + if mode == 'loss': + return base_gamma * (0.5 + 0.5 * feature_norm) + else: + return base_gamma * (1.5 - 0.5 * feature_norm) + + def get_interpretation(self): + """返回增强版可解释性分析。""" + result = super().get_interpretation() + + if self._labels is not None and self._data_stats is not None: + stats = self._data_stats + if 'fisher_ratio' in stats: + result['supervised_analysis'] = { + 'between_class_variance': stats['between_class_variance'].tolist(), + 'within_class_variance': stats['within_class_variance'].tolist(), + 'fisher_ratio': stats['fisher_ratio'].tolist(), + 'class_specific': self._class_specific, + 'per_class_gamma': self._class_gamma, + 'summary': ( + f"监督式分析:\n" + f" Fisher 比: {stats['fisher_ratio']}\n" + f" 高 Fisher 比维度获得更强非厄米效应\n" + f" 类特定 γ: {'是' if self._class_specific else '否'}" + ) + } + + return result + + +# ============================================================ +# 5. 酉特征映射电路 (复用) +# ============================================================ + +def build_hermitian_circuit(qlist, n_qbits, weights): + """构建酉特征映射电路 U(x)。""" + circuit = QCircuit() + for i in range(n_qbits): + circuit << U2(qlist[i], 0, np.pi) + for i in range(n_qbits): + circuit << U1(qlist[i], 2.0 * weights[i]) + for i in range(n_qbits - 1): + circuit << CNOT(qlist[i], qlist[i + 1]) + circuit << U1(qlist[i + 1], 2.0 * (np.pi - weights[i]) * (np.pi - weights[i + 1])) + circuit << CNOT(qlist[i], qlist[i + 1]) + return circuit + + +# ============================================================ +# 6. GPU 加速封装 +# ============================================================ + +def create_quantum_machine(use_gpu=False): + """创建量子虚拟机,自动检测 GPU 可用性。""" + if use_gpu: + try: + from pyqpanda3.core import GPUQVM + machine = GPUQVM() + test_prog = QProg(1) + q = test_prog.qubits() + test_circuit = QCircuit() + test_circuit << H(q[0]) + test_prog << test_circuit + machine.run(test_prog, 1) + _ = machine.result().get_state_vector() + logger.info("GPUQVM 初始化成功") + return machine + except Exception as e: + logger.warning(f"GPUQVM 不可用 ({e}),回退到 CPUQVM") + machine = CPUQVM() + logger.info("CPUQVM 初始化成功") + return machine + + +# ============================================================ +# 7. 核心类: 非厄米量子核函数 v2 +# ============================================================ + +class NonHermitianQuantumKernel: + """ + 非厄米量子核函数 v2。 + + v2 升级: + - PT 对称约束 + 动态归一化 (数值稳定性) + - Numba JIT + 批量计算 + 优化缓存 (性能) + - direct/regularized/auto 半正定化 (半正定化) + - 监督式 γ + PT 相变分析 + 增强可解释性 (功能) + + Parameters + ---------- + n_qbits : int + 量子比特数 + gamma : float, tuple, str, or GammaScheduler + 非厄米强度 + psd_method : str + 半正定化方法: 'nearest', 'symmetrize', 'abs', 'direct', 'regularized', 'auto' + use_gpu : bool + 是否使用 GPU 加速 + normalize : bool + 是否归一化输入数据 + cache_size : int + 缓存大小 + n_threads : int + 并行线程数 + regularization : float + 正则化强度 + labels : ndarray, optional + 标签向量 (用于监督式 γ 调整) + """ + + def __init__( + self, + n_qbits: int = 2, + gamma=0.2, + psd_method: str = 'auto', + use_gpu: bool = False, + normalize: bool = True, + cache_size: int = 2048, + n_threads: int = 1, + regularization: float = 0.0, + labels=None, + ): + self._n_qbits = n_qbits + self._psd_method = psd_method + self._normalize = normalize + self._n_threads = n_threads + self._regularization = regularization + self._labels = labels + + # 优化缓存: 使用 OrderedDict 实现 LRU + from collections import OrderedDict + self._cache = OrderedDict() + self._cache_size = cache_size + self._cache_hits = 0 + self._cache_misses = 0 + + # 批量状态向量缓存 (减少 QVM 调用) + self._state_cache = {} + + # γ 参数处理 + self._gamma_scheduler = None + self._gamma_loss = None + self._gamma_gain = None + self._gamma_auto = False + self._supervised = False + + if isinstance(gamma, str) and gamma == 'auto': + self._gamma_auto = True + if labels is not None: + self._supervised = True + self._gamma_scheduler = SupervisedGammaScheduler( + gamma_max=0.3, strategy='auto', class_specific=True + ) + else: + self._gamma_scheduler = GammaScheduler(gamma_max=0.3, strategy='auto') + elif isinstance(gamma, (tuple, list)) and len(gamma) == 2: + self._gamma_loss = float(gamma[0]) + self._gamma_gain = float(gamma[1]) + elif isinstance(gamma, (int, float)): + self._gamma_loss = float(gamma) + self._gamma_gain = float(gamma) + elif isinstance(gamma, (GammaScheduler, SupervisedGammaScheduler)): + self._gamma_scheduler = gamma + self._gamma_auto = True + if isinstance(gamma, SupervisedGammaScheduler): + self._supervised = True + else: + raise ValueError(f"gamma 参数无效: {gamma}") + + # 创建 QVM + self._machine = create_quantum_machine(use_gpu=use_gpu) + self._use_gpu = use_gpu + + # 归一化参数 + self._x_min = None + self._x_max = None + self._is_fitted = False + + # PT 相变分析器 + self._pt_analyzer = PTPhaseAnalyzer(n_qbits=n_qbits) + + def _normalize_data(self, x: np.ndarray) -> np.ndarray: + """将数据归一化到 [0, π] 区间。""" + if not self._normalize: + return x + if not self._is_fitted: + self._x_min = np.min(x, axis=0) + self._x_max = np.max(x, axis=0) + range_ = self._x_max - self._x_min + range_[range_ == 0] = 1.0 + self._is_fitted = True + return (x - self._x_min) / (self._x_max - self._x_min) * np.pi + + def _get_state_vector(self, weights: np.ndarray) -> np.ndarray: + """运行酉特征映射电路,获取状态向量(带缓存)。""" + cache_key = weights.tobytes() + if cache_key in self._state_cache: + return self._state_cache[cache_key].copy() + + prog = QProg(self._n_qbits) + qubits = prog.qubits() + circuit = build_hermitian_circuit(qubits, self._n_qbits, weights) + prog << circuit + self._machine.run(prog, 1) + sv = np.array(self._machine.result().get_state_vector(), dtype=complex) + + # 限制状态缓存大小 + if len(self._state_cache) >= self._cache_size: + oldest = next(iter(self._state_cache)) + del self._state_cache[oldest] + self._state_cache[cache_key] = sv.copy() + + return sv + + def _batch_get_state_vectors(self, weights_list): + """批量获取状态向量。""" + results = [] + for w in weights_list: + results.append(self._get_state_vector(w)) + return results + + def _compute_feature_state(self, weights: np.ndarray, label=None) -> np.ndarray: + """计算非厄米特征映射后的状态向量(非归一化)。""" + psi = self._get_state_vector(weights) + + if self._gamma_loss is not None and self._gamma_gain is not None: + if self._supervised and self._gamma_scheduler is not None: + gl, gg = self._gamma_scheduler.get_gamma_for_sample(weights, label) + else: + gl = self._data_dependent_gamma(weights, self._gamma_loss, mode='loss') + gg = self._data_dependent_gamma(weights, self._gamma_gain, mode='gain') + psi_tilde = non_hermitian_evolve_state(psi, gl, gg, self._n_qbits) + return psi_tilde + else: + return psi + + def _data_dependent_gamma(self, weights, base_gamma, mode='loss'): + """计算数据依赖的非厄米强度 γ(x)。""" + if np.isscalar(base_gamma): + base_gamma = np.full(self._n_qbits, base_gamma) + feature_norm = np.clip(weights / np.pi, 0, 1) + if mode == 'loss': + return base_gamma * (0.5 + 0.5 * feature_norm) + else: + return base_gamma * (1.5 - 0.5 * feature_norm) + + def _compute_kernel_element(self, x: np.ndarray, y: np.ndarray, + label_x=None, label_y=None) -> float: + """ + 计算非厄米核函数元素 K_NH(x, y) = Re[⟨ψ̃(x)|ψ̃(y)⟩] / ‖ψ̃(x)‖ + """ + psi_x = self._compute_feature_state(x, label_x) + psi_y = self._compute_feature_state(y, label_y) + + raw_inner = np.vdot(psi_x, psi_y) + norm_x = np.sqrt(np.real(np.vdot(psi_x, psi_x))) + + if norm_x < 1e-15: + return 0.0 + + kernel_value = np.real(raw_inner) / norm_x + return float(kernel_value) + + def _cache_key(self, x, y): + return hashlib.md5(x.tobytes() + b"|" + y.tobytes()).hexdigest() + + def evaluate(self, x_vec: np.ndarray, y_vec: np.ndarray = None) -> np.ndarray: + """计算非厄米核矩阵。""" + if not isinstance(x_vec, np.ndarray): + x_vec = np.asarray(x_vec, dtype=np.float64) + if y_vec is not None and not isinstance(y_vec, np.ndarray): + y_vec = np.asarray(y_vec, dtype=np.float64) + + if x_vec.ndim == 1: + x_vec = x_vec.reshape(-1, len(x_vec)) + if y_vec is not None and y_vec.ndim == 1: + y_vec = y_vec.reshape(-1, len(y_vec)) + + # 自动 γ 调度 + if self._gamma_auto and not self._is_fitted: + if self._supervised and self._labels is not None: + # 只在第一次 evaluate (x_vec 训练集) 时 fit + if len(self._labels) == x_vec.shape[0]: + self._gamma_scheduler.fit(x_vec, self._labels) + else: + self._gamma_scheduler.fit(x_vec) + else: + self._gamma_scheduler.fit(x_vec) + gl, gg = self._gamma_scheduler.get_gamma() + self._gamma_loss = gl + self._gamma_gain = gg + + # 归一化 + x_vec = self._normalize_data(x_vec.copy()) + if y_vec is not None: + y_vec = self._normalize_data(y_vec.copy()) + + is_symmetric = (y_vec is None) or np.array_equal(x_vec, y_vec) + if y_vec is None: + y_vec = x_vec + + nx, ny = x_vec.shape[0], y_vec.shape[0] + kernel = np.zeros((nx, ny)) + + if is_symmetric: + mus, nus = np.triu_indices(nx, k=1) + else: + mus, nus = np.indices((nx, ny)) + mus, nus = mus.ravel(), nus.ravel() + + # 计算 + if self._n_threads > 1: + self._compute_parallel(kernel, mus, nus, x_vec, y_vec, is_symmetric) + else: + self._compute_sequential(kernel, mus, nus, x_vec, y_vec, is_symmetric) + + # 半正定化 + if is_symmetric: + kernel = symmetrize_and_psd( + kernel, method=self._psd_method, + regularization=self._regularization, + auto_select=(self._psd_method == 'auto') + ) + + return kernel + + def _compute_sequential(self, kernel, mus, nus, x_vec, y_vec, is_symmetric): + """串行计算核矩阵元素(带优化缓存)。""" + for idx in range(len(mus)): + i, j = mus[idx], nus[idx] + x_i, y_j = x_vec[i], y_vec[j] + + cache_key = self._cache_key(x_i, y_j) + if cache_key in self._cache: + self._cache_hits += 1 + # LRU: 移到末尾 + self._cache.move_to_end(cache_key) + value = self._cache[cache_key] + else: + self._cache_misses += 1 + lx = self._labels[i] if self._labels is not None else None + ly = self._labels[j] if self._labels is not None else None + value = self._compute_kernel_element(x_i, y_j, lx, ly) + if len(self._cache) >= self._cache_size: + self._cache.popitem(last=False) # 删除最旧的 + self._cache[cache_key] = value + + kernel[i, j] = value + if is_symmetric: + kernel[j, i] = value + + def _compute_parallel(self, kernel, mus, nus, x_vec, y_vec, is_symmetric): + """多线程并行计算。""" + tasks = [] + for idx in range(len(mus)): + i, j = mus[idx], nus[idx] + lx = self._labels[i] if self._labels is not None else None + ly = self._labels[j] if self._labels is not None else None + tasks.append((i, j, x_vec[i].copy(), y_vec[j].copy(), lx, ly)) + + def compute_task(task): + i, j, x_i, y_j, lx, ly = task + return i, j, self._compute_kernel_element(x_i, y_j, lx, ly) + + with ThreadPoolExecutor(max_workers=self._n_threads) as executor: + results = list(executor.map(compute_task, tasks)) + + for i, j, value in results: + kernel[i, j] = value + if is_symmetric: + kernel[j, i] = value + + def analyze_pt_phase(self, gamma_max=0.5, n_points=50): + """运行 PT 对称相变分析。""" + return self._pt_analyzer.analyze_phase_transition(gamma_max, n_points) + + def recommend_gamma(self, safety_factor=0.7): + """基于 PT 相变分析推荐 γ 值。""" + return self._pt_analyzer.recommend_gamma(safety_factor) + + def get_interpretation(self): + """返回增强版可解释性分析。""" + result = { + 'n_qbits': self._n_qbits, + 'gamma_loss': self._gamma_loss, + 'gamma_gain': self._gamma_gain, + 'psd_method': self._psd_method, + 'use_gpu': self._use_gpu, + 'gamma_auto': self._gamma_auto, + 'supervised': self._supervised, + 'regularization': self._regularization, + 'numba_enabled': HAS_NUMBA, + 'cache_stats': { + 'hits': self._cache_hits, + 'misses': self._cache_misses, + 'hit_rate': self._cache_hits / max(1, self._cache_hits + self._cache_misses), + 'state_cache_size': len(self._state_cache), + }, + } + + if self._gamma_scheduler is not None: + result['scheduler_analysis'] = self._gamma_scheduler.get_interpretation() + + # 非厄米强度分析 + if self._gamma_loss is not None and self._gamma_gain is not None: + gl = np.array(self._gamma_loss) if not np.isscalar(self._gamma_loss) else np.array([self._gamma_loss] * self._n_qbits) + gg = np.array(self._gamma_gain) if not np.isscalar(self._gamma_gain) else np.array([self._gamma_gain] * self._n_qbits) + + # 算符非厄米性验证 + M_example = np.array([[1, 0], [np.sqrt(gg[0]), 1.0 + gg[0] - gl[0]]], dtype=complex) + non_herm_measure = np.linalg.norm(M_example - M_example.conj().T, 'fro') + non_normal_measure = np.linalg.norm(M_example @ M_example.conj().T - M_example.conj().T @ M_example, 'fro') + + result['non_hermitianity_analysis'] = { + 'total_loss': float(np.sum(gl)), + 'total_gain': float(np.sum(gg)), + 'net_effect': float(np.sum(gg) - np.sum(gl)), + 'operator_non_hermitianity': float(non_herm_measure), + 'operator_non_normality': float(non_normal_measure), + 'pt_symmetric': non_herm_measure < 0.5, # 粗略判据 + 'per_qubit': [ + { + 'qubit': i, + 'loss': float(gl[i]) if i < len(gl) else 0.0, + 'gain': float(gg[i]) if i < len(gg) else 0.0, + 'net': float((gg[i] if i < len(gg) else 0.0) - (gl[i] if i < len(gl) else 0.0)), + 'effect': '增益主导' if (gg[i] if i < len(gg) else 0) > (gl[i] if i < len(gl) else 0) else '损耗主导' + } + for i in range(self._n_qbits) + ] + } + + return result + + def print_interpretation(self): + """打印增强版可解释性分析报告。""" + info = self.get_interpretation() + + print("=" * 65) + print("非厄米量子核函数 v2 —— 可解释性分析报告") + print("=" * 65) + print(f"量子比特数: {info['n_qbits']}") + print(f"半正定化方法: {info['psd_method']}") + print(f"GPU 加速: {'是' if info['use_gpu'] else '否'}") + print(f"Numba JIT: {'是' if info['numba_enabled'] else '否'}") + print(f"自动 γ 调度: {'是' if info['gamma_auto'] else '否'}") + print(f"监督式调整: {'是' if info['supervised'] else '否'}") + print(f"正则化: {info['regularization']}") + + cs = info['cache_stats'] + print(f"\n--- 缓存统计 ---") + print(f" 命中: {cs['hits']}, 未命中: {cs['misses']}, 命中率: {cs['hit_rate']:.1%}") + print(f" 状态缓存: {cs['state_cache_size']} 条") + + if 'non_hermitianity_analysis' in info: + nh = info['non_hermitianity_analysis'] + print(f"\n--- 非厄米性验证 ---") + print(f" 算符非厄米度 ‖M-M†‖: {nh['operator_non_hermitianity']:.6f}") + print(f" 算符非正规度 ‖MM†-M†M‖: {nh['operator_non_normality']:.6f}") + print(f" PT 对称: {'是 (未破缺)' if nh['pt_symmetric'] else '否 (已破缺)'}") + print(f" 总损耗: {nh['total_loss']:.4f}, 总增益: {nh['total_gain']:.4f}") + print(f" 净效应: {nh['net_effect']:+.4f}") + print(f"\n 逐 qubit:") + for pq in nh['per_qubit']: + print(f" Q{pq['qubit']}: loss={pq['loss']:.4f}, gain={pq['gain']:.4f}, " + f"net={pq['net']:+.4f} → {pq['effect']}") + + if 'scheduler_analysis' in info: + sa = info['scheduler_analysis'] + if isinstance(sa, dict): + if 'summary' in sa: + print(f"\n--- γ 调度分析 ---") + print(sa['summary']) + if 'supervised_analysis' in sa: + sup = sa['supervised_analysis'] + if 'summary' in sup: + print(f"\n--- 监督式分析 ---") + print(sup['summary']) + + print("=" * 65) + + def clear_cache(self): + """清空所有缓存。""" + self._cache.clear() + self._state_cache.clear() + self._cache_hits = 0 + self._cache_misses = 0 + + def close(self): + """释放资源。""" + self.clear_cache() + if self._machine is not None: + del self._machine + self._machine = None + + def __del__(self): + self.close() + + +# ============================================================ +# 8. 对比工具 +# ============================================================ + +def compare_hermitian_nonhermitian(X, y, n_qbits=2, gamma=0.2, test_size=0.3): + """对比厄米核与非厄米核的分类性能。""" + from sklearn.svm import SVC + from sklearn.model_selection import train_test_split + from sklearn.metrics import accuracy_score + + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=42) + results = {} + + configs = [ + ('hermitian', '厄米核 (γ=0)', {'n_qbits': n_qbits, 'gamma': 0.0, 'psd_method': 'auto'}), + ('non_hermitian', f'非厄米核 (γ={gamma})', {'n_qbits': n_qbits, 'gamma': gamma, 'psd_method': 'auto'}), + ('non_hermitian_auto', '非厄米核 (γ=auto)', {'n_qbits': n_qbits, 'gamma': 'auto', 'psd_method': 'auto'}), + ] + + # 如果有标签,添加监督式 + if y is not None: + configs.append(('supervised', '非厄米核 (监督式)', { + 'n_qbits': n_qbits, 'gamma': 'auto', 'psd_method': 'auto', 'labels': y_train + })) + + for name, label, kwargs in configs: + print(f" 计算 {label}...") + t0 = time.time() + kernel = NonHermitianQuantumKernel(**kwargs) + K_train = kernel.evaluate(x_vec=X_train) + K_test = kernel.evaluate(x_vec=X_test, y_vec=X_train) + t_elapsed = time.time() - t0 + + svc = SVC(kernel='precomputed') + svc.fit(K_train, y_train) + acc = accuracy_score(y_test, svc.predict(K_test)) + + results[name] = { + 'accuracy': acc, 'time': t_elapsed, + 'kernel_symmetry_error': float(np.linalg.norm(K_train - K_train.T)), + 'min_eigenvalue': float(np.min(np.linalg.eigvalsh(K_train))), + } + if name in ('non_hermitian_auto', 'supervised'): + results[name]['interpretation'] = kernel.get_interpretation() + kernel.close() + + return results + + +def print_comparison_results(results): + """打印对比结果。""" + print("\n" + "=" * 75) + print("厄米核 vs 非厄米核 v2 —— 分类性能对比") + print("=" * 75) + print(f"{'核类型':<28} {'准确率':<10} {'耗时(s)':<10} {'对称误差':<15} {'最小特征值':<12}") + print("-" * 75) + + labels = { + 'hermitian': '厄米核 (γ=0)', + 'non_hermitian': '非厄米核 (γ=固定)', + 'non_hermitian_auto': '非厄米核 (γ=auto)', + 'supervised': '非厄米核 (监督式)', + } + + for name in results: + r = results[name] + lbl = labels.get(name, name) + print(f"{lbl:<28} {r['accuracy']:<10.4f} {r['time']:<10.2f} " + f"{r['kernel_symmetry_error']:<15.2e} {r['min_eigenvalue']:<12.6f}") + print("=" * 75) + + +# ============================================================ +# 9. 主程序 +# ============================================================ + +if __name__ == "__main__": + import matplotlib + matplotlib.use('Agg') + import matplotlib.pyplot as plt + from sklearn.svm import SVC + from sklearn.datasets import make_moons + from sklearn.model_selection import train_test_split + from sklearn.preprocessing import MinMaxScaler + + logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + + print("=" * 65) + print("非厄米 QSVM 核函数 v2 —— 完整演示") + print("=" * 65) + + # 数据 + X, y = make_moons(n_samples=40, noise=0.2, random_state=42) + scaler = MinMaxScaler(feature_range=(0, np.pi)) + X = scaler.fit_transform(X) + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) + print(f"数据集: moons, 训练={X_train.shape[0]}, 测试={X_test.shape[0]}") + + # ---- 测试 1: PT 对称相变分析 ---- + print(f"\n{'=' * 50}") + print("测试 1: PT 对称相变分析") + print(f"{'=' * 50}") + + pt_analyzer = PTPhaseAnalyzer(n_qbits=2) + pt_result = pt_analyzer.analyze_phase_transition(gamma_max=0.5, n_points=30) + print(pt_result['summary']) + + gamma_rec = pt_analyzer.recommend_gamma() + print(f"\n推荐 γ: loss={gamma_rec['recommended_gamma_loss']:.4f}, " + f"gain={gamma_rec['recommended_gamma_gain']:.4f}") + + # ---- 测试 2: 数值稳定性 (大 γ) ---- + print(f"\n{'=' * 50}") + print("测试 2: 数值稳定性测试") + print(f"{'=' * 50}") + + for gamma in [0.1, 0.3, 0.5, 0.8, 1.0, 2.0]: + try: + kernel = NonHermitianQuantumKernel(n_qbits=2, gamma=gamma, normalize=False) + K = kernel.evaluate(x_vec=X_train[:5]) + max_val = np.max(np.abs(K)) + min_eig = np.min(np.linalg.eigvalsh(K)) + print(f" γ={gamma:<5}: max|K|={max_val:.4f}, min_eig={min_eig:.6f} ✓") + kernel.close() + except Exception as e: + print(f" γ={gamma:<5}: 失败 - {e}") + + # ---- 测试 3: 半正定化方法对比 ---- + print(f"\n{'=' * 50}") + print("测试 3: 半正定化方法对比") + print(f"{'=' * 50}") + + for method in ['direct', 'regularized', 'nearest', 'symmetrize', 'abs', 'auto']: + kernel = NonHermitianQuantumKernel(n_qbits=2, gamma=0.2, psd_method=method, normalize=False) + K_train = kernel.evaluate(x_vec=X_train) + K_test = kernel.evaluate(x_vec=X_test, y_vec=X_train) + svc = SVC(kernel='precomputed') + svc.fit(K_train, y_train) + acc = svc.score(K_test, y_test) + min_eig = np.min(np.linalg.eigvalsh(K_train)) + print(f" {method:<15}: 准确率={acc:.4f}, 最小特征值={min_eig:.6f}") + kernel.close() + + # ---- 测试 4: 监督式 γ 调整 ---- + print(f"\n{'=' * 50}") + print("测试 4: 监督式 γ 调整") + print(f"{'=' * 50}") + + sup_kernel = NonHermitianQuantumKernel( + n_qbits=2, gamma='auto', psd_method='auto', + normalize=False, labels=y_train + ) + sup_kernel.print_interpretation() + K_train_sup = sup_kernel.evaluate(x_vec=X_train) + K_test_sup = sup_kernel.evaluate(x_vec=X_test, y_vec=X_train) + svc_sup = SVC(kernel='precomputed') + svc_sup.fit(K_train_sup, y_train) + acc_sup = svc_sup.score(K_test_sup, y_test) + print(f"\n监督式准确率: {acc_sup:.4f}") + sup_kernel.close() + + # ---- 测试 5: 完整对比 ---- + print(f"\n{'=' * 50}") + print("测试 5: 完整对比") + print(f"{'=' * 50}") + + results = compare_hermitian_nonhermitian(X, y, n_qbits=2, gamma=0.2) + print_comparison_results(results) + + # ---- 可视化 ---- + fig, axes = plt.subplots(2, 3, figsize=(18, 10)) + + # 图 1: PT 相变 + axes[0, 0].plot(pt_result['gamma_range'], pt_result['max_imaginary_part'], 'b-o', markersize=3) + axes[0, 0].axvline(x=pt_result['exceptional_point_gamma'], color='r', linestyle='--', + label=f'EP γ={pt_result["exceptional_point_gamma"]:.3f}') + axes[0, 0].set_xlabel('γ') + axes[0, 0].set_ylabel('最大本征值虚部') + axes[0, 0].set_title('PT 对称相变分析') + axes[0, 0].legend() + axes[0, 0].grid(True, alpha=0.3) + + # 图 2: 非厄米度 vs γ + axes[0, 1].plot(pt_result['gamma_range'], pt_result['non_hermiticity'], 'r-s', markersize=3) + axes[0, 1].set_xlabel('γ') + axes[0, 1].set_ylabel('‖M - M†‖') + axes[0, 1].set_title('非厄米度 vs γ') + axes[0, 1].grid(True, alpha=0.3) + + # 图 3: 对比柱状图 + names = list(results.keys()) + accs = [results[n]['accuracy'] for n in names] + labels_short = ['γ=0', 'γ=固定', 'γ=auto'] + if 'supervised' in results: + labels_short.append('监督式') + axes[0, 2].bar(labels_short, accs, color=['blue', 'red', 'green', 'orange'][:len(accs)]) + axes[0, 2].set_ylabel('准确率') + axes[0, 2].set_title('分类准确率对比') + axes[0, 2].set_ylim(0, 1.1) + + # 图 4-6: 核矩阵热力图 + for idx, (name, cmap, title_prefix) in enumerate([ + ('hermitian', 'Blues', '厄米'), + ('non_hermitian', 'Reds', '非厄米'), + ('non_hermitian_auto', 'Greens', '非厄米(auto)') + ]): + if name in results: + kernel = NonHermitianQuantumKernel( + n_qbits=2, gamma=0.0 if name == 'hermitian' else ('auto' if 'auto' in name else 0.2), + psd_method='auto', normalize=False + ) + K = kernel.evaluate(x_vec=X_train) + im = axes[1, idx].imshow(K, cmap=cmap, interpolation='nearest') + axes[1, idx].set_title(f'{title_prefix}核矩阵') + plt.colorbar(im, ax=axes[1, idx], fraction=0.046) + kernel.close() + + plt.tight_layout() + plt.savefig('/workspace/non_hermitian_qsvm_v2_analysis.png', dpi=150, bbox_inches='tight') + print(f"\n可视化已保存到: /workspace/non_hermitian_qsvm_v2_analysis.png") + + print("\n" + "=" * 65) + print("v2 演示完成!") + print("=" * 65)