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)