├── .gitattributes
├── LICENSE
├── README.md
├── doc
├── Makefile
├── build
│ ├── doctrees
│ │ ├── environment.pickle
│ │ ├── index.doctree
│ │ ├── modules.doctree
│ │ └── pysvm.doctree
│ └── html
│ │ ├── .buildinfo
│ │ ├── _sources
│ │ ├── index.rst.txt
│ │ ├── modules.rst.txt
│ │ └── pysvm.rst.txt
│ │ ├── _static
│ │ ├── basic.css
│ │ ├── css
│ │ │ ├── badge_only.css
│ │ │ ├── fonts
│ │ │ │ ├── Roboto-Slab-Bold.woff
│ │ │ │ ├── Roboto-Slab-Bold.woff2
│ │ │ │ ├── Roboto-Slab-Regular.woff
│ │ │ │ ├── Roboto-Slab-Regular.woff2
│ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ ├── fontawesome-webfont.svg
│ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ ├── fontawesome-webfont.woff
│ │ │ │ ├── fontawesome-webfont.woff2
│ │ │ │ ├── lato-bold-italic.woff
│ │ │ │ ├── lato-bold-italic.woff2
│ │ │ │ ├── lato-bold.woff
│ │ │ │ ├── lato-bold.woff2
│ │ │ │ ├── lato-normal-italic.woff
│ │ │ │ ├── lato-normal-italic.woff2
│ │ │ │ ├── lato-normal.woff
│ │ │ │ └── lato-normal.woff2
│ │ │ └── theme.css
│ │ ├── doctools.js
│ │ ├── documentation_options.js
│ │ ├── file.png
│ │ ├── jquery-3.5.1.js
│ │ ├── jquery.js
│ │ ├── js
│ │ │ ├── badge_only.js
│ │ │ ├── html5shiv-printshiv.min.js
│ │ │ ├── html5shiv.min.js
│ │ │ └── theme.js
│ │ ├── language_data.js
│ │ ├── minus.png
│ │ ├── plus.png
│ │ ├── pygments.css
│ │ ├── searchtools.js
│ │ ├── translations.js
│ │ ├── underscore-1.13.1.js
│ │ └── underscore.js
│ │ ├── genindex.html
│ │ ├── index.html
│ │ ├── modules.html
│ │ ├── objects.inv
│ │ ├── py-modindex.html
│ │ ├── pysvm.html
│ │ ├── search.html
│ │ └── searchindex.js
├── make.bat
└── source
│ ├── conf.py
│ ├── index.rst
│ ├── modules.rst
│ └── pysvm.rst
├── pysvm
├── __init__.py
├── rff.py
├── solver.py
└── svm
│ ├── __init__.py
│ ├── oc_svm.py
│ ├── svc.py
│ └── svr.py
├── setup.py
├── src
├── oc_svm.png
├── visual_classify.png
└── visual_regression.png
└── tests
├── dataset_classify.py
├── dataset_regression.py
├── visual_classify.py
├── visual_outlier.py
└── visual_regression.py
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Welt Xing
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PySVM : A NumPy implementation of SVM based on SMO algorithm
2 |
3 | [](https://pepy.tech/project/pysvm)
4 | [](https://pepy.tech/project/pysvm)
5 | 
6 | 
7 | 
8 | 
9 |
10 | 实现LIBSVM中的SVM算法,对标sklearn中的SVM模块
11 |
12 | - [x] LinearSVC
13 | - [x] KernelSVC
14 | - [x] NuSVC
15 | - [x] LinearSVR
16 | - [x] KernelSVR
17 | - [x] NuSVR
18 | - [x] OneClassSVM
19 |
20 | 2021.11.05 : 加入了高斯核函数的RFF方法。
21 |
22 | 2022.01.27 : 通过向量化运算对算法进行提速,加入性能对比。
23 |
24 | 2022.01.28 : 加入缓存机制,解决大数据下Q矩阵的缓存问题,参考。
25 |
26 | 2022.01.30 : 删除Solver类,设计针对特定问题的SMO算法。
27 |
28 | 2022.02.01 : 修改SVR算法中的错误。
29 |
30 | 2022.05.27 : 重构代码,将SMO算法求解和SVM解耦,更容易解读。
31 |
32 | ## 主要算法
33 |
34 | Python(NumPy)实现SMO算法,用于求解对偶问题
35 |
36 | $$
37 | \begin{aligned}
38 | \min_{\pmb\alpha}\quad\frac12\pmb\alpha^T\pmb Q\pmb\alpha+\pmb p^T\pmb\alpha\\
39 | \text{s.t.}\quad \begin{aligned}\pmb y^T\pmb\alpha&=0\\
40 | 0\leq\alpha_i&\leq C,\forall i
41 | \end{aligned}
42 | \end{aligned}
43 | $$
44 |
45 | 和
46 |
47 | $$
48 | \begin{aligned}
49 | \min_{\pmb\alpha}\quad\frac12\pmb\alpha^T\pmb Q\pmb\alpha+\pmb p^T\pmb\alpha\\
50 | \text{s.t.}
51 | \begin{aligned}\quad \pmb y^T\pmb\alpha&=\delta_1\\
52 | \pmb e^T\pmb\alpha&=\sum_{i}\alpha_i=\delta_2\\
53 | 0\leq&\alpha_i\leq C,\forall i
54 | \end{aligned}
55 | \end{aligned}
56 | $$
57 |
58 | 从而实现支持向量机分类、回归以及异常检测。
59 |
60 | ## Framework
61 |
62 | 我们实现了线性SVM,核SVM,用于分类,回归和异常检测:
63 |
64 | ```mermaid
65 | graph LR
66 | PySVM --> LinearSVM
67 | PySVM --> KernelSVM
68 | PySVM --> NuSVM
69 | LinearSVM --> LinearSVC
70 | LinearSVM --> LinearSVR
71 | KernelSVM --> KernelSVC
72 | KernelSVM --> KernelSVR
73 | KernelSVM --> OneClassSVM
74 | NuSVM --> NuSVC
75 | NuSVM --> NuSVR
76 | ```
77 |
78 | 设计框架:
79 |
80 | ```mermaid
81 | graph LR
82 | cache(LRU Cache) --> Solver
83 | Solver --> LinearSVM
84 | LinearSVM --> KernelSVM
85 | Kernel --> KernelSVM
86 | RFF --> Kernel
87 | mc(sklearn.multiclass) --> LinearSVM
88 | mc --> NuSVM
89 | NuSolver --> NuSVM
90 | Kernel --> NuSVM
91 | cache --> NuSolver
92 | ```
93 |
94 | 其中RFF表示随机傅里叶特征,LRU Cache缓存机制用于处理极大数据的场景。
95 |
96 | ## Install
97 |
98 | ```bash
99 | pip install pysvm
100 | ```
101 |
102 | 或源码安装
103 |
104 | ```bash
105 | git clone https://github.com/Kaslanarian/PySVM
106 | cd PySVM
107 | python setup.py install
108 | ```
109 |
110 | 运行一个简单例子
111 |
112 | ```python
113 | >>> from sklearn.datasets import load_iris
114 | >>> from pysvm import LinearSVC
115 | >>> X, y = load_iris(return_X_y=True)
116 | >>> X = (X - X.mean(0)) / X.std(0) # 标准化
117 | >>> clf = LinearSVC().fit(X, y) # 训练模型
118 | >>> clf.score(X, y) # 准确率
119 | 0.94
120 | ```
121 |
122 | ## Examples
123 |
124 | 在[`tests`](./tests)中,有5个例子,分别是:
125 |
126 | - [dataset_classify.py](./tests/dataset_classify.py), 使用三种SVM对sklearn自带数据集分类(默认参数、选取20%数据作为测试数据、数据经过标准化):
127 |
128 | | Accuracy | Iris | Wine | Breast Cancer | Digits |
129 | | :--------: | :-----: | :-----: | :-----------: | :-----: |
130 | | Linear SVC | 94.737% | 97.778% | 96.503% | 95.556% |
131 | | Kernel SVC | 97.368% | 97.778% | 96.503% | 98.222% |
132 | | NuSVC | 97.368% | 97.778% | 92.308% | 92.222% |
133 |
134 | - [dataset_regression.py](./tests/dataset_regression.py), 使用三种SVM对sklearn自带数据集回归(默认参数、选取20%数据作为测试数据、数据经过标准化):
135 |
136 | | R2 score | Boston | Diabetes |
137 | | :--------: | :----: | :------: |
138 | | Linear SVR | 0.6570 | 0.4537 |
139 | | Kernel SVR | 0.6992 | 0.1756 |
140 | | NuSVR | 0.6800 | 0.1459 |
141 |
142 | - [visual_classify.py](./tests/visual_classify.py),分别用LinearSVC和KernelSVC对人工构造的二分类数据集进行分类,画出分类结果图像和决策函数值图像:
143 |
144 | 
145 |
146 | - [visual_regression.py](./tests/visual_regression.py)用三种SVR拟合三种不同的数据:线性数据,二次函数和三角函数:
147 |
148 | 
149 |
150 | - [visual_outlier.py](./tests/visual_outlier.py)用OneClassSVM进行异常检测:
151 |
152 | 
153 |
154 | ## Citation
155 |
156 | If you used this package in your research and are interested in citing it here's how you do it:
157 |
158 | ```
159 | @Misc{xing2022pysvm,
160 | author = {Xing, Cunyuan},
161 | title = {{PySVM}: A NumPy implementation of SVM based on SMO algorithm},
162 | year = {2022},
163 | url = " https://github.com/Kaslanarian/PySVM"
164 | }
165 | ```
166 |
167 | ## Reference
168 |
169 | - Chang, Chih-Chung, and Chih-Jen Lin. "LIBSVM: a library for support vector machines." ACM transactions on intelligent systems and technology (TIST) 2.3 (2011): 1-27.
170 | - https://github.com/Kaslanarian/libsvm-sc-reading : 阅读LibSVM源码的知识整理与思考.
171 |
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = source
9 | BUILDDIR = build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/doc/build/doctrees/environment.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/doctrees/environment.pickle
--------------------------------------------------------------------------------
/doc/build/doctrees/index.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/doctrees/index.doctree
--------------------------------------------------------------------------------
/doc/build/doctrees/modules.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/doctrees/modules.doctree
--------------------------------------------------------------------------------
/doc/build/doctrees/pysvm.doctree:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/doctrees/pysvm.doctree
--------------------------------------------------------------------------------
/doc/build/html/.buildinfo:
--------------------------------------------------------------------------------
1 | # Sphinx build info version 1
2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
3 | config: 413e569e4f5b9ea0a17bed677037dfef
4 | tags: 645f666f9bcd5a90fca523b33c5a78b7
5 |
--------------------------------------------------------------------------------
/doc/build/html/_sources/index.rst.txt:
--------------------------------------------------------------------------------
1 | .. PySVM documentation master file, created by
2 | sphinx-quickstart on Sat May 28 10:21:39 2022.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to PySVM's documentation!
7 | =================================
8 |
9 | .. toctree::
10 | :maxdepth: 2
11 | :caption: Contents:
12 |
13 |
14 |
15 | Indices and tables
16 | ==================
17 |
18 | * :ref:`genindex`
19 | * :ref:`modindex`
20 | * :ref:`search`
21 |
--------------------------------------------------------------------------------
/doc/build/html/_sources/modules.rst.txt:
--------------------------------------------------------------------------------
1 | pysvm
2 | =====
3 |
4 | .. toctree::
5 | :maxdepth: 4
6 |
7 | pysvm
8 |
--------------------------------------------------------------------------------
/doc/build/html/_sources/pysvm.rst.txt:
--------------------------------------------------------------------------------
1 | pysvm package
2 | =============
3 |
4 | Submodules
5 | ----------
6 |
7 | pysvm.rff module
8 | ----------------
9 |
10 | .. automodule:: pysvm.rff
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | pysvm.solver module
16 | -------------------
17 |
18 | .. automodule:: pysvm.solver
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | pysvm.svm module
24 | ----------------
25 |
26 | .. automodule:: pysvm.svm
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 | Module contents
32 | ---------------
33 |
34 | .. automodule:: pysvm
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
--------------------------------------------------------------------------------
/doc/build/html/_static/basic.css:
--------------------------------------------------------------------------------
1 | /*
2 | * basic.css
3 | * ~~~~~~~~~
4 | *
5 | * Sphinx stylesheet -- basic theme.
6 | *
7 | * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | /* -- main layout ----------------------------------------------------------- */
13 |
14 | div.clearer {
15 | clear: both;
16 | }
17 |
18 | div.section::after {
19 | display: block;
20 | content: '';
21 | clear: left;
22 | }
23 |
24 | /* -- relbar ---------------------------------------------------------------- */
25 |
26 | div.related {
27 | width: 100%;
28 | font-size: 90%;
29 | }
30 |
31 | div.related h3 {
32 | display: none;
33 | }
34 |
35 | div.related ul {
36 | margin: 0;
37 | padding: 0 0 0 10px;
38 | list-style: none;
39 | }
40 |
41 | div.related li {
42 | display: inline;
43 | }
44 |
45 | div.related li.right {
46 | float: right;
47 | margin-right: 5px;
48 | }
49 |
50 | /* -- sidebar --------------------------------------------------------------- */
51 |
52 | div.sphinxsidebarwrapper {
53 | padding: 10px 5px 0 10px;
54 | }
55 |
56 | div.sphinxsidebar {
57 | float: left;
58 | width: 230px;
59 | margin-left: -100%;
60 | font-size: 90%;
61 | word-wrap: break-word;
62 | overflow-wrap : break-word;
63 | }
64 |
65 | div.sphinxsidebar ul {
66 | list-style: none;
67 | }
68 |
69 | div.sphinxsidebar ul ul,
70 | div.sphinxsidebar ul.want-points {
71 | margin-left: 20px;
72 | list-style: square;
73 | }
74 |
75 | div.sphinxsidebar ul ul {
76 | margin-top: 0;
77 | margin-bottom: 0;
78 | }
79 |
80 | div.sphinxsidebar form {
81 | margin-top: 10px;
82 | }
83 |
84 | div.sphinxsidebar input {
85 | border: 1px solid #98dbcc;
86 | font-family: sans-serif;
87 | font-size: 1em;
88 | }
89 |
90 | div.sphinxsidebar #searchbox form.search {
91 | overflow: hidden;
92 | }
93 |
94 | div.sphinxsidebar #searchbox input[type="text"] {
95 | float: left;
96 | width: 80%;
97 | padding: 0.25em;
98 | box-sizing: border-box;
99 | }
100 |
101 | div.sphinxsidebar #searchbox input[type="submit"] {
102 | float: left;
103 | width: 20%;
104 | border-left: none;
105 | padding: 0.25em;
106 | box-sizing: border-box;
107 | }
108 |
109 |
110 | img {
111 | border: 0;
112 | max-width: 100%;
113 | }
114 |
115 | /* -- search page ----------------------------------------------------------- */
116 |
117 | ul.search {
118 | margin: 10px 0 0 20px;
119 | padding: 0;
120 | }
121 |
122 | ul.search li {
123 | padding: 5px 0 5px 20px;
124 | background-image: url(file.png);
125 | background-repeat: no-repeat;
126 | background-position: 0 7px;
127 | }
128 |
129 | ul.search li a {
130 | font-weight: bold;
131 | }
132 |
133 | ul.search li p.context {
134 | color: #888;
135 | margin: 2px 0 0 30px;
136 | text-align: left;
137 | }
138 |
139 | ul.keywordmatches li.goodmatch a {
140 | font-weight: bold;
141 | }
142 |
143 | /* -- index page ------------------------------------------------------------ */
144 |
145 | table.contentstable {
146 | width: 90%;
147 | margin-left: auto;
148 | margin-right: auto;
149 | }
150 |
151 | table.contentstable p.biglink {
152 | line-height: 150%;
153 | }
154 |
155 | a.biglink {
156 | font-size: 1.3em;
157 | }
158 |
159 | span.linkdescr {
160 | font-style: italic;
161 | padding-top: 5px;
162 | font-size: 90%;
163 | }
164 |
165 | /* -- general index --------------------------------------------------------- */
166 |
167 | table.indextable {
168 | width: 100%;
169 | }
170 |
171 | table.indextable td {
172 | text-align: left;
173 | vertical-align: top;
174 | }
175 |
176 | table.indextable ul {
177 | margin-top: 0;
178 | margin-bottom: 0;
179 | list-style-type: none;
180 | }
181 |
182 | table.indextable > tbody > tr > td > ul {
183 | padding-left: 0em;
184 | }
185 |
186 | table.indextable tr.pcap {
187 | height: 10px;
188 | }
189 |
190 | table.indextable tr.cap {
191 | margin-top: 10px;
192 | background-color: #f2f2f2;
193 | }
194 |
195 | img.toggler {
196 | margin-right: 3px;
197 | margin-top: 3px;
198 | cursor: pointer;
199 | }
200 |
201 | div.modindex-jumpbox {
202 | border-top: 1px solid #ddd;
203 | border-bottom: 1px solid #ddd;
204 | margin: 1em 0 1em 0;
205 | padding: 0.4em;
206 | }
207 |
208 | div.genindex-jumpbox {
209 | border-top: 1px solid #ddd;
210 | border-bottom: 1px solid #ddd;
211 | margin: 1em 0 1em 0;
212 | padding: 0.4em;
213 | }
214 |
215 | /* -- domain module index --------------------------------------------------- */
216 |
217 | table.modindextable td {
218 | padding: 2px;
219 | border-collapse: collapse;
220 | }
221 |
222 | /* -- general body styles --------------------------------------------------- */
223 |
224 | div.body {
225 | min-width: 450px;
226 | max-width: 800px;
227 | }
228 |
229 | div.body p, div.body dd, div.body li, div.body blockquote {
230 | -moz-hyphens: auto;
231 | -ms-hyphens: auto;
232 | -webkit-hyphens: auto;
233 | hyphens: auto;
234 | }
235 |
236 | a.headerlink {
237 | visibility: hidden;
238 | }
239 |
240 | a.brackets:before,
241 | span.brackets > a:before{
242 | content: "[";
243 | }
244 |
245 | a.brackets:after,
246 | span.brackets > a:after {
247 | content: "]";
248 | }
249 |
250 | h1:hover > a.headerlink,
251 | h2:hover > a.headerlink,
252 | h3:hover > a.headerlink,
253 | h4:hover > a.headerlink,
254 | h5:hover > a.headerlink,
255 | h6:hover > a.headerlink,
256 | dt:hover > a.headerlink,
257 | caption:hover > a.headerlink,
258 | p.caption:hover > a.headerlink,
259 | div.code-block-caption:hover > a.headerlink {
260 | visibility: visible;
261 | }
262 |
263 | div.body p.caption {
264 | text-align: inherit;
265 | }
266 |
267 | div.body td {
268 | text-align: left;
269 | }
270 |
271 | .first {
272 | margin-top: 0 !important;
273 | }
274 |
275 | p.rubric {
276 | margin-top: 30px;
277 | font-weight: bold;
278 | }
279 |
280 | img.align-left, figure.align-left, .figure.align-left, object.align-left {
281 | clear: left;
282 | float: left;
283 | margin-right: 1em;
284 | }
285 |
286 | img.align-right, figure.align-right, .figure.align-right, object.align-right {
287 | clear: right;
288 | float: right;
289 | margin-left: 1em;
290 | }
291 |
292 | img.align-center, figure.align-center, .figure.align-center, object.align-center {
293 | display: block;
294 | margin-left: auto;
295 | margin-right: auto;
296 | }
297 |
298 | img.align-default, figure.align-default, .figure.align-default {
299 | display: block;
300 | margin-left: auto;
301 | margin-right: auto;
302 | }
303 |
304 | .align-left {
305 | text-align: left;
306 | }
307 |
308 | .align-center {
309 | text-align: center;
310 | }
311 |
312 | .align-default {
313 | text-align: center;
314 | }
315 |
316 | .align-right {
317 | text-align: right;
318 | }
319 |
320 | /* -- sidebars -------------------------------------------------------------- */
321 |
322 | div.sidebar,
323 | aside.sidebar {
324 | margin: 0 0 0.5em 1em;
325 | border: 1px solid #ddb;
326 | padding: 7px;
327 | background-color: #ffe;
328 | width: 40%;
329 | float: right;
330 | clear: right;
331 | overflow-x: auto;
332 | }
333 |
334 | p.sidebar-title {
335 | font-weight: bold;
336 | }
337 |
338 | div.admonition, div.topic, blockquote {
339 | clear: left;
340 | }
341 |
342 | /* -- topics ---------------------------------------------------------------- */
343 |
344 | div.topic {
345 | border: 1px solid #ccc;
346 | padding: 7px;
347 | margin: 10px 0 10px 0;
348 | }
349 |
350 | p.topic-title {
351 | font-size: 1.1em;
352 | font-weight: bold;
353 | margin-top: 10px;
354 | }
355 |
356 | /* -- admonitions ----------------------------------------------------------- */
357 |
358 | div.admonition {
359 | margin-top: 10px;
360 | margin-bottom: 10px;
361 | padding: 7px;
362 | }
363 |
364 | div.admonition dt {
365 | font-weight: bold;
366 | }
367 |
368 | p.admonition-title {
369 | margin: 0px 10px 5px 0px;
370 | font-weight: bold;
371 | }
372 |
373 | div.body p.centered {
374 | text-align: center;
375 | margin-top: 25px;
376 | }
377 |
378 | /* -- content of sidebars/topics/admonitions -------------------------------- */
379 |
380 | div.sidebar > :last-child,
381 | aside.sidebar > :last-child,
382 | div.topic > :last-child,
383 | div.admonition > :last-child {
384 | margin-bottom: 0;
385 | }
386 |
387 | div.sidebar::after,
388 | aside.sidebar::after,
389 | div.topic::after,
390 | div.admonition::after,
391 | blockquote::after {
392 | display: block;
393 | content: '';
394 | clear: both;
395 | }
396 |
397 | /* -- tables ---------------------------------------------------------------- */
398 |
399 | table.docutils {
400 | margin-top: 10px;
401 | margin-bottom: 10px;
402 | border: 0;
403 | border-collapse: collapse;
404 | }
405 |
406 | table.align-center {
407 | margin-left: auto;
408 | margin-right: auto;
409 | }
410 |
411 | table.align-default {
412 | margin-left: auto;
413 | margin-right: auto;
414 | }
415 |
416 | table caption span.caption-number {
417 | font-style: italic;
418 | }
419 |
420 | table caption span.caption-text {
421 | }
422 |
423 | table.docutils td, table.docutils th {
424 | padding: 1px 8px 1px 5px;
425 | border-top: 0;
426 | border-left: 0;
427 | border-right: 0;
428 | border-bottom: 1px solid #aaa;
429 | }
430 |
431 | table.footnote td, table.footnote th {
432 | border: 0 !important;
433 | }
434 |
435 | th {
436 | text-align: left;
437 | padding-right: 5px;
438 | }
439 |
440 | table.citation {
441 | border-left: solid 1px gray;
442 | margin-left: 1px;
443 | }
444 |
445 | table.citation td {
446 | border-bottom: none;
447 | }
448 |
449 | th > :first-child,
450 | td > :first-child {
451 | margin-top: 0px;
452 | }
453 |
454 | th > :last-child,
455 | td > :last-child {
456 | margin-bottom: 0px;
457 | }
458 |
459 | /* -- figures --------------------------------------------------------------- */
460 |
461 | div.figure, figure {
462 | margin: 0.5em;
463 | padding: 0.5em;
464 | }
465 |
466 | div.figure p.caption, figcaption {
467 | padding: 0.3em;
468 | }
469 |
470 | div.figure p.caption span.caption-number,
471 | figcaption span.caption-number {
472 | font-style: italic;
473 | }
474 |
475 | div.figure p.caption span.caption-text,
476 | figcaption span.caption-text {
477 | }
478 |
479 | /* -- field list styles ----------------------------------------------------- */
480 |
481 | table.field-list td, table.field-list th {
482 | border: 0 !important;
483 | }
484 |
485 | .field-list ul {
486 | margin: 0;
487 | padding-left: 1em;
488 | }
489 |
490 | .field-list p {
491 | margin: 0;
492 | }
493 |
494 | .field-name {
495 | -moz-hyphens: manual;
496 | -ms-hyphens: manual;
497 | -webkit-hyphens: manual;
498 | hyphens: manual;
499 | }
500 |
501 | /* -- hlist styles ---------------------------------------------------------- */
502 |
503 | table.hlist {
504 | margin: 1em 0;
505 | }
506 |
507 | table.hlist td {
508 | vertical-align: top;
509 | }
510 |
511 | /* -- object description styles --------------------------------------------- */
512 |
513 | .sig {
514 | font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
515 | }
516 |
517 | .sig-name, code.descname {
518 | background-color: transparent;
519 | font-weight: bold;
520 | }
521 |
522 | .sig-name {
523 | font-size: 1.1em;
524 | }
525 |
526 | code.descname {
527 | font-size: 1.2em;
528 | }
529 |
530 | .sig-prename, code.descclassname {
531 | background-color: transparent;
532 | }
533 |
534 | .optional {
535 | font-size: 1.3em;
536 | }
537 |
538 | .sig-paren {
539 | font-size: larger;
540 | }
541 |
542 | .sig-param.n {
543 | font-style: italic;
544 | }
545 |
546 | /* C++ specific styling */
547 |
548 | .sig-inline.c-texpr,
549 | .sig-inline.cpp-texpr {
550 | font-family: unset;
551 | }
552 |
553 | .sig.c .k, .sig.c .kt,
554 | .sig.cpp .k, .sig.cpp .kt {
555 | color: #0033B3;
556 | }
557 |
558 | .sig.c .m,
559 | .sig.cpp .m {
560 | color: #1750EB;
561 | }
562 |
563 | .sig.c .s, .sig.c .sc,
564 | .sig.cpp .s, .sig.cpp .sc {
565 | color: #067D17;
566 | }
567 |
568 |
569 | /* -- other body styles ----------------------------------------------------- */
570 |
571 | ol.arabic {
572 | list-style: decimal;
573 | }
574 |
575 | ol.loweralpha {
576 | list-style: lower-alpha;
577 | }
578 |
579 | ol.upperalpha {
580 | list-style: upper-alpha;
581 | }
582 |
583 | ol.lowerroman {
584 | list-style: lower-roman;
585 | }
586 |
587 | ol.upperroman {
588 | list-style: upper-roman;
589 | }
590 |
591 | :not(li) > ol > li:first-child > :first-child,
592 | :not(li) > ul > li:first-child > :first-child {
593 | margin-top: 0px;
594 | }
595 |
596 | :not(li) > ol > li:last-child > :last-child,
597 | :not(li) > ul > li:last-child > :last-child {
598 | margin-bottom: 0px;
599 | }
600 |
601 | ol.simple ol p,
602 | ol.simple ul p,
603 | ul.simple ol p,
604 | ul.simple ul p {
605 | margin-top: 0;
606 | }
607 |
608 | ol.simple > li:not(:first-child) > p,
609 | ul.simple > li:not(:first-child) > p {
610 | margin-top: 0;
611 | }
612 |
613 | ol.simple p,
614 | ul.simple p {
615 | margin-bottom: 0;
616 | }
617 |
618 | dl.footnote > dt,
619 | dl.citation > dt {
620 | float: left;
621 | margin-right: 0.5em;
622 | }
623 |
624 | dl.footnote > dd,
625 | dl.citation > dd {
626 | margin-bottom: 0em;
627 | }
628 |
629 | dl.footnote > dd:after,
630 | dl.citation > dd:after {
631 | content: "";
632 | clear: both;
633 | }
634 |
635 | dl.field-list {
636 | display: grid;
637 | grid-template-columns: fit-content(30%) auto;
638 | }
639 |
640 | dl.field-list > dt {
641 | font-weight: bold;
642 | word-break: break-word;
643 | padding-left: 0.5em;
644 | padding-right: 5px;
645 | }
646 |
647 | dl.field-list > dt:after {
648 | content: ":";
649 | }
650 |
651 | dl.field-list > dd {
652 | padding-left: 0.5em;
653 | margin-top: 0em;
654 | margin-left: 0em;
655 | margin-bottom: 0em;
656 | }
657 |
658 | dl {
659 | margin-bottom: 15px;
660 | }
661 |
662 | dd > :first-child {
663 | margin-top: 0px;
664 | }
665 |
666 | dd ul, dd table {
667 | margin-bottom: 10px;
668 | }
669 |
670 | dd {
671 | margin-top: 3px;
672 | margin-bottom: 10px;
673 | margin-left: 30px;
674 | }
675 |
676 | dl > dd:last-child,
677 | dl > dd:last-child > :last-child {
678 | margin-bottom: 0;
679 | }
680 |
681 | dt:target, span.highlighted {
682 | background-color: #fbe54e;
683 | }
684 |
685 | rect.highlighted {
686 | fill: #fbe54e;
687 | }
688 |
689 | dl.glossary dt {
690 | font-weight: bold;
691 | font-size: 1.1em;
692 | }
693 |
694 | .versionmodified {
695 | font-style: italic;
696 | }
697 |
698 | .system-message {
699 | background-color: #fda;
700 | padding: 5px;
701 | border: 3px solid red;
702 | }
703 |
704 | .footnote:target {
705 | background-color: #ffa;
706 | }
707 |
708 | .line-block {
709 | display: block;
710 | margin-top: 1em;
711 | margin-bottom: 1em;
712 | }
713 |
714 | .line-block .line-block {
715 | margin-top: 0;
716 | margin-bottom: 0;
717 | margin-left: 1.5em;
718 | }
719 |
720 | .guilabel, .menuselection {
721 | font-family: sans-serif;
722 | }
723 |
724 | .accelerator {
725 | text-decoration: underline;
726 | }
727 |
728 | .classifier {
729 | font-style: oblique;
730 | }
731 |
732 | .classifier:before {
733 | font-style: normal;
734 | margin: 0 0.5em;
735 | content: ":";
736 | display: inline-block;
737 | }
738 |
739 | abbr, acronym {
740 | border-bottom: dotted 1px;
741 | cursor: help;
742 | }
743 |
744 | /* -- code displays --------------------------------------------------------- */
745 |
746 | pre {
747 | overflow: auto;
748 | overflow-y: hidden; /* fixes display issues on Chrome browsers */
749 | }
750 |
751 | pre, div[class*="highlight-"] {
752 | clear: both;
753 | }
754 |
755 | span.pre {
756 | -moz-hyphens: none;
757 | -ms-hyphens: none;
758 | -webkit-hyphens: none;
759 | hyphens: none;
760 | white-space: nowrap;
761 | }
762 |
763 | div[class*="highlight-"] {
764 | margin: 1em 0;
765 | }
766 |
767 | td.linenos pre {
768 | border: 0;
769 | background-color: transparent;
770 | color: #aaa;
771 | }
772 |
773 | table.highlighttable {
774 | display: block;
775 | }
776 |
777 | table.highlighttable tbody {
778 | display: block;
779 | }
780 |
781 | table.highlighttable tr {
782 | display: flex;
783 | }
784 |
785 | table.highlighttable td {
786 | margin: 0;
787 | padding: 0;
788 | }
789 |
790 | table.highlighttable td.linenos {
791 | padding-right: 0.5em;
792 | }
793 |
794 | table.highlighttable td.code {
795 | flex: 1;
796 | overflow: hidden;
797 | }
798 |
799 | .highlight .hll {
800 | display: block;
801 | }
802 |
803 | div.highlight pre,
804 | table.highlighttable pre {
805 | margin: 0;
806 | }
807 |
808 | div.code-block-caption + div {
809 | margin-top: 0;
810 | }
811 |
812 | div.code-block-caption {
813 | margin-top: 1em;
814 | padding: 2px 5px;
815 | font-size: small;
816 | }
817 |
818 | div.code-block-caption code {
819 | background-color: transparent;
820 | }
821 |
822 | table.highlighttable td.linenos,
823 | span.linenos,
824 | div.highlight span.gp { /* gp: Generic.Prompt */
825 | user-select: none;
826 | -webkit-user-select: text; /* Safari fallback only */
827 | -webkit-user-select: none; /* Chrome/Safari */
828 | -moz-user-select: none; /* Firefox */
829 | -ms-user-select: none; /* IE10+ */
830 | }
831 |
832 | div.code-block-caption span.caption-number {
833 | padding: 0.1em 0.3em;
834 | font-style: italic;
835 | }
836 |
837 | div.code-block-caption span.caption-text {
838 | }
839 |
840 | div.literal-block-wrapper {
841 | margin: 1em 0;
842 | }
843 |
844 | code.xref, a code {
845 | background-color: transparent;
846 | font-weight: bold;
847 | }
848 |
849 | h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
850 | background-color: transparent;
851 | }
852 |
853 | .viewcode-link {
854 | float: right;
855 | }
856 |
857 | .viewcode-back {
858 | float: right;
859 | font-family: sans-serif;
860 | }
861 |
862 | div.viewcode-block:target {
863 | margin: -1px -10px;
864 | padding: 0 10px;
865 | }
866 |
867 | /* -- math display ---------------------------------------------------------- */
868 |
869 | img.math {
870 | vertical-align: middle;
871 | }
872 |
873 | div.body div.math p {
874 | text-align: center;
875 | }
876 |
877 | span.eqno {
878 | float: right;
879 | }
880 |
881 | span.eqno a.headerlink {
882 | position: absolute;
883 | z-index: 1;
884 | }
885 |
886 | div.math:hover a.headerlink {
887 | visibility: visible;
888 | }
889 |
890 | /* -- printout stylesheet --------------------------------------------------- */
891 |
892 | @media print {
893 | div.document,
894 | div.documentwrapper,
895 | div.bodywrapper {
896 | margin: 0 !important;
897 | width: 100%;
898 | }
899 |
900 | div.sphinxsidebar,
901 | div.related,
902 | div.footer,
903 | #top-link {
904 | display: none;
905 | }
906 | }
--------------------------------------------------------------------------------
/doc/build/html/_static/css/badge_only.css:
--------------------------------------------------------------------------------
1 | .fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/Roboto-Slab-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/Roboto-Slab-Bold.woff
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/Roboto-Slab-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/Roboto-Slab-Bold.woff2
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/Roboto-Slab-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/Roboto-Slab-Regular.woff
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/Roboto-Slab-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/Roboto-Slab-Regular.woff2
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/lato-bold-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/lato-bold-italic.woff
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/lato-bold-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/lato-bold-italic.woff2
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/lato-bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/lato-bold.woff
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/lato-bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/lato-bold.woff2
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/lato-normal-italic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/lato-normal-italic.woff
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/lato-normal-italic.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/lato-normal-italic.woff2
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/lato-normal.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/lato-normal.woff
--------------------------------------------------------------------------------
/doc/build/html/_static/css/fonts/lato-normal.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/css/fonts/lato-normal.woff2
--------------------------------------------------------------------------------
/doc/build/html/_static/doctools.js:
--------------------------------------------------------------------------------
1 | /*
2 | * doctools.js
3 | * ~~~~~~~~~~~
4 | *
5 | * Sphinx JavaScript utilities for all documentation.
6 | *
7 | * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | /**
13 | * select a different prefix for underscore
14 | */
15 | $u = _.noConflict();
16 |
17 | /**
18 | * make the code below compatible with browsers without
19 | * an installed firebug like debugger
20 | if (!window.console || !console.firebug) {
21 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
22 | "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
23 | "profile", "profileEnd"];
24 | window.console = {};
25 | for (var i = 0; i < names.length; ++i)
26 | window.console[names[i]] = function() {};
27 | }
28 | */
29 |
30 | /**
31 | * small helper function to urldecode strings
32 | *
33 | * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
34 | */
35 | jQuery.urldecode = function(x) {
36 | if (!x) {
37 | return x
38 | }
39 | return decodeURIComponent(x.replace(/\+/g, ' '));
40 | };
41 |
42 | /**
43 | * small helper function to urlencode strings
44 | */
45 | jQuery.urlencode = encodeURIComponent;
46 |
47 | /**
48 | * This function returns the parsed url parameters of the
49 | * current request. Multiple values per key are supported,
50 | * it will always return arrays of strings for the value parts.
51 | */
52 | jQuery.getQueryParameters = function(s) {
53 | if (typeof s === 'undefined')
54 | s = document.location.search;
55 | var parts = s.substr(s.indexOf('?') + 1).split('&');
56 | var result = {};
57 | for (var i = 0; i < parts.length; i++) {
58 | var tmp = parts[i].split('=', 2);
59 | var key = jQuery.urldecode(tmp[0]);
60 | var value = jQuery.urldecode(tmp[1]);
61 | if (key in result)
62 | result[key].push(value);
63 | else
64 | result[key] = [value];
65 | }
66 | return result;
67 | };
68 |
69 | /**
70 | * highlight a given string on a jquery object by wrapping it in
71 | * span elements with the given class name.
72 | */
73 | jQuery.fn.highlightText = function(text, className) {
74 | function highlight(node, addItems) {
75 | if (node.nodeType === 3) {
76 | var val = node.nodeValue;
77 | var pos = val.toLowerCase().indexOf(text);
78 | if (pos >= 0 &&
79 | !jQuery(node.parentNode).hasClass(className) &&
80 | !jQuery(node.parentNode).hasClass("nohighlight")) {
81 | var span;
82 | var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
83 | if (isInSVG) {
84 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
85 | } else {
86 | span = document.createElement("span");
87 | span.className = className;
88 | }
89 | span.appendChild(document.createTextNode(val.substr(pos, text.length)));
90 | node.parentNode.insertBefore(span, node.parentNode.insertBefore(
91 | document.createTextNode(val.substr(pos + text.length)),
92 | node.nextSibling));
93 | node.nodeValue = val.substr(0, pos);
94 | if (isInSVG) {
95 | var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
96 | var bbox = node.parentElement.getBBox();
97 | rect.x.baseVal.value = bbox.x;
98 | rect.y.baseVal.value = bbox.y;
99 | rect.width.baseVal.value = bbox.width;
100 | rect.height.baseVal.value = bbox.height;
101 | rect.setAttribute('class', className);
102 | addItems.push({
103 | "parent": node.parentNode,
104 | "target": rect});
105 | }
106 | }
107 | }
108 | else if (!jQuery(node).is("button, select, textarea")) {
109 | jQuery.each(node.childNodes, function() {
110 | highlight(this, addItems);
111 | });
112 | }
113 | }
114 | var addItems = [];
115 | var result = this.each(function() {
116 | highlight(this, addItems);
117 | });
118 | for (var i = 0; i < addItems.length; ++i) {
119 | jQuery(addItems[i].parent).before(addItems[i].target);
120 | }
121 | return result;
122 | };
123 |
124 | /*
125 | * backward compatibility for jQuery.browser
126 | * This will be supported until firefox bug is fixed.
127 | */
128 | if (!jQuery.browser) {
129 | jQuery.uaMatch = function(ua) {
130 | ua = ua.toLowerCase();
131 |
132 | var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
133 | /(webkit)[ \/]([\w.]+)/.exec(ua) ||
134 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
135 | /(msie) ([\w.]+)/.exec(ua) ||
136 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
137 | [];
138 |
139 | return {
140 | browser: match[ 1 ] || "",
141 | version: match[ 2 ] || "0"
142 | };
143 | };
144 | jQuery.browser = {};
145 | jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
146 | }
147 |
148 | /**
149 | * Small JavaScript module for the documentation.
150 | */
151 | var Documentation = {
152 |
153 | init : function() {
154 | this.fixFirefoxAnchorBug();
155 | this.highlightSearchWords();
156 | this.initIndexTable();
157 | this.initOnKeyListeners();
158 | },
159 |
160 | /**
161 | * i18n support
162 | */
163 | TRANSLATIONS : {},
164 | PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; },
165 | LOCALE : 'unknown',
166 |
167 | // gettext and ngettext don't access this so that the functions
168 | // can safely bound to a different name (_ = Documentation.gettext)
169 | gettext : function(string) {
170 | var translated = Documentation.TRANSLATIONS[string];
171 | if (typeof translated === 'undefined')
172 | return string;
173 | return (typeof translated === 'string') ? translated : translated[0];
174 | },
175 |
176 | ngettext : function(singular, plural, n) {
177 | var translated = Documentation.TRANSLATIONS[singular];
178 | if (typeof translated === 'undefined')
179 | return (n == 1) ? singular : plural;
180 | return translated[Documentation.PLURALEXPR(n)];
181 | },
182 |
183 | addTranslations : function(catalog) {
184 | for (var key in catalog.messages)
185 | this.TRANSLATIONS[key] = catalog.messages[key];
186 | this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
187 | this.LOCALE = catalog.locale;
188 | },
189 |
190 | /**
191 | * add context elements like header anchor links
192 | */
193 | addContextElements : function() {
194 | $('div[id] > :header:first').each(function() {
195 | $('').
196 | attr('href', '#' + this.id).
197 | attr('title', _('Permalink to this headline')).
198 | appendTo(this);
199 | });
200 | $('dt[id]').each(function() {
201 | $('').
202 | attr('href', '#' + this.id).
203 | attr('title', _('Permalink to this definition')).
204 | appendTo(this);
205 | });
206 | },
207 |
208 | /**
209 | * workaround a firefox stupidity
210 | * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
211 | */
212 | fixFirefoxAnchorBug : function() {
213 | if (document.location.hash && $.browser.mozilla)
214 | window.setTimeout(function() {
215 | document.location.href += '';
216 | }, 10);
217 | },
218 |
219 | /**
220 | * highlight the search words provided in the url in the text
221 | */
222 | highlightSearchWords : function() {
223 | var params = $.getQueryParameters();
224 | var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
225 | if (terms.length) {
226 | var body = $('div.body');
227 | if (!body.length) {
228 | body = $('body');
229 | }
230 | window.setTimeout(function() {
231 | $.each(terms, function() {
232 | body.highlightText(this.toLowerCase(), 'highlighted');
233 | });
234 | }, 10);
235 | $('
' + _('Hide Search Matches') + '
')
237 | .appendTo($('#searchbox'));
238 | }
239 | },
240 |
241 | /**
242 | * init the domain index toggle buttons
243 | */
244 | initIndexTable : function() {
245 | var togglers = $('img.toggler').click(function() {
246 | var src = $(this).attr('src');
247 | var idnum = $(this).attr('id').substr(7);
248 | $('tr.cg-' + idnum).toggle();
249 | if (src.substr(-9) === 'minus.png')
250 | $(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
251 | else
252 | $(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
253 | }).css('display', '');
254 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
255 | togglers.click();
256 | }
257 | },
258 |
259 | /**
260 | * helper function to hide the search marks again
261 | */
262 | hideSearchWords : function() {
263 | $('#searchbox .highlight-link').fadeOut(300);
264 | $('span.highlighted').removeClass('highlighted');
265 | var url = new URL(window.location);
266 | url.searchParams.delete('highlight');
267 | window.history.replaceState({}, '', url);
268 | },
269 |
270 | /**
271 | * helper function to focus on search bar
272 | */
273 | focusSearchBar : function() {
274 | $('input[name=q]').first().focus();
275 | },
276 |
277 | /**
278 | * make the url absolute
279 | */
280 | makeURL : function(relativeURL) {
281 | return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
282 | },
283 |
284 | /**
285 | * get the current relative url
286 | */
287 | getCurrentURL : function() {
288 | var path = document.location.pathname;
289 | var parts = path.split(/\//);
290 | $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
291 | if (this === '..')
292 | parts.pop();
293 | });
294 | var url = parts.join('/');
295 | return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
296 | },
297 |
298 | initOnKeyListeners: function() {
299 | // only install a listener if it is really needed
300 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS &&
301 | !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS)
302 | return;
303 |
304 | $(document).keydown(function(event) {
305 | var activeElementType = document.activeElement.tagName;
306 | // don't navigate when in search box, textarea, dropdown or button
307 | if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT'
308 | && activeElementType !== 'BUTTON') {
309 | if (event.altKey || event.ctrlKey || event.metaKey)
310 | return;
311 |
312 | if (!event.shiftKey) {
313 | switch (event.key) {
314 | case 'ArrowLeft':
315 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS)
316 | break;
317 | var prevHref = $('link[rel="prev"]').prop('href');
318 | if (prevHref) {
319 | window.location.href = prevHref;
320 | return false;
321 | }
322 | break;
323 | case 'ArrowRight':
324 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS)
325 | break;
326 | var nextHref = $('link[rel="next"]').prop('href');
327 | if (nextHref) {
328 | window.location.href = nextHref;
329 | return false;
330 | }
331 | break;
332 | case 'Escape':
333 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS)
334 | break;
335 | Documentation.hideSearchWords();
336 | return false;
337 | }
338 | }
339 |
340 | // some keyboard layouts may need Shift to get /
341 | switch (event.key) {
342 | case '/':
343 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS)
344 | break;
345 | Documentation.focusSearchBar();
346 | return false;
347 | }
348 | }
349 | });
350 | }
351 | };
352 |
353 | // quick alias for translations
354 | _ = Documentation.gettext;
355 |
356 | $(document).ready(function() {
357 | Documentation.init();
358 | });
359 |
--------------------------------------------------------------------------------
/doc/build/html/_static/documentation_options.js:
--------------------------------------------------------------------------------
1 | var DOCUMENTATION_OPTIONS = {
2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
3 | VERSION: '0.1',
4 | LANGUAGE: 'zh_CN',
5 | COLLAPSE_INDEX: false,
6 | BUILDER: 'html',
7 | FILE_SUFFIX: '.html',
8 | LINK_SUFFIX: '.html',
9 | HAS_SOURCE: true,
10 | SOURCELINK_SUFFIX: '.txt',
11 | NAVIGATION_WITH_KEYS: false,
12 | SHOW_SEARCH_SUMMARY: true,
13 | ENABLE_SEARCH_SHORTCUTS: true,
14 | };
--------------------------------------------------------------------------------
/doc/build/html/_static/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/file.png
--------------------------------------------------------------------------------
/doc/build/html/_static/js/badge_only.js:
--------------------------------------------------------------------------------
1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}});
--------------------------------------------------------------------------------
/doc/build/html/_static/js/html5shiv-printshiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document);
--------------------------------------------------------------------------------
/doc/build/html/_static/js/html5shiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
--------------------------------------------------------------------------------
/doc/build/html/_static/js/theme.js:
--------------------------------------------------------------------------------
1 | !function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap(""),n("table.docutils.footnote").wrap(""),n("table.docutils.citation").wrap(""),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0
63 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
64 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
65 | var s_v = "^(" + C + ")?" + v; // vowel in stem
66 |
67 | this.stemWord = function (w) {
68 | var stem;
69 | var suffix;
70 | var firstch;
71 | var origword = w;
72 |
73 | if (w.length < 3)
74 | return w;
75 |
76 | var re;
77 | var re2;
78 | var re3;
79 | var re4;
80 |
81 | firstch = w.substr(0,1);
82 | if (firstch == "y")
83 | w = firstch.toUpperCase() + w.substr(1);
84 |
85 | // Step 1a
86 | re = /^(.+?)(ss|i)es$/;
87 | re2 = /^(.+?)([^s])s$/;
88 |
89 | if (re.test(w))
90 | w = w.replace(re,"$1$2");
91 | else if (re2.test(w))
92 | w = w.replace(re2,"$1$2");
93 |
94 | // Step 1b
95 | re = /^(.+?)eed$/;
96 | re2 = /^(.+?)(ed|ing)$/;
97 | if (re.test(w)) {
98 | var fp = re.exec(w);
99 | re = new RegExp(mgr0);
100 | if (re.test(fp[1])) {
101 | re = /.$/;
102 | w = w.replace(re,"");
103 | }
104 | }
105 | else if (re2.test(w)) {
106 | var fp = re2.exec(w);
107 | stem = fp[1];
108 | re2 = new RegExp(s_v);
109 | if (re2.test(stem)) {
110 | w = stem;
111 | re2 = /(at|bl|iz)$/;
112 | re3 = new RegExp("([^aeiouylsz])\\1$");
113 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
114 | if (re2.test(w))
115 | w = w + "e";
116 | else if (re3.test(w)) {
117 | re = /.$/;
118 | w = w.replace(re,"");
119 | }
120 | else if (re4.test(w))
121 | w = w + "e";
122 | }
123 | }
124 |
125 | // Step 1c
126 | re = /^(.+?)y$/;
127 | if (re.test(w)) {
128 | var fp = re.exec(w);
129 | stem = fp[1];
130 | re = new RegExp(s_v);
131 | if (re.test(stem))
132 | w = stem + "i";
133 | }
134 |
135 | // Step 2
136 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
137 | if (re.test(w)) {
138 | var fp = re.exec(w);
139 | stem = fp[1];
140 | suffix = fp[2];
141 | re = new RegExp(mgr0);
142 | if (re.test(stem))
143 | w = stem + step2list[suffix];
144 | }
145 |
146 | // Step 3
147 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
148 | if (re.test(w)) {
149 | var fp = re.exec(w);
150 | stem = fp[1];
151 | suffix = fp[2];
152 | re = new RegExp(mgr0);
153 | if (re.test(stem))
154 | w = stem + step3list[suffix];
155 | }
156 |
157 | // Step 4
158 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
159 | re2 = /^(.+?)(s|t)(ion)$/;
160 | if (re.test(w)) {
161 | var fp = re.exec(w);
162 | stem = fp[1];
163 | re = new RegExp(mgr1);
164 | if (re.test(stem))
165 | w = stem;
166 | }
167 | else if (re2.test(w)) {
168 | var fp = re2.exec(w);
169 | stem = fp[1] + fp[2];
170 | re2 = new RegExp(mgr1);
171 | if (re2.test(stem))
172 | w = stem;
173 | }
174 |
175 | // Step 5
176 | re = /^(.+?)e$/;
177 | if (re.test(w)) {
178 | var fp = re.exec(w);
179 | stem = fp[1];
180 | re = new RegExp(mgr1);
181 | re2 = new RegExp(meq1);
182 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
183 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
184 | w = stem;
185 | }
186 | re = /ll$/;
187 | re2 = new RegExp(mgr1);
188 | if (re.test(w) && re2.test(w)) {
189 | re = /.$/;
190 | w = w.replace(re,"");
191 | }
192 |
193 | // and turn initial Y back to y
194 | if (firstch == "y")
195 | w = firstch.toLowerCase() + w.substr(1);
196 | return w;
197 | }
198 | }
199 |
200 |
201 |
202 |
203 | var splitChars = (function() {
204 | var result = {};
205 | var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648,
206 | 1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702,
207 | 2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971,
208 | 2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345,
209 | 3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761,
210 | 3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823,
211 | 4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125,
212 | 8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695,
213 | 11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587,
214 | 43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141];
215 | var i, j, start, end;
216 | for (i = 0; i < singles.length; i++) {
217 | result[singles[i]] = true;
218 | }
219 | var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709],
220 | [722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161],
221 | [1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568],
222 | [1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807],
223 | [1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047],
224 | [2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383],
225 | [2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450],
226 | [2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547],
227 | [2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673],
228 | [2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820],
229 | [2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946],
230 | [2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023],
231 | [3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173],
232 | [3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332],
233 | [3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481],
234 | [3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718],
235 | [3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791],
236 | [3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095],
237 | [4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205],
238 | [4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687],
239 | [4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968],
240 | [4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869],
241 | [5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102],
242 | [6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271],
243 | [6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592],
244 | [6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822],
245 | [6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167],
246 | [7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959],
247 | [7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143],
248 | [8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318],
249 | [8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483],
250 | [8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101],
251 | [10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567],
252 | [11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292],
253 | [12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444],
254 | [12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783],
255 | [12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311],
256 | [19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511],
257 | [42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774],
258 | [42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071],
259 | [43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263],
260 | [43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519],
261 | [43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647],
262 | [43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967],
263 | [44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295],
264 | [57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274],
265 | [64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007],
266 | [65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381],
267 | [65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]];
268 | for (i = 0; i < ranges.length; i++) {
269 | start = ranges[i][0];
270 | end = ranges[i][1];
271 | for (j = start; j <= end; j++) {
272 | result[j] = true;
273 | }
274 | }
275 | return result;
276 | })();
277 |
278 | function splitQuery(query) {
279 | var result = [];
280 | var start = -1;
281 | for (var i = 0; i < query.length; i++) {
282 | if (splitChars[query.charCodeAt(i)]) {
283 | if (start !== -1) {
284 | result.push(query.slice(start, i));
285 | start = -1;
286 | }
287 | } else if (start === -1) {
288 | start = i;
289 | }
290 | }
291 | if (start !== -1) {
292 | result.push(query.slice(start));
293 | }
294 | return result;
295 | }
296 |
297 |
298 |
--------------------------------------------------------------------------------
/doc/build/html/_static/minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/minus.png
--------------------------------------------------------------------------------
/doc/build/html/_static/plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/_static/plus.png
--------------------------------------------------------------------------------
/doc/build/html/_static/pygments.css:
--------------------------------------------------------------------------------
1 | pre { line-height: 125%; }
2 | td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
3 | span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
4 | td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
5 | span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
6 | .highlight .hll { background-color: #ffffcc }
7 | .highlight { background: #f8f8f8; }
8 | .highlight .c { color: #3D7B7B; font-style: italic } /* Comment */
9 | .highlight .err { border: 1px solid #FF0000 } /* Error */
10 | .highlight .k { color: #008000; font-weight: bold } /* Keyword */
11 | .highlight .o { color: #666666 } /* Operator */
12 | .highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
13 | .highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
14 | .highlight .cp { color: #9C6500 } /* Comment.Preproc */
15 | .highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
16 | .highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
17 | .highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
18 | .highlight .gd { color: #A00000 } /* Generic.Deleted */
19 | .highlight .ge { font-style: italic } /* Generic.Emph */
20 | .highlight .gr { color: #E40000 } /* Generic.Error */
21 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
22 | .highlight .gi { color: #008400 } /* Generic.Inserted */
23 | .highlight .go { color: #717171 } /* Generic.Output */
24 | .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
25 | .highlight .gs { font-weight: bold } /* Generic.Strong */
26 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
27 | .highlight .gt { color: #0044DD } /* Generic.Traceback */
28 | .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
29 | .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
30 | .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
31 | .highlight .kp { color: #008000 } /* Keyword.Pseudo */
32 | .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
33 | .highlight .kt { color: #B00040 } /* Keyword.Type */
34 | .highlight .m { color: #666666 } /* Literal.Number */
35 | .highlight .s { color: #BA2121 } /* Literal.String */
36 | .highlight .na { color: #687822 } /* Name.Attribute */
37 | .highlight .nb { color: #008000 } /* Name.Builtin */
38 | .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
39 | .highlight .no { color: #880000 } /* Name.Constant */
40 | .highlight .nd { color: #AA22FF } /* Name.Decorator */
41 | .highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */
42 | .highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
43 | .highlight .nf { color: #0000FF } /* Name.Function */
44 | .highlight .nl { color: #767600 } /* Name.Label */
45 | .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
46 | .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
47 | .highlight .nv { color: #19177C } /* Name.Variable */
48 | .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
49 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */
50 | .highlight .mb { color: #666666 } /* Literal.Number.Bin */
51 | .highlight .mf { color: #666666 } /* Literal.Number.Float */
52 | .highlight .mh { color: #666666 } /* Literal.Number.Hex */
53 | .highlight .mi { color: #666666 } /* Literal.Number.Integer */
54 | .highlight .mo { color: #666666 } /* Literal.Number.Oct */
55 | .highlight .sa { color: #BA2121 } /* Literal.String.Affix */
56 | .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
57 | .highlight .sc { color: #BA2121 } /* Literal.String.Char */
58 | .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
59 | .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
60 | .highlight .s2 { color: #BA2121 } /* Literal.String.Double */
61 | .highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
62 | .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
63 | .highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
64 | .highlight .sx { color: #008000 } /* Literal.String.Other */
65 | .highlight .sr { color: #A45A77 } /* Literal.String.Regex */
66 | .highlight .s1 { color: #BA2121 } /* Literal.String.Single */
67 | .highlight .ss { color: #19177C } /* Literal.String.Symbol */
68 | .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
69 | .highlight .fm { color: #0000FF } /* Name.Function.Magic */
70 | .highlight .vc { color: #19177C } /* Name.Variable.Class */
71 | .highlight .vg { color: #19177C } /* Name.Variable.Global */
72 | .highlight .vi { color: #19177C } /* Name.Variable.Instance */
73 | .highlight .vm { color: #19177C } /* Name.Variable.Magic */
74 | .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/doc/build/html/_static/searchtools.js:
--------------------------------------------------------------------------------
1 | /*
2 | * searchtools.js
3 | * ~~~~~~~~~~~~~~~~
4 | *
5 | * Sphinx JavaScript utilities for the full-text search.
6 | *
7 | * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
8 | * :license: BSD, see LICENSE for details.
9 | *
10 | */
11 |
12 | if (!Scorer) {
13 | /**
14 | * Simple result scoring code.
15 | */
16 | var Scorer = {
17 | // Implement the following function to further tweak the score for each result
18 | // The function takes a result array [filename, title, anchor, descr, score]
19 | // and returns the new score.
20 | /*
21 | score: function(result) {
22 | return result[4];
23 | },
24 | */
25 |
26 | // query matches the full name of an object
27 | objNameMatch: 11,
28 | // or matches in the last dotted part of the object name
29 | objPartialMatch: 6,
30 | // Additive scores depending on the priority of the object
31 | objPrio: {0: 15, // used to be importantResults
32 | 1: 5, // used to be objectResults
33 | 2: -5}, // used to be unimportantResults
34 | // Used when the priority is not in the mapping.
35 | objPrioDefault: 0,
36 |
37 | // query found in title
38 | title: 15,
39 | partialTitle: 7,
40 | // query found in terms
41 | term: 5,
42 | partialTerm: 2
43 | };
44 | }
45 |
46 | if (!splitQuery) {
47 | function splitQuery(query) {
48 | return query.split(/\s+/);
49 | }
50 | }
51 |
52 | /**
53 | * Search Module
54 | */
55 | var Search = {
56 |
57 | _index : null,
58 | _queued_query : null,
59 | _pulse_status : -1,
60 |
61 | htmlToText : function(htmlString) {
62 | var virtualDocument = document.implementation.createHTMLDocument('virtual');
63 | var htmlElement = $(htmlString, virtualDocument);
64 | htmlElement.find('.headerlink').remove();
65 | docContent = htmlElement.find('[role=main]')[0];
66 | if(docContent === undefined) {
67 | console.warn("Content block not found. Sphinx search tries to obtain it " +
68 | "via '[role=main]'. Could you check your theme or template.");
69 | return "";
70 | }
71 | return docContent.textContent || docContent.innerText;
72 | },
73 |
74 | init : function() {
75 | var params = $.getQueryParameters();
76 | if (params.q) {
77 | var query = params.q[0];
78 | $('input[name="q"]')[0].value = query;
79 | this.performSearch(query);
80 | }
81 | },
82 |
83 | loadIndex : function(url) {
84 | $.ajax({type: "GET", url: url, data: null,
85 | dataType: "script", cache: true,
86 | complete: function(jqxhr, textstatus) {
87 | if (textstatus != "success") {
88 | document.getElementById("searchindexloader").src = url;
89 | }
90 | }});
91 | },
92 |
93 | setIndex : function(index) {
94 | var q;
95 | this._index = index;
96 | if ((q = this._queued_query) !== null) {
97 | this._queued_query = null;
98 | Search.query(q);
99 | }
100 | },
101 |
102 | hasIndex : function() {
103 | return this._index !== null;
104 | },
105 |
106 | deferQuery : function(query) {
107 | this._queued_query = query;
108 | },
109 |
110 | stopPulse : function() {
111 | this._pulse_status = 0;
112 | },
113 |
114 | startPulse : function() {
115 | if (this._pulse_status >= 0)
116 | return;
117 | function pulse() {
118 | var i;
119 | Search._pulse_status = (Search._pulse_status + 1) % 4;
120 | var dotString = '';
121 | for (i = 0; i < Search._pulse_status; i++)
122 | dotString += '.';
123 | Search.dots.text(dotString);
124 | if (Search._pulse_status > -1)
125 | window.setTimeout(pulse, 500);
126 | }
127 | pulse();
128 | },
129 |
130 | /**
131 | * perform a search for something (or wait until index is loaded)
132 | */
133 | performSearch : function(query) {
134 | // create the required interface elements
135 | this.out = $('#search-results');
136 | this.title = $('' + _('Searching') + '
').appendTo(this.out);
137 | this.dots = $('').appendTo(this.title);
138 | this.status = $('
').appendTo(this.out);
139 | this.output = $('').appendTo(this.out);
140 |
141 | $('#search-progress').text(_('Preparing search...'));
142 | this.startPulse();
143 |
144 | // index already loaded, the browser was quick!
145 | if (this.hasIndex())
146 | this.query(query);
147 | else
148 | this.deferQuery(query);
149 | },
150 |
151 | /**
152 | * execute search (requires search index to be loaded)
153 | */
154 | query : function(query) {
155 | var i;
156 |
157 | // stem the searchterms and add them to the correct list
158 | var stemmer = new Stemmer();
159 | var searchterms = [];
160 | var excluded = [];
161 | var hlterms = [];
162 | var tmp = splitQuery(query);
163 | var objectterms = [];
164 | for (i = 0; i < tmp.length; i++) {
165 | if (tmp[i] !== "") {
166 | objectterms.push(tmp[i].toLowerCase());
167 | }
168 |
169 | if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i] === "") {
170 | // skip this "word"
171 | continue;
172 | }
173 | // stem the word
174 | var word = stemmer.stemWord(tmp[i].toLowerCase());
175 | var toAppend;
176 | // select the correct list
177 | if (word[0] == '-') {
178 | toAppend = excluded;
179 | word = word.substr(1);
180 | }
181 | else {
182 | toAppend = searchterms;
183 | hlterms.push(tmp[i].toLowerCase());
184 | }
185 | // only add if not already in the list
186 | if (!$u.contains(toAppend, word))
187 | toAppend.push(word);
188 | }
189 | var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
190 |
191 | // console.debug('SEARCH: searching for:');
192 | // console.info('required: ', searchterms);
193 | // console.info('excluded: ', excluded);
194 |
195 | // prepare search
196 | var terms = this._index.terms;
197 | var titleterms = this._index.titleterms;
198 |
199 | // array of [filename, title, anchor, descr, score]
200 | var results = [];
201 | $('#search-progress').empty();
202 |
203 | // lookup as object
204 | for (i = 0; i < objectterms.length; i++) {
205 | var others = [].concat(objectterms.slice(0, i),
206 | objectterms.slice(i+1, objectterms.length));
207 | results = results.concat(this.performObjectSearch(objectterms[i], others));
208 | }
209 |
210 | // lookup as search terms in fulltext
211 | results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms));
212 |
213 | // let the scorer override scores with a custom scoring function
214 | if (Scorer.score) {
215 | for (i = 0; i < results.length; i++)
216 | results[i][4] = Scorer.score(results[i]);
217 | }
218 |
219 | // now sort the results by score (in opposite order of appearance, since the
220 | // display function below uses pop() to retrieve items) and then
221 | // alphabetically
222 | results.sort(function(a, b) {
223 | var left = a[4];
224 | var right = b[4];
225 | if (left > right) {
226 | return 1;
227 | } else if (left < right) {
228 | return -1;
229 | } else {
230 | // same score: sort alphabetically
231 | left = a[1].toLowerCase();
232 | right = b[1].toLowerCase();
233 | return (left > right) ? -1 : ((left < right) ? 1 : 0);
234 | }
235 | });
236 |
237 | // for debugging
238 | //Search.lastresults = results.slice(); // a copy
239 | //console.info('search results:', Search.lastresults);
240 |
241 | // print the results
242 | var resultCount = results.length;
243 | function displayNextItem() {
244 | // results left, load the summary and display it
245 | if (results.length) {
246 | var item = results.pop();
247 | var listItem = $('');
248 | var requestUrl = "";
249 | var linkUrl = "";
250 | if (DOCUMENTATION_OPTIONS.BUILDER === 'dirhtml') {
251 | // dirhtml builder
252 | var dirname = item[0] + '/';
253 | if (dirname.match(/\/index\/$/)) {
254 | dirname = dirname.substring(0, dirname.length-6);
255 | } else if (dirname == 'index/') {
256 | dirname = '';
257 | }
258 | requestUrl = DOCUMENTATION_OPTIONS.URL_ROOT + dirname;
259 | linkUrl = requestUrl;
260 |
261 | } else {
262 | // normal html builders
263 | requestUrl = DOCUMENTATION_OPTIONS.URL_ROOT + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX;
264 | linkUrl = item[0] + DOCUMENTATION_OPTIONS.LINK_SUFFIX;
265 | }
266 | listItem.append($('').attr('href',
267 | linkUrl +
268 | highlightstring + item[2]).html(item[1]));
269 | if (item[3]) {
270 | listItem.append($(' (' + item[3] + ')'));
271 | Search.output.append(listItem);
272 | setTimeout(function() {
273 | displayNextItem();
274 | }, 5);
275 | } else if (DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY) {
276 | $.ajax({url: requestUrl,
277 | dataType: "text",
278 | complete: function(jqxhr, textstatus) {
279 | var data = jqxhr.responseText;
280 | if (data !== '' && data !== undefined) {
281 | var summary = Search.makeSearchSummary(data, searchterms, hlterms);
282 | if (summary) {
283 | listItem.append(summary);
284 | }
285 | }
286 | Search.output.append(listItem);
287 | setTimeout(function() {
288 | displayNextItem();
289 | }, 5);
290 | }});
291 | } else {
292 | // just display title
293 | Search.output.append(listItem);
294 | setTimeout(function() {
295 | displayNextItem();
296 | }, 5);
297 | }
298 | }
299 | // search finished, update title and status message
300 | else {
301 | Search.stopPulse();
302 | Search.title.text(_('Search Results'));
303 | if (!resultCount)
304 | Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
305 | else
306 | Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
307 | Search.status.fadeIn(500);
308 | }
309 | }
310 | displayNextItem();
311 | },
312 |
313 | /**
314 | * search for object names
315 | */
316 | performObjectSearch : function(object, otherterms) {
317 | var filenames = this._index.filenames;
318 | var docnames = this._index.docnames;
319 | var objects = this._index.objects;
320 | var objnames = this._index.objnames;
321 | var titles = this._index.titles;
322 |
323 | var i;
324 | var results = [];
325 |
326 | for (var prefix in objects) {
327 | for (var iMatch = 0; iMatch != objects[prefix].length; ++iMatch) {
328 | var match = objects[prefix][iMatch];
329 | var name = match[4];
330 | var fullname = (prefix ? prefix + '.' : '') + name;
331 | var fullnameLower = fullname.toLowerCase()
332 | if (fullnameLower.indexOf(object) > -1) {
333 | var score = 0;
334 | var parts = fullnameLower.split('.');
335 | // check for different match types: exact matches of full name or
336 | // "last name" (i.e. last dotted part)
337 | if (fullnameLower == object || parts[parts.length - 1] == object) {
338 | score += Scorer.objNameMatch;
339 | // matches in last name
340 | } else if (parts[parts.length - 1].indexOf(object) > -1) {
341 | score += Scorer.objPartialMatch;
342 | }
343 | var objname = objnames[match[1]][2];
344 | var title = titles[match[0]];
345 | // If more than one term searched for, we require other words to be
346 | // found in the name/title/description
347 | if (otherterms.length > 0) {
348 | var haystack = (prefix + ' ' + name + ' ' +
349 | objname + ' ' + title).toLowerCase();
350 | var allfound = true;
351 | for (i = 0; i < otherterms.length; i++) {
352 | if (haystack.indexOf(otherterms[i]) == -1) {
353 | allfound = false;
354 | break;
355 | }
356 | }
357 | if (!allfound) {
358 | continue;
359 | }
360 | }
361 | var descr = objname + _(', in ') + title;
362 |
363 | var anchor = match[3];
364 | if (anchor === '')
365 | anchor = fullname;
366 | else if (anchor == '-')
367 | anchor = objnames[match[1]][1] + '-' + fullname;
368 | // add custom score for some objects according to scorer
369 | if (Scorer.objPrio.hasOwnProperty(match[2])) {
370 | score += Scorer.objPrio[match[2]];
371 | } else {
372 | score += Scorer.objPrioDefault;
373 | }
374 | results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]);
375 | }
376 | }
377 | }
378 |
379 | return results;
380 | },
381 |
382 | /**
383 | * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
384 | */
385 | escapeRegExp : function(string) {
386 | return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
387 | },
388 |
389 | /**
390 | * search for full-text terms in the index
391 | */
392 | performTermsSearch : function(searchterms, excluded, terms, titleterms) {
393 | var docnames = this._index.docnames;
394 | var filenames = this._index.filenames;
395 | var titles = this._index.titles;
396 |
397 | var i, j, file;
398 | var fileMap = {};
399 | var scoreMap = {};
400 | var results = [];
401 |
402 | // perform the search on the required terms
403 | for (i = 0; i < searchterms.length; i++) {
404 | var word = searchterms[i];
405 | var files = [];
406 | var _o = [
407 | {files: terms[word], score: Scorer.term},
408 | {files: titleterms[word], score: Scorer.title}
409 | ];
410 | // add support for partial matches
411 | if (word.length > 2) {
412 | var word_regex = this.escapeRegExp(word);
413 | for (var w in terms) {
414 | if (w.match(word_regex) && !terms[word]) {
415 | _o.push({files: terms[w], score: Scorer.partialTerm})
416 | }
417 | }
418 | for (var w in titleterms) {
419 | if (w.match(word_regex) && !titleterms[word]) {
420 | _o.push({files: titleterms[w], score: Scorer.partialTitle})
421 | }
422 | }
423 | }
424 |
425 | // no match but word was a required one
426 | if ($u.every(_o, function(o){return o.files === undefined;})) {
427 | break;
428 | }
429 | // found search word in contents
430 | $u.each(_o, function(o) {
431 | var _files = o.files;
432 | if (_files === undefined)
433 | return
434 |
435 | if (_files.length === undefined)
436 | _files = [_files];
437 | files = files.concat(_files);
438 |
439 | // set score for the word in each file to Scorer.term
440 | for (j = 0; j < _files.length; j++) {
441 | file = _files[j];
442 | if (!(file in scoreMap))
443 | scoreMap[file] = {};
444 | scoreMap[file][word] = o.score;
445 | }
446 | });
447 |
448 | // create the mapping
449 | for (j = 0; j < files.length; j++) {
450 | file = files[j];
451 | if (file in fileMap && fileMap[file].indexOf(word) === -1)
452 | fileMap[file].push(word);
453 | else
454 | fileMap[file] = [word];
455 | }
456 | }
457 |
458 | // now check if the files don't contain excluded terms
459 | for (file in fileMap) {
460 | var valid = true;
461 |
462 | // check if all requirements are matched
463 | var filteredTermCount = // as search terms with length < 3 are discarded: ignore
464 | searchterms.filter(function(term){return term.length > 2}).length
465 | if (
466 | fileMap[file].length != searchterms.length &&
467 | fileMap[file].length != filteredTermCount
468 | ) continue;
469 |
470 | // ensure that none of the excluded terms is in the search result
471 | for (i = 0; i < excluded.length; i++) {
472 | if (terms[excluded[i]] == file ||
473 | titleterms[excluded[i]] == file ||
474 | $u.contains(terms[excluded[i]] || [], file) ||
475 | $u.contains(titleterms[excluded[i]] || [], file)) {
476 | valid = false;
477 | break;
478 | }
479 | }
480 |
481 | // if we have still a valid result we can add it to the result list
482 | if (valid) {
483 | // select one (max) score for the file.
484 | // for better ranking, we should calculate ranking by using words statistics like basic tf-idf...
485 | var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]}));
486 | results.push([docnames[file], titles[file], '', null, score, filenames[file]]);
487 | }
488 | }
489 | return results;
490 | },
491 |
492 | /**
493 | * helper function to return a node containing the
494 | * search summary for a given text. keywords is a list
495 | * of stemmed words, hlwords is the list of normal, unstemmed
496 | * words. the first one is used to find the occurrence, the
497 | * latter for highlighting it.
498 | */
499 | makeSearchSummary : function(htmlText, keywords, hlwords) {
500 | var text = Search.htmlToText(htmlText);
501 | if (text == "") {
502 | return null;
503 | }
504 | var textLower = text.toLowerCase();
505 | var start = 0;
506 | $.each(keywords, function() {
507 | var i = textLower.indexOf(this.toLowerCase());
508 | if (i > -1)
509 | start = i;
510 | });
511 | start = Math.max(start - 120, 0);
512 | var excerpt = ((start > 0) ? '...' : '') +
513 | $.trim(text.substr(start, 240)) +
514 | ((start + 240 - text.length) ? '...' : '');
515 | var rv = $('').text(excerpt);
516 | $.each(hlwords, function() {
517 | rv = rv.highlightText(this, 'highlighted');
518 | });
519 | return rv;
520 | }
521 | };
522 |
523 | $(document).ready(function() {
524 | Search.init();
525 | });
526 |
--------------------------------------------------------------------------------
/doc/build/html/_static/translations.js:
--------------------------------------------------------------------------------
1 | Documentation.addTranslations({
2 | "locale": "zh_Hans_CN",
3 | "messages": {
4 | "%(filename)s — %(docstitle)s": "%(filename)s — %(docstitle)s",
5 | "© Copyright %(copyright)s.": "© \u7248\u6743\u6240\u6709 %(copyright)s.",
6 | "© Copyright %(copyright)s.": "© \u7248\u6743\u6240\u6709 %(copyright)s.",
7 | ", in ": "\uff0c \u5728 ",
8 | "About these documents": "\u5173\u4e8e\u8fd9\u4e9b\u6587\u6863",
9 | "Automatically generated list of changes in version %(version)s": "\u81ea\u52a8\u751f\u6210\u7684 %(version)s \u7248\u672c\u4e2d\u7684\u66f4\u6539\u5217\u8868",
10 | "C API changes": "C API \u66f4\u6539",
11 | "Changes in Version %(version)s — %(docstitle)s": "\u66f4\u6539\u53d1\u751f\u5728\u7248\u672c %(version)s— %(docstitle)s",
12 | "Collapse sidebar": "\u6298\u53e0\u8fb9\u680f",
13 | "Complete Table of Contents": "\u5b8c\u6574\u7684\u5185\u5bb9\u8868",
14 | "Contents": "\u76ee\u5f55",
15 | "Copyright": "\u7248\u6743\u6240\u6709",
16 | "Created using Sphinx %(sphinx_version)s.": "\u7531 Sphinx %(sphinx_version)s\u521b\u5efa\u3002",
17 | "Expand sidebar": "\u5c55\u5f00\u8fb9\u680f",
18 | "Full index on one page": "\u4e00\u9875\u7684\u5168\u90e8\u7d22\u5f15",
19 | "General Index": "\u603b\u76ee\u5f55",
20 | "Global Module Index": "\u5168\u5c40\u6a21\u5757\u7d22\u5f15",
21 | "Go": "\u8f6c\u5411",
22 | "Hide Search Matches": "\u9690\u85cf\u641c\u7d22\u7ed3\u679c",
23 | "Index": "\u7d22\u5f15",
24 | "Index – %(key)s": "\u7d22\u5f15 – %(key)s",
25 | "Index pages by letter": "\u6309\u7167\u5b57\u6bcd\u7684\u7d22\u5f15\u9875",
26 | "Indices and tables:": "\u7d22\u5f15\u548c\u8868\u683c\uff1a",
27 | "Last updated on %(last_updated)s.": "\u6700\u540e\u66f4\u65b0\u4e8e %(last_updated)s.",
28 | "Library changes": "\u5e93\u66f4\u6539",
29 | "Navigation": "\u5bfc\u822a",
30 | "Next topic": "\u4e0b\u4e00\u4e2a\u4e3b\u9898",
31 | "Other changes": "\u5176\u4ed6\u66f4\u6539",
32 | "Overview": "\u6982\u8ff0",
33 | "Permalink to this definition": "\u6c38\u4e45\u94fe\u63a5\u81f3\u76ee\u6807",
34 | "Permalink to this headline": "\u6c38\u4e45\u94fe\u63a5\u81f3\u6807\u9898",
35 | "Please activate JavaScript to enable the search\n functionality.": "\u8bf7\u6fc0\u6d3b JavaScript \u4ee5\u5f00\u542f\u641c\u7d22\u529f\u80fd\u3002",
36 | "Preparing search...": "\u51c6\u5907\u641c\u7d22\u2026\u2026",
37 | "Previous topic": "\u4e0a\u4e00\u4e2a\u4e3b\u9898",
38 | "Quick search": "\u5feb\u901f\u641c\u7d22",
39 | "Search": "\u641c\u7d22",
40 | "Search Page": "\u641c\u7d22\u9875\u9762",
41 | "Search Results": "\u641c\u7d22\u7ed3\u679c",
42 | "Search finished, found %s page(s) matching the search query.": "\u641c\u7d22\u5b8c\u6210\uff0c\u6709 %s \u4e2a\u9875\u9762\u5339\u914d\u3002",
43 | "Search within %(docstitle)s": "\u5728 %(docstitle)s \u4e2d\u641c\u7d22",
44 | "Searching": "\u641c\u7d22\u4e2d",
45 | "Searching for multiple words only shows matches that contain\n all words.": "\u641c\u5bfb\u5305\u542b\u591a\u4e2a\u5b57\u7684\u8bcd\u6c47\u65f6\uff0c\n \u53ea\u6709\u6240\u542b\u6240\u6709\u5185\u5bb9\u90fd\u5339\u914d\u65f6\u624d\u4f1a\u51fa\u73b0\u3002",
46 | "Show Source": "\u663e\u793a\u6e90\u4ee3\u7801",
47 | "Table of Contents": "\u76ee\u5f55",
48 | "This Page": "\u672c\u9875",
49 | "Welcome! This is": "\u6b22\u8fce\uff01\u8fd9\u662f",
50 | "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.": "\u6ca1\u6709\u4efb\u4f55\u6587\u6863\u5339\u914d\u60a8\u7684\u641c\u7d22\u3002\u8bf7\u786e\u4fdd\u4f60\u8f93\u5165\u7684\u8bcd\u62fc\u5199\u6b63\u786e\u5e76\u9009\u62e9\u4e86\u5408\u9002\u7684\u5206\u7c7b\u3002",
51 | "all functions, classes, terms": "\u6240\u7684\u51fd\u6570\uff0c\u7c7b\uff0c\u672f\u8bed",
52 | "can be huge": "\u53ef\u80fd\u4f1a\u5f88\u591a",
53 | "last updated": "\u6700\u540e\u66f4\u65b0\u4e8e",
54 | "lists all sections and subsections": "\u5217\u51fa\u6240\u6709\u7684\u7ae0\u8282\u548c\u90e8\u5206",
55 | "next chapter": "\u4e0b\u4e00\u7ae0",
56 | "previous chapter": "\u4e0a\u4e00\u7ae0",
57 | "quick access to all modules": "\u5feb\u901f\u67e5\u770b\u6240\u6709\u7684\u6a21\u5757",
58 | "search": "\u641c\u7d22",
59 | "search this documentation": "\u641c\u7d22\u6587\u6863",
60 | "the documentation for": "\u8fd9\u4efd\u6587\u6863\u662f"
61 | },
62 | "plural_expr": "0"
63 | });
--------------------------------------------------------------------------------
/doc/build/html/_static/underscore.js:
--------------------------------------------------------------------------------
1 | !function(n,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define("underscore",r):(n="undefined"!=typeof globalThis?globalThis:n||self,function(){var t=n._,e=n._=r();e.noConflict=function(){return n._=t,e}}())}(this,(function(){
2 | // Underscore.js 1.13.1
3 | // https://underscorejs.org
4 | // (c) 2009-2021 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors
5 | // Underscore may be freely distributed under the MIT license.
6 | var n="1.13.1",r="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||Function("return this")()||{},t=Array.prototype,e=Object.prototype,u="undefined"!=typeof Symbol?Symbol.prototype:null,o=t.push,i=t.slice,a=e.toString,f=e.hasOwnProperty,c="undefined"!=typeof ArrayBuffer,l="undefined"!=typeof DataView,s=Array.isArray,p=Object.keys,v=Object.create,h=c&&ArrayBuffer.isView,y=isNaN,d=isFinite,g=!{toString:null}.propertyIsEnumerable("toString"),b=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"],m=Math.pow(2,53)-1;function j(n,r){return r=null==r?n.length-1:+r,function(){for(var t=Math.max(arguments.length-r,0),e=Array(t),u=0;u=0&&t<=m}}function J(n){return function(r){return null==r?void 0:r[n]}}var G=J("byteLength"),H=K(G),Q=/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;var X=c?function(n){return h?h(n)&&!q(n):H(n)&&Q.test(a.call(n))}:C(!1),Y=J("length");function Z(n,r){r=function(n){for(var r={},t=n.length,e=0;e":">",'"':""","'":"'","`":"`"},Cn=Ln($n),Kn=Ln(_n($n)),Jn=tn.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g},Gn=/(.)^/,Hn={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},Qn=/\\|'|\r|\n|\u2028|\u2029/g;function Xn(n){return"\\"+Hn[n]}var Yn=/^\s*(\w|\$)+\s*$/;var Zn=0;function nr(n,r,t,e,u){if(!(e instanceof r))return n.apply(t,u);var o=Mn(n.prototype),i=n.apply(o,u);return _(i)?i:o}var rr=j((function(n,r){var t=rr.placeholder,e=function(){for(var u=0,o=r.length,i=Array(o),a=0;a1)ur(a,r-1,t,e),u=e.length;else for(var f=0,c=a.length;f0&&(t=r.apply(this,arguments)),n<=1&&(r=null),t}}var lr=rr(cr,2);function sr(n,r,t){r=qn(r,t);for(var e,u=nn(n),o=0,i=u.length;o0?0:u-1;o>=0&&o0?a=o>=0?o:Math.max(o+f,a):f=o>=0?Math.min(o+1,f):o+f+1;else if(t&&o&&f)return e[o=t(e,u)]===u?o:-1;if(u!=u)return(o=r(i.call(e,a,f),$))>=0?o+a:-1;for(o=n>0?a:f-1;o>=0&&o0?0:i-1;for(u||(e=r[o?o[a]:a],a+=n);a>=0&&a=3;return r(n,Fn(t,u,4),e,o)}}var Ar=wr(1),xr=wr(-1);function Sr(n,r,t){var e=[];return r=qn(r,t),jr(n,(function(n,t,u){r(n,t,u)&&e.push(n)})),e}function Or(n,r,t){r=qn(r,t);for(var e=!er(n)&&nn(n),u=(e||n).length,o=0;o=0}var Br=j((function(n,r,t){var e,u;return D(r)?u=r:(r=Nn(r),e=r.slice(0,-1),r=r[r.length-1]),_r(n,(function(n){var o=u;if(!o){if(e&&e.length&&(n=In(n,e)),null==n)return;o=n[r]}return null==o?o:o.apply(n,t)}))}));function Nr(n,r){return _r(n,Rn(r))}function Ir(n,r,t){var e,u,o=-1/0,i=-1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=er(n)?n:jn(n)).length;ao&&(o=e);else r=qn(r,t),jr(n,(function(n,t,e){((u=r(n,t,e))>i||u===-1/0&&o===-1/0)&&(o=n,i=u)}));return o}function Tr(n,r,t){if(null==r||t)return er(n)||(n=jn(n)),n[Wn(n.length-1)];var e=er(n)?En(n):jn(n),u=Y(e);r=Math.max(Math.min(r,u),0);for(var o=u-1,i=0;i1&&(e=Fn(e,r[1])),r=an(n)):(e=qr,r=ur(r,!1,!1),n=Object(n));for(var u=0,o=r.length;u1&&(t=r[1])):(r=_r(ur(r,!1,!1),String),e=function(n,t){return!Er(r,t)}),Ur(n,e,t)}));function zr(n,r,t){return i.call(n,0,Math.max(0,n.length-(null==r||t?1:r)))}function Lr(n,r,t){return null==n||n.length<1?null==r||t?void 0:[]:null==r||t?n[0]:zr(n,n.length-r)}function $r(n,r,t){return i.call(n,null==r||t?1:r)}var Cr=j((function(n,r){return r=ur(r,!0,!0),Sr(n,(function(n){return!Er(r,n)}))})),Kr=j((function(n,r){return Cr(n,r)}));function Jr(n,r,t,e){A(r)||(e=t,t=r,r=!1),null!=t&&(t=qn(t,e));for(var u=[],o=[],i=0,a=Y(n);ir?(e&&(clearTimeout(e),e=null),a=c,i=n.apply(u,o),e||(u=o=null)):e||!1===t.trailing||(e=setTimeout(f,l)),i};return c.cancel=function(){clearTimeout(e),a=0,e=u=o=null},c},debounce:function(n,r,t){var e,u,o,i,a,f=function(){var c=zn()-u;r>c?e=setTimeout(f,r-c):(e=null,t||(i=n.apply(a,o)),e||(o=a=null))},c=j((function(c){return a=this,o=c,u=zn(),e||(e=setTimeout(f,r),t&&(i=n.apply(a,o))),i}));return c.cancel=function(){clearTimeout(e),e=o=a=null},c},wrap:function(n,r){return rr(r,n)},negate:fr,compose:function(){var n=arguments,r=n.length-1;return function(){for(var t=r,e=n[r].apply(this,arguments);t--;)e=n[t].call(this,e);return e}},after:function(n,r){return function(){if(--n<1)return r.apply(this,arguments)}},before:cr,once:lr,findKey:sr,findIndex:vr,findLastIndex:hr,sortedIndex:yr,indexOf:gr,lastIndexOf:br,find:mr,detect:mr,findWhere:function(n,r){return mr(n,Dn(r))},each:jr,forEach:jr,map:_r,collect:_r,reduce:Ar,foldl:Ar,inject:Ar,reduceRight:xr,foldr:xr,filter:Sr,select:Sr,reject:function(n,r,t){return Sr(n,fr(qn(r)),t)},every:Or,all:Or,some:Mr,any:Mr,contains:Er,includes:Er,include:Er,invoke:Br,pluck:Nr,where:function(n,r){return Sr(n,Dn(r))},max:Ir,min:function(n,r,t){var e,u,o=1/0,i=1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=er(n)?n:jn(n)).length;ae||void 0===t)return 1;if(t
2 |
3 |
4 |
5 |
6 | 索引 — PySVM 0.1 文档
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
43 |
44 |
48 |
49 |
50 |
51 |
52 |
53 | - »
54 | - 索引
55 | -
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
索引
65 |
66 |
67 |
C
68 | |
D
69 | |
F
70 | |
G
71 | |
K
72 | |
L
73 | |
N
74 | |
O
75 | |
P
76 | |
S
77 | |
T
78 | |
U
79 | |
W
80 | |
模
81 |
82 |
83 |
C
84 |
108 |
109 |
D
110 |
122 |
123 |
F
124 |
150 |
151 |
G
152 |
164 |
165 |
K
166 |
176 |
177 |
L
178 |
188 |
189 |
N
190 |
206 |
207 |
O
208 |
214 |
215 |
P
216 |
217 | |
235 |
236 | -
237 | pysvm
238 |
239 |
243 | -
244 | pysvm.rff
245 |
246 |
250 | -
251 | pysvm.solver
252 |
253 |
257 | -
258 | pysvm.svm
259 |
260 |
264 | |
265 |
266 |
267 |
S
268 |
294 |
295 |
T
296 |
302 |
303 |
U
304 |
318 |
319 |
W
320 |
334 |
335 |
模
336 |
337 |
338 | -
339 | 模块
340 |
341 |
351 | |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
372 |
373 |
374 |
375 |
376 |
381 |
382 |
383 |
--------------------------------------------------------------------------------
/doc/build/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Welcome to PySVM’s documentation! — PySVM 0.1 文档
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
48 |
49 |
53 |
54 |
55 |
56 |
57 |
58 | - »
59 | - Welcome to PySVM’s documentation!
60 | -
61 | 查看页面源码
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | Welcome to PySVM’s documentation!
71 |
72 |
73 |
74 |
75 | Indices and tables
76 |
81 |
82 |
83 |
84 |
85 |
86 |
100 |
101 |
102 |
103 |
104 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/doc/build/html/modules.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | pysvm — PySVM 0.1 文档
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
47 |
48 |
52 |
53 |
54 |
55 |
56 |
57 | - »
58 | - pysvm
59 | -
60 | 查看页面源码
61 |
62 |
63 |
64 |
65 |
87 |
101 |
102 |
103 |
104 |
105 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/doc/build/html/objects.inv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/doc/build/html/objects.inv
--------------------------------------------------------------------------------
/doc/build/html/py-modindex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Python 模块索引 — PySVM 0.1 文档
7 |
8 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
46 |
47 |
51 |
52 |
53 |
54 |
55 |
56 | - »
57 | - Python 模块索引
58 | -
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
Python 模块索引
68 |
69 |
72 |
73 |
99 |
100 |
101 |
102 |
103 |
117 |
118 |
119 |
120 |
121 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/doc/build/html/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 搜索 — PySVM 0.1 文档
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
46 |
47 |
51 |
52 |
53 |
54 |
55 |
56 | - »
57 | - 搜索
58 | -
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
95 |
96 |
97 |
98 |
99 |
104 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/doc/build/html/searchindex.js:
--------------------------------------------------------------------------------
1 | Search.setIndex({docnames:["index","modules","pysvm"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":5,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,"sphinx.ext.intersphinx":1,"sphinx.ext.todo":2,sphinx:56},filenames:["index.rst","modules.rst","pysvm.rst"],objects:{"":[[2,0,0,"-","pysvm"]],"pysvm.KernelSVC":[[2,2,1,"","decision_function"],[2,2,1,"","fit"],[2,2,1,"","predict"],[2,2,1,"","score"]],"pysvm.KernelSVR":[[2,2,1,"","fit"],[2,2,1,"","predict"],[2,2,1,"","score"]],"pysvm.LinearSVC":[[2,2,1,"","decision_function"],[2,2,1,"","fit"],[2,2,1,"","predict"],[2,2,1,"","score"]],"pysvm.LinearSVR":[[2,2,1,"","decision_function"],[2,2,1,"","fit"],[2,2,1,"","predict"],[2,2,1,"","score"]],"pysvm.NuSVC":[[2,2,1,"","fit"],[2,2,1,"","predict"],[2,2,1,"","score"]],"pysvm.NuSVR":[[2,2,1,"","fit"],[2,2,1,"","predict"],[2,2,1,"","score"]],"pysvm.OneClassSVM":[[2,2,1,"","fit"],[2,2,1,"","predict"],[2,2,1,"","score"]],"pysvm.rff":[[2,1,1,"","NormalRFF"]],"pysvm.rff.NormalRFF":[[2,2,1,"","fit"],[2,2,1,"","fit_transform"],[2,2,1,"","transform"]],"pysvm.solver":[[2,1,1,"","NuSolver"],[2,1,1,"","NuSolverWithCache"],[2,1,1,"","Solver"],[2,1,1,"","SolverWithCache"]],"pysvm.solver.NuSolver":[[2,2,1,"","calculate_rho_b"],[2,2,1,"","update"],[2,2,1,"","working_set_select"]],"pysvm.solver.NuSolverWithCache":[[2,3,1,"","cache_size"],[2,2,1,"","calculate_rho_b"],[2,2,1,"","get_Q"],[2,2,1,"","update"],[2,2,1,"","working_set_select"]],"pysvm.solver.Solver":[[2,2,1,"","calculate_rho"],[2,2,1,"","get_Q"],[2,2,1,"","update"],[2,2,1,"","working_set_select"]],"pysvm.solver.SolverWithCache":[[2,3,1,"","cache_size"],[2,2,1,"","calculate_rho"],[2,2,1,"","get_Q"],[2,2,1,"","update"],[2,2,1,"","working_set_select"]],pysvm:[[2,1,1,"","KernelSVC"],[2,1,1,"","KernelSVR"],[2,1,1,"","LinearSVC"],[2,1,1,"","LinearSVR"],[2,1,1,"","NuSVC"],[2,1,1,"","NuSVR"],[2,1,1,"","OneClassSVM"],[2,0,0,"-","rff"],[2,0,0,"-","solver"],[2,0,0,"-","svm"]]},objnames:{"0":["py","module","Python \u6a21\u5757"],"1":["py","class","Python \u7c7b"],"2":["py","method","Python \u65b9\u6cd5"],"3":["py","attribute","Python \u5c5e\u6027"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute"},terms:{"0.0":2,"0.5":2,"05":2,"07":2,"09":2,"1.0":2,"1000":2,"11":2,"16":2,"1e":2,"2021":2,"256":2,"\u4e00\u5bf9":2,"\u4e00\u5bf9\u4e00":2,"\u4e00\u9636":2,"\u4e0b\u964d":2,"\u4e0b\u9762":2,"\u4e0d\u5230":2,"\u4e24\u5bf9":2,"\u4e2d\u6709":2,"\u4ece\u800c":2,"\u4f18\u5316":2,"\u4f30\u8ba1":2,"\u4f7f\u7528":2,"\u4fdd\u8bc1":2,"\u4fe1\u606f":2,"\u504f\u7f6e":2,"\u505c\u6b62":2,"\u5085\u91cc\u53f6":2,"\u51b3\u7b56":2,"\u51b3\u7b56\u51fd\u6570":2,"\u51fd\u6570":2,"\u5206\u7c7b":2,"\u5224\u522b":2,"\u5224\u522b\u5f0f":2,"\u5355\u7c7b":2,"\u53c2\u6570":2,"\u53c2\u8003":2,"\u53d8\u6210":2,"\u53d8\u91cf":2,"\u53ea\u80fd":2,"\u5411\u91cf":2,"\u56de\u5f52":2,"\u56e0\u6b64":2,"\u57fa\u7c7b":2,"\u5904\u7406":2,"\u591a\u5c11":2,"\u591a\u6838":2,"\u591a\u9879":2,"\u591a\u9879\u5f0f":2,"\u5927\u5c0f":2,"\u5982\u679c":2,"\u5b58\u50a8":2,"\u5b58\u5728":2,"\u5b66\u4e60":2,"\u5b9e\u73b0":2,"\u5bb9\u5fcd":2,"\u5bb9\u5fcd\u5ea6":2,"\u5bf9\u5076":2,"\u5c31\u662f":2,"\u5de5\u4f5c":2,"\u5e26\u6765":2,"\u5e26\u6838":2,"\u5e76\u884c":2,"\u5efa\u8bae":2,"\u5f02\u5e38":2,"\u5f15\u53d1":2,"\u5f84\u5411":2,"\u5f97\u5230":2,"\u60c5\u51b5":2,"\u610f\u4e49":2,"\u6211\u4eec":2,"\u6240\u4ee5":2,"\u635f\u5931":2,"\u63a7\u5236":2,"\u652f\u6301":2,"\u6570\u636e":2,"\u6570\u91cf":2,"\u65b9\u5f0f":2,"\u662f\u5426":2,"\u66f4\u5927":2,"\u66f4\u65b0":2,"\u673a\u5236":2,"\u6761\u4ef6":2,"\u6807\u7b7e":2,"\u68c0\u6d4b":2,"\u6a21\u5757":2,"\u6a21\u578b":2,"\u6b21\u6570":2,"\u6b63\u5219":2,"\u6b63\u5e38":2,"\u6b63\u786e":2,"\u6b63\u786e\u7387":2,"\u6b64\u65f6":2,"\u6bd4\u8f83":2,"\u6c42\u89e3":2,"\u6ce8\u610f":2,"\u6ee1\u8db3":2,"\u6ee1\u8db3\u6761\u4ef6":2,"\u7136\u540e":2,"\u7279\u5f81":2,"\u72ec\u7acb":2,"\u7528\u4e8e":2,"\u76d1\u7763":2,"\u76ee\u6807":2,"\u76f4\u63a5":2,"\u77e9\u9635":2,"\u7b56\u7565":2,"\u7b97\u6cd5":2,"\u7c7b\u4f3c":2,"\u7c7b\u578b":2,"\u7cfb\u6570":2,"\u7ea6\u675f":2,"\u7ebf\u6027":2,"\u7ed9\u5b9a":2,"\u7f13\u5b58":2,"\u83b7\u53d6":2,"\u8ba1\u7b97":2,"\u8bad\u7ec3":2,"\u8bc4\u4f30":2,"\u8c03\u7528":2,"\u8f93\u5165":2,"\u8f93\u51fa":2,"\u8fb9\u754c":2,"\u8fd4\u56de":2,"\u8fd9\u91cc":2,"\u8fdb\u884c":2,"\u8fed\u4ee3":2,"\u9009\u51fa":2,"\u9009\u62e9":2,"\u903c\u8fd1":2,"\u90a3\u4e48":2,"\u91c7\u6837":2,"\u91c7\u7528":2,"\u95ee\u9898":2,"\u968f\u673a":2,"\u9700\u8981":2,"\u9884\u6d4b":2,"\u9884\u6d4b\u503c":2,"\u9ed8\u8ba4":2,"class":2,"default":2,"float":2,"for":2,"function":2,"if":2,"in":2,"int":2,"new":2,"return":2,"var":2,"with":2,_i:2,addit:2,alpha:2,alpha_i:2,alpha_t:2,and:2,arepsilon:[],arg:2,arrai:2,auto:2,base:2,bikernelsvc:2,bilinearsvc:2,binusvc:2,bool:2,cach:2,cache_s:2,calcul:2,calculate_rho:2,calculate_rho_b:2,cdot:2,coef0:2,content:1,cpu:2,data:2,decis:2,decision_funct:2,degre:2,dfrac12:2,dfrac:2,dict:2,eps:2,fals:2,featur:2,fit:2,fit_param:2,fit_transform:2,frac12:2,func:2,gamma:2,get:2,get_q:2,hing:2,http:2,index:0,input:2,it:2,iter:2,job:2,kernel:2,kernelsvc:2,kernelsvr:2,le1:2,le:2,leq:2,leqslant:2,libsmo:2,like:2,linear:2,linearsvc:2,linearsvr:2,low:2,lru:2,ly:2,ly_i:2,math:[],max:2,max_:2,max_it:2,min:2,min_:2,modul:[0,1],multiclass:2,n_featur:2,n_features_new:2,n_job:2,n_output:2,n_sampl:2,nabla:2,nabla_if:2,nabla_tf:2,ndarrai:2,none:2,normalrff:2,np:2,nu:2,numpi:2,nusolv:2,nusolverwithcach:2,nusvc:2,nusvm:2,nusvr:2,object:2,oc:2,oc_svm:2,of:2,oneclasssvm:2,option:2,or:2,output:2,ovo:2,ovr:2,packag:1,page:0,param:2,paramet:2,ploi:2,pmb:2,poli:2,predict:2,qi:2,qj:2,quad:2,r2:2,rbf:2,rff:1,rho:2,sampl:2,scale:2,score:2,search:0,select:2,self:2,set:2,sgn:2,shape:2,sigmoid:2,size:2,sklearn:2,smo:2,solver:1,solverwithcach:2,str:2,submodul:1,sum:2,sum_:2,svc:2,svm:1,svr:2,target:2,text:2,tf:2,then:2,to:2,tol:2,toler:2,top:2,transform:2,transformermixin:2,unsupervis:2,up:2,updat:2,valu:2,varepsilon:2,version:2,vert0:2,welt:2,work:2,working_set_select:2,x_1:2,x_i:2,x_l:2,x_new:2,xyz:2,y_i:2,y_t:2,z_i:2},titles:["Welcome to PySVM\u2019s documentation!","pysvm","pysvm package"],titleterms:{and:0,content:2,document:0,indic:0,modul:2,packag:2,pysvm:[0,1,2],rff:2,solver:2,submodul:2,svm:2,tabl:0,to:0,welcom:0}})
--------------------------------------------------------------------------------
/doc/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=source
11 | set BUILDDIR=build
12 |
13 | %SPHINXBUILD% >NUL 2>NUL
14 | if errorlevel 9009 (
15 | echo.
16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
17 | echo.installed, then set the SPHINXBUILD environment variable to point
18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
19 | echo.may add the Sphinx directory to PATH.
20 | echo.
21 | echo.If you don't have Sphinx installed, grab it from
22 | echo.https://www.sphinx-doc.org/
23 | exit /b 1
24 | )
25 |
26 | if "%1" == "" goto help
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/doc/source/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | #
3 | # This file only contains a selection of the most common options. For a full
4 | # list see the documentation:
5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html
6 |
7 | # -- Path setup --------------------------------------------------------------
8 |
9 | # If extensions (or modules to document with autodoc) are in another directory,
10 | # add these directories to sys.path here. If the directory is relative to the
11 | # documentation root, use os.path.abspath to make it absolute, like shown here.
12 |
13 | import os
14 | import sys
15 |
16 | sys.path.insert(0, os.path.abspath('../../'))
17 |
18 | # -- Project information -----------------------------------------------------
19 |
20 | project = 'PySVM'
21 | copyright = '2022, Welt Xing'
22 | author = 'Welt Xing'
23 |
24 | # The full version, including alpha/beta/rc tags
25 | release = '0.1'
26 |
27 | # -- General configuration ---------------------------------------------------
28 |
29 | # Add any Sphinx extension module names here, as strings. They can be
30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
31 | # ones.
32 | extensions = [
33 | 'sphinx.ext.autodoc',
34 | 'sphinx.ext.napoleon',
35 | 'sphinx.ext.doctest',
36 | 'sphinx.ext.intersphinx',
37 | 'sphinx.ext.todo',
38 | 'sphinx.ext.coverage',
39 | 'sphinx.ext.mathjax',
40 | ]
41 |
42 | # Add any paths that contain templates here, relative to this directory.
43 | templates_path = ['_templates']
44 |
45 | # The language for content autogenerated by Sphinx. Refer to documentation
46 | # for a list of supported languages.
47 | #
48 | # This is also used if you do content translation via gettext catalogs.
49 | # Usually you set "language" from the command line for these cases.
50 | language = 'zh_CN'
51 |
52 | # List of patterns, relative to source directory, that match files and
53 | # directories to ignore when looking for source files.
54 | # This pattern also affects html_static_path and html_extra_path.
55 | exclude_patterns = []
56 |
57 | # -- Options for HTML output -------------------------------------------------
58 |
59 | # The theme to use for HTML and HTML Help pages. See the documentation for
60 | # a list of builtin themes.
61 | #
62 | html_theme = 'sphinx_rtd_theme'
63 |
64 | # Add any paths that contain custom static files (such as style sheets) here,
65 | # relative to this directory. They are copied after the builtin static files,
66 | # so a file named "default.css" will overwrite the builtin "default.css".
67 | html_static_path = ['_static']
--------------------------------------------------------------------------------
/doc/source/index.rst:
--------------------------------------------------------------------------------
1 | .. PySVM documentation master file, created by
2 | sphinx-quickstart on Sat May 28 10:21:39 2022.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | Welcome to PySVM's documentation!
7 | =================================
8 |
9 | .. toctree::
10 | :maxdepth: 2
11 | :caption: Contents:
12 |
13 |
14 |
15 | Indices and tables
16 | ==================
17 |
18 | * :ref:`genindex`
19 | * :ref:`modindex`
20 | * :ref:`search`
21 |
--------------------------------------------------------------------------------
/doc/source/modules.rst:
--------------------------------------------------------------------------------
1 | pysvm
2 | =====
3 |
4 | .. toctree::
5 | :maxdepth: 4
6 |
7 | pysvm
8 |
--------------------------------------------------------------------------------
/doc/source/pysvm.rst:
--------------------------------------------------------------------------------
1 | pysvm package
2 | =============
3 |
4 | Submodules
5 | ----------
6 |
7 | pysvm.rff module
8 | ----------------
9 |
10 | .. automodule:: pysvm.rff
11 | :members:
12 | :undoc-members:
13 | :show-inheritance:
14 |
15 | pysvm.solver module
16 | -------------------
17 |
18 | .. automodule:: pysvm.solver
19 | :members:
20 | :undoc-members:
21 | :show-inheritance:
22 |
23 | pysvm.svm module
24 | ----------------
25 |
26 | .. automodule:: pysvm.svm
27 | :members:
28 | :undoc-members:
29 | :show-inheritance:
30 |
31 | Module contents
32 | ---------------
33 |
34 | .. automodule:: pysvm
35 | :members:
36 | :undoc-members:
37 | :show-inheritance:
38 |
--------------------------------------------------------------------------------
/pysvm/__init__.py:
--------------------------------------------------------------------------------
1 | from .svm import LinearSVC, LinearSVR, KernelSVC, KernelSVR, NuSVC, NuSVR, OneClassSVM
2 |
3 | __all__ = [
4 | "LinearSVC", "LinearSVR", "KernelSVC", "KernelSVR", "NuSVC", "NuSVR",
5 | "OneClassSVM"
6 | ]
7 |
--------------------------------------------------------------------------------
/pysvm/rff.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from sklearn.base import TransformerMixin
3 |
4 |
5 | class NormalRFF(TransformerMixin):
6 | '''随机傅里叶特征逼近RBF核函数'''
7 | def __init__(self, gamma=1, D=1000) -> None:
8 | super().__init__()
9 | self.gamma = gamma
10 | self.D = D
11 |
12 | def fit(self, X: np.ndarray):
13 | self.n_features = np.array(X).shape[1]
14 | self.w = np.sqrt(self.gamma * 2) * np.random.randn(
15 | self.D, self.n_features)
16 | self.b = np.random.uniform(0, 2 * np.pi, self.D)
17 | return self
18 |
19 | def transform(self, X: np.ndarray):
20 | return np.sqrt(2 / self.D) * np.cos(np.matmul(X, self.w.T) + self.b)
21 |
22 | def fit_transform(self, X: np.ndarray):
23 | return self.fit(X).transform(X)
24 |
--------------------------------------------------------------------------------
/pysvm/solver.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from functools import lru_cache
3 |
4 |
5 | class Solver:
6 | r'''SMO算法求解器,迭代求解下面的问题:
7 |
8 | .. math:: \min_{\pmb\alpha}\quad&\frac12\pmb\alpha^T\pmb Q\pmb\alpha+\pmb p^T\pmb\alpha\\
9 | \text{s.t.}\quad&\pmb y^T\pmb\alpha=0\\
10 | &0\leq\alpha_i\leq C,i=1,\cdots,l
11 |
12 | Parameters
13 | ----------
14 | Q : numpy.ndarray
15 | 优化问题中的 :math:`\pmb Q` 矩阵;
16 | p : numpy.ndarray
17 | 优化问题中的 :math:`\pmb p` 向量;
18 | y : numpy.ndarray
19 | 优化问题中的 :math:`\pmb y` 向量;
20 | C : float
21 | 优化问题中的 :math:`C` 变量;
22 | tol : float, default=1e-5
23 | 变量选择的tolerance,默认为1e-5.
24 | '''
25 | def __init__(self,
26 | Q: np.ndarray,
27 | p: np.ndarray,
28 | y: np.ndarray,
29 | C: float,
30 | tol: float = 1e-5) -> None:
31 | problem_size = p.shape[0]
32 | assert problem_size == y.shape[0]
33 | if Q is not None:
34 | assert problem_size == Q.shape[0]
35 | assert problem_size == Q.shape[1]
36 |
37 | self.Q = Q
38 | self.p = p
39 | self.y = y
40 | self.C = C
41 | self.tol = tol
42 | self.alpha = np.zeros(problem_size)
43 |
44 | # Calculate -y·▽f(α)
45 | self.neg_y_grad = -y * p
46 |
47 | def working_set_select(self):
48 | r'''工作集选择,这里采用一阶选择:
49 |
50 | .. math:: \pmb{I}_{up}(\pmb\alpha)&=\{t|\alpha_t0,y_t=-1\}\\
51 | \pmb{I}_{low}(\pmb\alpha)&=\{t|\alpha_t0,y_t=1\}\\
52 | i&\in\arg\max_{t}\{-y_t\nabla_tf(\pmb\alpha)|t\in\pmb{I}_{up}(\pmb\alpha)\}\\
53 | j&\in\arg\max_{t}\{-y_t\nabla_tf(\pmb\alpha)|t\in\pmb{I}_{low}(\pmb\alpha)\}\\
54 | '''
55 | Iup = np.argwhere(
56 | np.logical_or(
57 | np.logical_and(self.alpha < self.C, self.y > 0),
58 | np.logical_and(self.alpha > 0, self.y < 0),
59 | )).flatten()
60 | Ilow = np.argwhere(
61 | np.logical_or(
62 | np.logical_and(self.alpha < self.C, self.y < 0),
63 | np.logical_and(self.alpha > 0, self.y > 0),
64 | )).flatten()
65 |
66 | find_fail = False
67 | try:
68 | i = Iup[np.argmax(self.neg_y_grad[Iup])]
69 | j = Ilow[np.argmin(self.neg_y_grad[Ilow])]
70 | except:
71 | find_fail = True
72 |
73 | if find_fail or self.neg_y_grad[i] - self.neg_y_grad[j] < self.tol:
74 | return -1, -1
75 | return i, j
76 |
77 | def update(self, i: int, j: int, func=None):
78 | '''变量更新,在保证变量满足约束的条件下对两变量进行更新
79 |
80 | 参考.
81 | '''
82 | Qi, Qj = self.get_Q(i, func), self.get_Q(j, func)
83 | yi, yj = self.y[i], self.y[j]
84 | alpha_i, alpha_j = self.alpha[i], self.alpha[j]
85 |
86 | quad_coef = Qi[i] + Qj[j] - 2 * yi * yj * Qi[j]
87 | if quad_coef <= 0:
88 | quad_coef = 1e-12
89 |
90 | if yi * yj == -1:
91 | delta = (self.neg_y_grad[i] * yi +
92 | self.neg_y_grad[j] * yj) / quad_coef
93 | diff = alpha_i - alpha_j
94 | self.alpha[i] += delta
95 | self.alpha[j] += delta
96 |
97 | if diff > 0:
98 | if (self.alpha[j] < 0):
99 | self.alpha[j] = 0
100 | self.alpha[i] = diff
101 |
102 | else:
103 | if (self.alpha[i] < 0):
104 | self.alpha[i] = 0
105 | self.alpha[j] = -diff
106 |
107 | if diff > 0:
108 | if (self.alpha[i] > self.C):
109 | self.alpha[i] = self.C
110 | self.alpha[j] = self.C - diff
111 |
112 | else:
113 | if (self.alpha[j] > self.C):
114 | self.alpha[j] = self.C
115 | self.alpha[i] = self.C + diff
116 |
117 | else:
118 | delta = (self.neg_y_grad[j] * yj -
119 | self.neg_y_grad[i] * yi) / quad_coef
120 | sum = self.alpha[i] + self.alpha[j]
121 | self.alpha[i] -= delta
122 | self.alpha[j] += delta
123 |
124 | if sum > self.C:
125 | if self.alpha[i] > self.C:
126 | self.alpha[i] = self.C
127 | self.alpha[j] = sum - self.C
128 |
129 | else:
130 | if self.alpha[j] < 0:
131 | self.alpha[j] = 0
132 | self.alpha[i] = sum
133 |
134 | if sum > self.C:
135 | if self.alpha[j] > self.C:
136 | self.alpha[j] = self.C
137 | self.alpha[i] = sum - self.C
138 |
139 | else:
140 | if self.alpha[i] < 0:
141 | self.alpha[i] = 0
142 | self.alpha[j] = sum
143 |
144 | delta_i = self.alpha[i] - alpha_i
145 | delta_j = self.alpha[j] - alpha_j
146 | self.neg_y_grad -= self.y * (delta_i * Qi + delta_j * Qj)
147 | return delta_i, delta_j
148 |
149 | def calculate_rho(self) -> float:
150 | r'''计算偏置项
151 |
152 | .. math:: \rho=\dfrac{\sum_{i:0<\alpha_i 0,
162 | self.alpha < self.C,
163 | )
164 | if sv.sum() > 0:
165 | rho = -np.average(self.neg_y_grad[sv])
166 | else:
167 | ub_id = np.logical_or(
168 | np.logical_and(self.alpha == 0, self.y < 0),
169 | np.logical_and(self.alpha == self.C, self.y > 0),
170 | )
171 | lb_id = np.logical_or(
172 | np.logical_and(self.alpha == 0, self.y > 0),
173 | np.logical_and(self.alpha == self.C, self.y < 0),
174 | )
175 | rho = -(self.neg_y_grad[lb_id].min() +
176 | self.neg_y_grad[ub_id].max()) / 2
177 | return rho
178 |
179 | def get_Q(self, i: int, func=None):
180 | '''获取核矩阵的第i行/列,即
181 |
182 | .. math:: [K(\pmb x_1, \pmb x_i),\cdots,K(\pmb x_l, \pmb x_i)]
183 | '''
184 | return self.Q[i]
185 |
186 |
187 | class SolverWithCache(Solver):
188 | '''带核函数缓存机制的Solver:使用LRU缓存来计算Q矩阵,从而不需要计算Q矩阵,从而带来存储的问题。
189 |
190 | Parameters
191 | ----------
192 | p : numpy.ndarray
193 | 优化问题中的 :math:`\pmb p` 向量;
194 | y : numpy.ndarray
195 | 优化问题中的 :math:`\pmb y` 向量;
196 | C : float
197 | 优化问题中的 :math:`C` 变量;
198 | tol : float, default=1e-5
199 | 变量选择的tolerance,默认为1e-5.
200 | cache_size : int, default=256
201 | LRU缓存数.
202 |
203 | See also
204 | --------
205 | Solver
206 | '''
207 | cache_size = 256
208 |
209 | def __init__(self,
210 | p: np.ndarray,
211 | y: np.ndarray,
212 | C: float,
213 | tol: float = 1e-5,
214 | cache_size: int = 256) -> None:
215 | super().__init__(None, p, y, C, tol)
216 | cache_size = cache_size
217 |
218 | def working_set_select(self):
219 | return super().working_set_select()
220 |
221 | def update(self, i: int, j: int, func=None):
222 | return super().update(i, j, func=func)
223 |
224 | def calculate_rho(self):
225 | return super().calculate_rho()
226 |
227 | @lru_cache(cache_size)
228 | def get_Q(self, i, func):
229 | return func(i)
230 |
231 |
232 | class NuSolver(Solver):
233 | r'''SMO算法求解器,迭代求解下面的问题
234 |
235 | .. math:: \min_{\pmb\alpha}\quad&\frac12\pmb\alpha^T\pmb Q\pmb\alpha+\pmb p^T\pmb\alpha\\
236 | \text{s.t.}\quad&\pmb y^T\pmb\alpha=0\\
237 | &\pmb e^T\pmb\alpha=t\\
238 | &0\leq\alpha_i\leq C,i=1,\cdots,l
239 |
240 | Parameters
241 | ----------
242 | Q : numpy.ndarray
243 | 优化问题中的 :math:`\pmb Q` 矩阵;
244 | p : numpy.ndarray
245 | 优化问题中的 :math:`\pmb p` 向量;
246 | y : numpy.ndarray
247 | 优化问题中的 :math:`\pmb y` 向量;
248 | t : float
249 | 优化问题中的 :math:`t` 变量;
250 | C : float
251 | 优化问题中的 :math:`C` 变量;
252 | tol : float, default=1e-5
253 | 变量选择的tolerance,默认为1e-5.
254 | '''
255 | def __init__(self,
256 | Q: np.ndarray,
257 | p: np.ndarray,
258 | y: np.ndarray,
259 | t: float,
260 | C: float,
261 | tol: float = 1e-5) -> None:
262 | super().__init__(Q, p, y, C, tol)
263 | problem_size = p.shape[0]
264 | assert problem_size == y.shape[0]
265 | if Q is not None:
266 | assert problem_size == Q.shape[0]
267 | assert problem_size == Q.shape[1]
268 |
269 | sum_pos = sum_neg = t / 2
270 | self.alpha = np.empty(problem_size)
271 |
272 | for i in range(problem_size):
273 | if self.y[i] == 1:
274 | self.alpha[i] = min(1., sum_pos)
275 | sum_pos -= self.alpha[i]
276 | else:
277 | self.alpha[i] = min(1., sum_neg)
278 | sum_neg -= self.alpha[i]
279 |
280 | self.neg_y_grad = -self.y * (np.matmul(Q, self.alpha) + self.p)
281 | self.QD = np.diag(self.Q)
282 |
283 | def working_set_select(self, func=None):
284 | r'''采用一阶信息进行变量选择,选出两对变量,然后比较估计下降量,选出能让目标函数下降更大的变量对
285 |
286 | 存在只能选出一对的情况,此时我们不比较,直接返回这对变量;
287 | 如果两对都选不到,停止迭代。
288 | '''
289 | Iup = np.argwhere(
290 | np.logical_or(
291 | np.logical_and(self.alpha < self.C, self.y > 0),
292 | np.logical_and(self.alpha > 0, self.y < 0),
293 | )).flatten()
294 | Ilow = np.argwhere(
295 | np.logical_or(
296 | np.logical_and(self.alpha < self.C, self.y < 0),
297 | np.logical_and(self.alpha > 0, self.y > 0),
298 | )).flatten()
299 |
300 | pos_fail, neg_fail = False, False
301 | try:
302 | Imp = Iup[self.y[Iup] > 0]
303 | IMp = Ilow[self.y[Ilow] > 0]
304 | i_p = Imp[np.argmax(self.neg_y_grad[Imp])]
305 | j_p = IMp[np.argmin(self.neg_y_grad[IMp])]
306 | except:
307 | pos_fail = True
308 |
309 | try:
310 | Imn = Iup[self.y[Iup] < 0]
311 | IMn = Ilow[self.y[Ilow] < 0]
312 | i_n = Imn[np.argmax(self.neg_y_grad[Imn])]
313 | j_n = IMn[np.argmin(self.neg_y_grad[IMn])]
314 | except:
315 | neg_fail = True
316 |
317 | if pos_fail and neg_fail:
318 | return -1, -1, -1, -1
319 | elif pos_fail:
320 | return i_n, j_n, self.get_Q(i_n, func), self.get_Q(j_n, func)
321 | elif neg_fail:
322 | return i_p, j_p, self.get_Q(i_p, func), self.get_Q(j_p, func)
323 | else:
324 | grad_diff_p = self.neg_y_grad[i_p] - self.neg_y_grad[j_p]
325 | Q_ip = self.get_Q(i_p, func)
326 | quad_coef = self.QD[i_p] + self.QD[j_p] - 2 * Q_ip[j_p]
327 | if quad_coef <= 0:
328 | quad_coef = 1e-12
329 | obj_diff_p = -grad_diff_p**2 / quad_coef
330 |
331 | grad_diff_n = self.neg_y_grad[i_n] - self.neg_y_grad[j_n]
332 | Q_in = self.get_Q(i_n, func)
333 | quad_coef = self.QD[i_n] + self.QD[j_n] - 2 * Q_in[j_n]
334 | if quad_coef <= 0:
335 | quad_coef = 1e-12
336 | obj_diff_n = -grad_diff_n**2 / quad_coef
337 | if obj_diff_p < obj_diff_n:
338 | return i_p, j_p, Q_ip, self.get_Q(j_p, func)
339 | return i_n, j_n, Q_in, self.get_Q(j_n, func)
340 |
341 | def update(self, i, j, Qi, Qj):
342 | alpha_i, alpha_j = self.alpha[i], self.alpha[j]
343 | quad_coef = Qi[i] + Qj[j] - 2 * Qi[j]
344 | if quad_coef <= 0:
345 | quad_coef = 1e-12
346 | delta = self.y[i] * (self.neg_y_grad[j] -
347 | self.neg_y_grad[i]) / quad_coef
348 |
349 | sum = alpha_i + alpha_j
350 | self.alpha[i] -= delta
351 | self.alpha[j] += delta
352 |
353 | if sum > self.C:
354 | if self.alpha[i] > self.C:
355 | self.alpha[i] = self.C
356 | self.alpha[j] = sum - self.C
357 |
358 | else:
359 | if self.alpha[j] < 0:
360 | self.alpha[j] = 0
361 | self.alpha[i] = sum
362 |
363 | if sum > self.C:
364 | if self.alpha[j] > self.C:
365 | self.alpha[j] = self.C
366 | self.alpha[i] = sum - self.C
367 |
368 | else:
369 | if self.alpha[i] < 0:
370 | self.alpha[i] = 0
371 | self.alpha[j] = sum
372 |
373 | delta_i, delta_j = self.alpha[i] - alpha_i, self.alpha[j] - alpha_j
374 | self.neg_y_grad -= self.y * (delta_i * Qi + delta_j * Qj)
375 |
376 | return delta_i, delta_j
377 |
378 | def calculate_rho_b(self):
379 | grad = -self.y * self.neg_y_grad
380 | pos_sv = np.logical_and(
381 | np.logical_and(self.alpha > 0, self.alpha < 1),
382 | self.y == 1,
383 | )
384 | if pos_sv.sum() == 0:
385 | try:
386 | r1 = ((grad[np.logical_and(
387 | self.alpha == 1,
388 | self.y == 1,
389 | )]).max() + (grad[np.logical_and(
390 | self.alpha == 0,
391 | self.y == 1,
392 | )])).min() / 2
393 | except:
394 | r1 = 0
395 | else:
396 | r1 = np.average(grad[pos_sv])
397 |
398 | neg_sv = np.logical_and(
399 | np.logical_and(self.alpha > 0, self.alpha < 1),
400 | self.y == -1,
401 | )
402 | if neg_sv.sum() == 0:
403 | try:
404 | r2 = (grad[np.logical_and(
405 | self.alpha == 1,
406 | self.y == -1,
407 | )].max() + grad[np.logical_and(
408 | self.alpha == 0,
409 | self.y == -1,
410 | )].min()) / 2
411 | except:
412 | r2 = 0
413 | else:
414 | r2 = np.average(grad[neg_sv])
415 |
416 | rho = (r1 + r2) / 2
417 | b = (r2 - r1) / 2
418 |
419 | return rho, b
420 |
421 |
422 | class NuSolverWithCache(NuSolver, SolverWithCache):
423 | '''带核函数缓存机制的NuSolver:使用LRU缓存来计算Q矩阵,从而不需要计算Q矩阵,从而带来存储的问题。
424 |
425 | Parameters
426 | ----------
427 | Q : numpy.ndarray
428 | 优化问题中的 :math:`\pmb Q` 矩阵;
429 | p : numpy.ndarray
430 | 优化问题中的 :math:`\pmb p` 向量;
431 | y : numpy.ndarray
432 | 优化问题中的 :math:`\pmb y` 向量;
433 | t : float
434 | 优化问题中的 :math:`t` 变量;
435 | C : float
436 | 优化问题中的 :math:`C` 变量;
437 | tol : float, default=1e-5
438 | 变量选择的tolerance,默认为1e-5.
439 |
440 | See also
441 | --------
442 | NuSolver
443 | '''
444 | cache_size = 256
445 |
446 | def __init__(self, p, y, t, C, func, tol=1e-5, cache_size=256) -> None:
447 | self.p = p
448 | self.y = y
449 | self.C = C
450 | self.tol = tol
451 |
452 | cache_size = cache_size
453 | problem_size = p.shape[0]
454 | assert problem_size == y.shape[0]
455 |
456 | sum_pos = sum_neg = t / 2
457 | self.alpha = np.zeros(problem_size)
458 | self.neg_y_grad = np.zeros(problem_size)
459 |
460 | for i in range(problem_size):
461 | if self.y[i] == 1:
462 | self.alpha[i] = min(1., sum_pos)
463 | sum_pos -= self.alpha[i]
464 | else:
465 | self.alpha[i] = min(1., sum_neg)
466 | sum_neg -= self.alpha[i]
467 |
468 | QD = []
469 | for i in range(problem_size):
470 | self.neg_y_grad[i] = self.get_Q(i, func) @ self.alpha + self.p[i]
471 | QD.append(self.get_Q(i, func)[i])
472 | self.neg_y_grad *= -self.y
473 | self.QD = np.array(QD)
474 |
475 | def working_set_select(self, func=None):
476 | return super().working_set_select(func)
477 |
478 | def update(self, i, j, Qi, Qj):
479 | return super().update(i, j, Qi, Qj)
480 |
481 | def calculate_rho_b(self):
482 | return super().calculate_rho_b()
483 |
484 | @lru_cache(cache_size)
485 | def get_Q(self, i, func):
486 | return func(i)
487 |
--------------------------------------------------------------------------------
/pysvm/svm/__init__.py:
--------------------------------------------------------------------------------
1 | from .svc import LinearSVC, KernelSVC, NuSVC
2 | from .svr import LinearSVR, KernelSVR, NuSVR
3 | from .oc_svm import OneClassSVM
4 |
--------------------------------------------------------------------------------
/pysvm/svm/oc_svm.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | from .svc import BiNuSVC
4 | from ..solver import Solver, SolverWithCache
5 |
6 |
7 | class OneClassSVM(BiNuSVC):
8 | r'''OneClassSVM(OC_SVM),单类SVM,用于异常检测
9 |
10 | 求解对偶问题
11 |
12 | .. math:: \min_{\pmb\alpha}\quad&\dfrac{1}{2}\pmb\alpha^\top Q\pmb\alpha\\
13 | \text{s.t.}\quad&0\le\alpha_i\le1/(\nu l),i=1,\cdots l\\
14 | &\pmb e^\top\alpha=1
15 |
16 | 得到判别式
17 |
18 | .. math:: f(\pmb x)=\text{sgn}(\sum_{i=1}^ly_i\alpha_i\pmb K(\pmb x_i,\pmb x)-\rho)
19 |
20 | Parameters
21 | ----------
22 | nu : float, default=0.5
23 | 控制支持向量的数量的参数;
24 | kernel : {"linear", "poly", "rbf", "sigmoid"}, default="rbf"
25 | 核函数,默认径向基函数(RBF);
26 | degree : float, default=3
27 | 多项式核的次数,默认3;
28 | gamma : {"scale", "auto", float}, default="scale"
29 | rbf、ploy和sigmoid核的参数 :math:`\gamma`,如果用'scale',那么就是1 / (n_features * X.var()),如果用'auto',那么就是1 / n_features;
30 | coef0 : float, default=0.
31 | 核函数中的独立项。它只在"poly"和"sigmoid"中有意义;
32 | max_iter : int, default=1000
33 | SMO算法迭代次数,默认1000;
34 | rff : bool, default=False
35 | 是否采用随机傅里叶特征,默认为False;
36 | D : int, default=1000
37 | 随机傅里叶特征的采样次数,默认为1000;
38 | tol : float, default=1e-5
39 | SMO算法的容忍度参数,默认1e-5;
40 | cache_size : int, default=256
41 | lru缓存大小,默认256,如果为0则不使用缓存,计算Q矩阵然后求解.
42 | '''
43 | def __init__(self,
44 | nu: float = 0.5,
45 | kernel: str = 'rbf',
46 | degree: float = 3,
47 | gamma: float = 'scale',
48 | coef0: float = 0.,
49 | max_iter: int = 1000,
50 | rff: bool = False,
51 | D: int = 1000,
52 | tol: float = 1e-5,
53 | cache_size: int = 256) -> None:
54 | super().__init__(nu, kernel, degree, gamma, coef0, max_iter, rff, D,
55 | tol, cache_size)
56 |
57 | def fit(self, X: np.ndarray):
58 | '''训练函数,注意到OC_SVM是无监督学习,所以输入无标签
59 |
60 | Parameters
61 | ----------
62 | X : np.ndarray
63 | 训练特征数据
64 | '''
65 | X = np.array(X)
66 | l, self.n_features = X.shape
67 |
68 | kernel_func = self.register_kernel(X.std())
69 | p = np.zeros(l)
70 | y = np.ones(l)
71 |
72 | def func(i):
73 | return kernel_func(X, X[i:i + 1]).flatten()
74 |
75 | # init
76 | alpha = np.ones(l)
77 | n = int(self.nu * l)
78 | for i in range(n):
79 | alpha[i] = 1
80 | if n < l:
81 | alpha[i] = self.nu * l - n
82 | for i in range(n + 1, l):
83 | alpha[i] = 0
84 |
85 | if self.cache_size == 0:
86 | Q = kernel_func(X, X)
87 | solver = Solver(Q, p, y, 1, self.tol)
88 | solver.alpha = alpha
89 | solver.neg_y_grad = -y * np.matmul(Q, solver.alpha)
90 |
91 | else:
92 | solver = SolverWithCache(p, y, 1, self.tol, self.cache_size)
93 | solver.alpha = alpha
94 | for i in range(l):
95 | solver.neg_y_grad[i] -= y[i] * np.matmul(func(i), solver.alpha)
96 |
97 | for n_iter in range(self.max_iter):
98 | i, j = solver.working_set_select()
99 | if i < 0:
100 | break
101 |
102 | solver.update(i, j, func)
103 | else:
104 | print("OneClassSVM not coverage with {} iterations".format(
105 | self.max_iter))
106 |
107 | rho = solver.calculate_rho()
108 | self.decision_function = lambda x: np.matmul(
109 | solver.alpha,
110 | kernel_func(X, x),
111 | ) - rho
112 | return self
113 |
114 | def predict(self, X: np.ndarray):
115 | '''判别数据是否异常,正常为1,异常为-1'''
116 | pred = np.sign(self.decision_function(X))
117 | pred[pred == 0] = -1
118 | return pred
119 |
120 | def score(self, X, y):
121 | '''无监督问题不存在评估函数,因此调用该函数会引发异常'''
122 | raise NotImplementedError
123 |
--------------------------------------------------------------------------------
/pysvm/svm/svc.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from sklearn.base import BaseEstimator
3 | from sklearn.metrics import accuracy_score
4 |
5 | from sklearn.multiclass import OneVsOneClassifier, OneVsRestClassifier
6 | from ..rff import NormalRFF
7 | from ..solver import Solver, SolverWithCache, NuSolver, NuSolverWithCache
8 |
9 |
10 | class BiLinearSVC(BaseEstimator):
11 | r'''二分类线性SVM,该类被多分类LinearSVC继承,所以不需要使用它。
12 |
13 | 通过求解对偶问题
14 |
15 | .. math:: \min_{\pmb\alpha}\quad&\dfrac12\pmb\alpha^\top Q\pmb\alpha-\pmb{e}^\top\pmb{\alpha}\\
16 | \text{s.t.}\quad& \pmb{y}^\top\pmb\alpha=0,\\
17 | &0\leqslant\alpha_i\leqslant C,i=1,\cdots ,l
18 |
19 | 得到决策边界
20 |
21 | .. math:: f(\pmb x)=\sum_{i=1}^ly_i\alpha_i\pmb x_i^T\pmb x-\rho
22 |
23 | Parameters
24 | ----------
25 | C : float, default=1
26 | SVM的正则化参数,默认为1;
27 | max_iter : int, default=1000
28 | SMO算法迭代次数,默认1000;
29 | tol : float, default=1e-5
30 | SMO算法的容忍度参数,默认1e-5;
31 | cache_size : int, default=256
32 | lru缓存大小,默认256,如果为0则不使用缓存,计算Q矩阵然后求解.
33 | '''
34 | def __init__(self,
35 | C: float = 1.,
36 | max_iter: int = 1000,
37 | tol: float = 1e-5,
38 | cache_size: int = 256) -> None:
39 | super().__init__()
40 | self.C = C
41 | self.max_iter = max_iter
42 | self.tol = tol
43 | self.cache_size = cache_size
44 |
45 | def fit(self, X: np.ndarray, y: np.ndarray):
46 | '''训练模型
47 |
48 | Parameters
49 | ----------
50 | X : np.ndarray
51 | 训练集特征;
52 | y : np.array
53 | 训练集标签,建议0为负标签,1为正标签.
54 | '''
55 | X, y = np.array(X), np.array(y, dtype=float)
56 | y[y != 1] = -1
57 | l, self.n_features = X.shape
58 | p = -np.ones(l)
59 |
60 | w = np.zeros(self.n_features)
61 | if self.cache_size == 0:
62 | Q = y.reshape(-1, 1) * y * np.matmul(X, X.T)
63 | solver = Solver(Q, p, y, self.C, self.tol)
64 | else:
65 | solver = SolverWithCache(p, y, self.C, self.tol, self.cache_size)
66 |
67 | def func(i):
68 | return y * np.matmul(X, X[i]) * y[i]
69 |
70 | for n_iter in range(self.max_iter):
71 | i, j = solver.working_set_select()
72 | if i < 0:
73 | break
74 |
75 | delta_i, delta_j = solver.update(i, j, func)
76 | w += delta_i * y[i] * X[i] + delta_j * y[j] * X[j]
77 | else:
78 | print("LinearSVC not coverage with {} iterations".format(
79 | self.max_iter))
80 |
81 | self.coef_ = (w, solver.calculate_rho())
82 | return self
83 |
84 | def decision_function(self, X: np.ndarray) -> np.ndarray:
85 | '''决策函数,输出预测值'''
86 | return np.matmul(self.coef_[0], np.array(X).T) - self.coef_[-1]
87 |
88 | def predict(self, X: np.ndarray) -> np.ndarray:
89 | '''预测函数,输出预测标签(0-1)'''
90 | return (self.decision_function(np.array(X)) >= 0).astype(int)
91 |
92 | def score(self, X: np.ndarray, y: np.ndarray) -> float:
93 | '''评估函数,给定特征和标签,输出正确率'''
94 | return accuracy_score(y, self.predict(X))
95 |
96 |
97 | class LinearSVC(BiLinearSVC):
98 | r'''多分类线性SVM,使用sklearn的multiclass模块实现了多分类。
99 |
100 | Parameters
101 | ----------
102 | C : float, default=1
103 | SVM的正则化参数,默认为1;
104 | max_iter : int, default=1000
105 | SMO算法迭代次数,默认1000;
106 | tol : float, default=1e-5
107 | SMO算法的容忍度参数,默认1e-5;
108 | cache_size : int, default=256
109 | lru缓存大小,默认256,如果为0则不使用缓存,计算Q矩阵然后求解;
110 | multiclass : {"ovr", "ovo"}, default="ovr"
111 | 多分类策略,ovr(一对多)或ovo(一对一),默认ovr;
112 | n_jobs : int, default=None
113 | 是否采用多核,使用多少CPU并行,默认不采用。
114 | '''
115 | def __init__(self,
116 | C: float = 1.,
117 | max_iter: int = 1000,
118 | tol: float = 1e-5,
119 | cache_size: int = 256,
120 | multiclass: str = "ovr",
121 | n_jobs=None) -> None:
122 | super().__init__(C, max_iter, tol, cache_size)
123 | self.multiclass = multiclass
124 | self.n_jobs = n_jobs
125 | params = {
126 | "estimator": BiLinearSVC(C, max_iter, tol, cache_size),
127 | "n_jobs": n_jobs,
128 | }
129 | self.multiclass_model: OneVsOneClassifier = {
130 | "ovo": OneVsOneClassifier(**params),
131 | "ovr": OneVsRestClassifier(**params),
132 | }[multiclass]
133 |
134 | def fit(self, X: np.ndarray, y: np.ndarray):
135 | '''训练模型
136 |
137 | Parameters
138 | ----------
139 | X : np.ndarray
140 | 训练集特征;
141 | y : np.array
142 | 训练集标签,建议0为负标签,1为正标签.
143 |
144 | Return
145 | ------
146 | self : LinearSVC
147 | '''
148 | self.multiclass_model.fit(X, y)
149 | return self
150 |
151 | def decision_function(self, X: np.ndarray):
152 | return self.multiclass_model.decision_function(X)
153 |
154 | def predict(self, X: np.ndarray):
155 | return self.multiclass_model.predict(X)
156 |
157 | def score(self, X: np.ndarray, y: np.ndarray):
158 | return self.multiclass_model.score(X, y)
159 |
160 |
161 | class BiKernelSVC(BiLinearSVC):
162 | r'''二分类核SVM,该类被多分类KernelSVC继承,所以不需要使用它。优化问题与BiLinearSVC相同,只是Q矩阵定义不同。
163 |
164 | 此时的决策边界
165 |
166 | .. math:: f(\pmb x)=\sum_{i=1}^ly_i\alpha_i K(\pmb x_i, \pmb x)-\rho
167 |
168 | Parameters
169 | ----------
170 | C : float, default=1
171 | SVM的正则化参数,默认为1;
172 | kernel : {"linear", "poly", "rbf", "sigmoid"}, default="rbf"
173 | 核函数,默认径向基函数(RBF);
174 | degree : float, default=3
175 | 多项式核的次数,默认3;
176 | gamma : {"scale", "auto", float}, default="scale"
177 | rbf、ploy和sigmoid核的参数 :math:`\gamma`,如果用'scale',那么就是1 / (n_features * X.var()),如果用'auto',那么就是1 / n_features;
178 | coef0 : float, default=0.
179 | 核函数中的独立项。它只在"poly"和"sigmoid"中有意义;
180 | max_iter : int, default=1000
181 | SMO算法迭代次数,默认1000;
182 | rff : bool, default=False
183 | 是否采用随机傅里叶特征,默认为False;
184 | D : int, default=1000
185 | 随机傅里叶特征的采样次数,默认为1000;
186 | tol : float, default=1e-5
187 | SMO算法的容忍度参数,默认1e-5;
188 | cache_size : int, default=256
189 | lru缓存大小,默认256,如果为0则不使用缓存,计算Q矩阵然后求解.
190 | '''
191 | def __init__(self,
192 | C: float = 1.,
193 | kernel: str = 'rbf',
194 | degree: float = 3,
195 | gamma: str = 'scale',
196 | coef0: float = 0,
197 | max_iter: int = 1000,
198 | rff: bool = False,
199 | D: int = 1000,
200 | tol: float = 1e-5,
201 | cache_size: int = 256) -> None:
202 | super().__init__(C, max_iter, tol, cache_size)
203 | self.kernel = kernel
204 | self.gamma = gamma
205 | self.degree = degree
206 | self.coef0 = coef0
207 | self.rff = rff
208 | self.D = D
209 |
210 | def register_kernel(self, std: float):
211 | '''注册核函数
212 |
213 | Parameters
214 | ----------
215 | std : 输入数据的标准差,用于rbf='scale'的情况
216 | '''
217 | if type(self.gamma) == str:
218 | gamma = {
219 | 'scale': 1 / (self.n_features * std),
220 | 'auto': 1 / self.n_features,
221 | }[self.gamma]
222 | else:
223 | gamma = self.gamma
224 |
225 | if self.rff:
226 | rff = NormalRFF(gamma, self.D).fit(np.ones((1, self.n_features)))
227 | rbf_func = lambda x, y: np.matmul(rff.transform(x),
228 | rff.transform(y).T)
229 | else:
230 | rbf_func = lambda x, y: np.exp(-gamma * (
231 | (x**2).sum(1, keepdims=True) +
232 | (y**2).sum(1) - 2 * np.matmul(x, y.T)))
233 |
234 | degree = self.degree
235 | coef0 = self.coef0
236 | return {
237 | "linear": lambda x, y: np.matmul(x, y.T),
238 | "poly": lambda x, y: (gamma * np.matmul(x, y.T) + coef0)**degree,
239 | "rbf": rbf_func,
240 | "sigmoid": lambda x, y: np.tanh(gamma * np.matmul(x, y.T) + coef0)
241 | }[self.kernel]
242 |
243 | def fit(self, X: np.ndarray, y: np.ndarray):
244 | X, y = np.array(X), np.array(y, dtype=float)
245 | y[y != 1] = -1
246 | l, self.n_features = X.shape
247 | p = -np.ones(l)
248 |
249 | kernel_func = self.register_kernel(X.std())
250 |
251 | if self.cache_size == 0:
252 | Q = y.reshape(-1, 1) * y * kernel_func(X, X)
253 | solver = Solver(Q, p, y, self.C, self.tol)
254 | else:
255 | solver = SolverWithCache(p, y, self.C, self.tol, self.cache_size)
256 |
257 | def func(i):
258 | return y * kernel_func(X, X[i:i + 1]).flatten() * y[i]
259 |
260 | for n_iter in range(self.max_iter):
261 | i, j = solver.working_set_select()
262 | if i < 0:
263 | break
264 | solver.update(i, j, func)
265 | else:
266 | print("KernelSVC not coverage with {} iterations".format(
267 | self.max_iter))
268 |
269 | self.decision_function = lambda x: np.matmul(
270 | solver.alpha * y,
271 | kernel_func(X, x),
272 | ) - solver.calculate_rho()
273 | return self
274 |
275 | def predict(self, X: np.ndarray) -> np.ndarray:
276 | return super().predict(X)
277 |
278 | def score(self, X: np.ndarray, y: np.ndarray) -> float:
279 | return super().score(X, y)
280 |
281 |
282 | class KernelSVC(LinearSVC, BiKernelSVC):
283 | r'''多分类核SVM。
284 |
285 | Parameters
286 | ----------
287 | C : float, default=1
288 | SVM的正则化参数,默认为1;
289 | kernel : {"linear", "poly", "rbf", "sigmoid"}, default="rbf"
290 | 核函数,默认径向基函数(RBF);
291 | degree : float, default=3
292 | 多项式核的次数,默认3;
293 | gamma : {"scale", "auto", float}, default="scale"
294 | rbf、ploy和sigmoid核的参数 :math:`\gamma`,如果用'scale',那么就是1 / (n_features * X.var()),如果用'auto',那么就是1 / n_features;
295 | coef0 : float, default=0.
296 | 核函数中的独立项。它只在"poly"和"sigmoid"中有意义;
297 | max_iter : int, default=1000
298 | SMO算法迭代次数,默认1000;
299 | rff : bool, default=False
300 | 是否采用随机傅里叶特征,默认为False;
301 | D : int, default=1000
302 | 随机傅里叶特征的采样次数,默认为1000;
303 | tol : float, default=1e-5
304 | SMO算法的容忍度参数,默认1e-5;
305 | cache_size : int, default=256
306 | lru缓存大小,默认256,如果为0则不使用缓存,计算Q矩阵然后求解.
307 | multiclass : {"ovr", "ovo"}, default="ovr"
308 | 多分类策略,ovr(一对多)或ovo(一对一),默认ovr;
309 | n_jobs : int, default=None
310 | 是否采用多核,使用多少CPU并行,默认不采用。
311 | '''
312 | def __init__(self,
313 | C: float = 1.,
314 | kernel: str = 'rbf',
315 | degree: float = 3,
316 | gamma: float = 'scale',
317 | coef0: float = 0.,
318 | max_iter: int = 1000,
319 | rff: bool = False,
320 | D: int = 1000,
321 | tol: float = 1e-5,
322 | cache_size: int = 256,
323 | multiclass: str = "ovr",
324 | n_jobs: int = None) -> None:
325 | super().__init__(C, max_iter, tol, cache_size)
326 | self.kernel = kernel
327 | self.gamma = gamma
328 | self.degree = degree
329 | self.coef0 = coef0
330 | self.rff = rff
331 | self.D = D
332 | params = {
333 | "estimator":
334 | BiKernelSVC(C, kernel, degree, gamma, coef0, max_iter, rff, D, tol,
335 | cache_size),
336 | "n_jobs":
337 | n_jobs,
338 | }
339 | self.multiclass_model = {
340 | "ovo": OneVsOneClassifier(**params),
341 | "ovr": OneVsRestClassifier(**params),
342 | }[multiclass]
343 |
344 | def fit(self, X: np.ndarray, y: np.ndarray):
345 | return super().fit(X, y)
346 |
347 | def decision_function(self, X: np.ndarray):
348 | return super().decision_function(X)
349 |
350 | def predict(self, X: np.ndarray):
351 | return super().predict(X)
352 |
353 | def score(self, X: np.ndarray, y: np.ndarray):
354 | return super().score(X, y)
355 |
356 |
357 | class BiNuSVC(BiKernelSVC):
358 | r'''二分类NuSVM,通过参数 :math:`\nu`来控制支持向量的数量。
359 |
360 | 通过求解对偶问题
361 |
362 | .. math:: \min_{\pmb\alpha}\quad&\dfrac12\pmb\alpha^\top Q\pmb\alpha\\
363 | \text{s.t.}\quad&0\leqslant\alpha_i\leqslant\frac{1}{l},,i=1,\cdots,l\\
364 | &\pmb{e}^\top\pmb\alpha\geqslant \nu,\pmb y^\top\pmb{\alpha}=0
365 |
366 | 得到决策边界
367 |
368 | .. math:: f(\pmb x)=\sum_{i=1}^ly_i\alpha_i\pmb K(\pmb x_i,\pmb x)-\rho
369 |
370 | Parameters
371 | ----------
372 | nu : float, default=0.5
373 | NuSVM的参数,控制支持向量的数量;
374 | kernel : {"linear", "poly", "rbf", "sigmoid"}, default="rbf"
375 | 核函数,默认径向基函数(RBF);
376 | degree : float, default=3
377 | 多项式核的次数,默认3;
378 | gamma : {"scale", "auto", float}, default="scale"
379 | rbf、ploy和sigmoid核的参数 :math:`\gamma`,如果用'scale',那么就是1 / (n_features * X.var()),如果用'auto',那么就是1 / n_features;
380 | coef0 : float, default=0.
381 | 核函数中的独立项。它只在"poly"和"sigmoid"中有意义;
382 | max_iter : int, default=1000
383 | SMO算法迭代次数,默认1000;
384 | rff : bool, default=False
385 | 是否采用随机傅里叶特征,默认为False;
386 | D : int, default=1000
387 | 随机傅里叶特征的采样次数,默认为1000;
388 | tol : float, default=1e-5
389 | SMO算法的容忍度参数,默认1e-5;
390 | cache_size : int, default=256
391 | lru缓存大小,默认256,如果为0则不使用缓存,计算Q矩阵然后求解.
392 | '''
393 | def __init__(self,
394 | nu: float = 0.5,
395 | kernel: str = 'rbf',
396 | degree: float = 3,
397 | gamma: float = 'scale',
398 | coef0: float = 0.,
399 | max_iter: int = 1000,
400 | rff: bool = False,
401 | D: int = 1000,
402 | tol: float = 1e-5,
403 | cache_size: int = 256) -> None:
404 | super().__init__(1, kernel, degree, gamma, coef0, max_iter, rff, D,
405 | tol, cache_size)
406 | self.nu = nu
407 |
408 | def fit(self, X: np.ndarray, y: np.ndarray):
409 | X, y = np.array(X), np.array(y, dtype=float)
410 | y[y != 1] = -1
411 | l, self.n_features = X.shape
412 | p = np.zeros(l)
413 |
414 | kernel_func = self.register_kernel(X.std())
415 |
416 | def func(i):
417 | return y * kernel_func(X, X[i:i + 1]).flatten() * y[i]
418 |
419 | if self.cache_size == 0:
420 | Q = y.reshape(-1, 1) * y * kernel_func(X, X)
421 | solver = NuSolver(Q, p, y, self.nu * l, self.C, self.tol)
422 | else:
423 | solver = NuSolverWithCache(p, y, self.nu * l, self.C, func,
424 | self.tol, self.cache_size)
425 |
426 | for n_iter in range(self.max_iter):
427 | i, j, Qi, Qj = solver.working_set_select(func)
428 | if i < 0:
429 | break
430 | solver.update(i, j, Qi, Qj)
431 | else:
432 | print("NuSVC not coverage with {} iterations".format(
433 | self.max_iter))
434 |
435 | rho, b = solver.calculate_rho_b()
436 | self.decision_function = lambda x: np.matmul(
437 | solver.alpha * y,
438 | kernel_func(X, x),
439 | ) / rho + b / rho
440 | return self
441 |
442 | def predict(self, X: np.ndarray):
443 | return super().predict(X)
444 |
445 | def score(self, X: np.ndarray, y: np.ndarray):
446 | return super().score(X, y)
447 |
448 |
449 | class NuSVC(KernelSVC, BiNuSVC):
450 | '''多分类NuSVM
451 |
452 | Parameters
453 | ----------
454 | nu : float, default=0.5
455 | NuSVM的参数,控制支持向量的数量;
456 | kernel : {"linear", "poly", "rbf", "sigmoid"}, default="rbf"
457 | 核函数,默认径向基函数(RBF);
458 | degree : float, default=3
459 | 多项式核的次数,默认3;
460 | gamma : {"scale", "auto", float}, default="scale"
461 | rbf、ploy和sigmoid核的参数 :math:`\gamma`,如果用'scale',那么就是1 / (n_features * X.var()),如果用'auto',那么就是1 / n_features;
462 | coef0 : float, default=0.
463 | 核函数中的独立项。它只在"poly"和"sigmoid"中有意义;
464 | max_iter : int, default=1000
465 | SMO算法迭代次数,默认1000;
466 | rff : bool, default=False
467 | 是否采用随机傅里叶特征,默认为False;
468 | D : int, default=1000
469 | 随机傅里叶特征的采样次数,默认为1000;
470 | tol : float, default=1e-5
471 | SMO算法的容忍度参数,默认1e-5;
472 | cache_size : int, default=256
473 | lru缓存大小,默认256,如果为0则不使用缓存,计算Q矩阵然后求解.
474 | multiclass : {"ovr", "ovo"}, default="ovr"
475 | 多分类策略,ovr(一对多)或ovo(一对一),默认ovr;
476 | n_jobs : int, default=None
477 | 是否采用多核,使用多少CPU并行,默认不采用。
478 | '''
479 | def __init__(self,
480 | nu: float = 0.5,
481 | kernel: str = 'rbf',
482 | degree: float = 3,
483 | gamma: float = 'scale',
484 | coef0: float = 0.,
485 | max_iter: int = 1000,
486 | rff: bool = False,
487 | D: int = 1000,
488 | tol: float = 1e-5,
489 | cache_size: int = 256,
490 | multiclass: str = "ovr",
491 | n_jobs: int = None) -> None:
492 | super().__init__(1, kernel, degree, gamma, coef0, max_iter, rff, D,
493 | tol, cache_size, multiclass, n_jobs)
494 | self.nu = nu
495 | params = {
496 | "estimator":
497 | BiNuSVC(nu, kernel, degree, gamma, coef0, max_iter, rff, D, tol,
498 | cache_size),
499 | "n_jobs":
500 | n_jobs,
501 | }
502 | self.multiclass_model: OneVsOneClassifier = {
503 | "ovo": OneVsOneClassifier(**params),
504 | "ovr": OneVsRestClassifier(**params),
505 | }[multiclass]
506 |
507 | def fit(self, X: np.ndarray, y: np.ndarray):
508 | return super().fit(X, y)
509 |
510 | def predict(self, X: np.ndarray):
511 | return super().predict(X)
512 |
513 | def score(self, X: np.ndarray, y: np.ndarray):
514 | return super().score(X, y)
515 |
--------------------------------------------------------------------------------
/pysvm/svm/svr.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from sklearn.metrics import r2_score
3 |
4 | from .svc import BiLinearSVC, BiKernelSVC
5 | from ..solver import Solver, SolverWithCache, NuSolver, NuSolverWithCache
6 |
7 |
8 | class LinearSVR(BiLinearSVC):
9 | r'''线性SVM回归(SVR)
10 |
11 | 原对偶问题
12 |
13 | .. math:: \min_{\pmb{\alpha},\pmb{\alpha}^*}\quad&\dfrac12(\pmb{\alpha}-\pmb{\alpha}^*)^\top Q(\pmb{\alpha}-\pmb{\alpha}^*)+\varepsilon\sum_{i=1}^l(\alpha_i+\alpha_i^*)+\sum_{i=1}^l z_i({\alpha}_i-{\alpha}_i^*)\\
14 | \text{s.t.}\quad&\pmb e^\top(\pmb{\alpha}-\pmb{\alpha}^*)=0\\
15 | &0\leqslant\alpha_i,\alpha^*_i\leqslant C,i=1,\cdots ,l
16 |
17 | 我们将其变成单变量优化问题,然后使用SMO求解,参考https://welts.xyz/2021/09/16/svr/。得到决策边界
18 |
19 | .. math:: f(\pmb x)=\sum_{i=1}^l(-\alpha_i+\alpha_i^*)\pmb x_i^T\pmb x-\rho
20 |
21 | Parameters
22 | ----------
23 | C : float, default=1
24 | SVM的正则化参数,默认为1;
25 | eps : float, default=0
26 | :math:`\varepsilon`-hinge损失的参数;
27 | max_iter : int, default=1000
28 | SMO算法迭代次数,默认1000;
29 | tol : float, default=1e-5
30 | SMO算法的容忍度参数,默认1e-5;
31 | cache_size : int, default=256
32 | lru缓存大小,默认256,如果为0则不使用缓存,计算Q矩阵然后求解.
33 | '''
34 | def __init__(self,
35 | C: float = 1.,
36 | eps: float = 0.,
37 | max_iter: int = 1000,
38 | tol: float = 1e-5,
39 | cache_size: int = 256) -> None:
40 | super().__init__(C, max_iter, tol, cache_size)
41 | self.eps = eps
42 |
43 | def fit(self, X: np.ndarray, y: np.ndarray):
44 | '''训练模型
45 |
46 | Parameters
47 | ----------
48 | X : np.ndarray
49 | 训练集特征;
50 | y : np.array
51 | 训练集target
52 |
53 | Return
54 | ------
55 | self : LinearSVR
56 | '''
57 | X, z = np.array(X), np.array(y)
58 | l, self.n_features = X.shape
59 |
60 | y = np.empty(2 * l)
61 | y[:l], y[l:] = 1., -1.
62 |
63 | p = np.ones(2 * l) * self.eps
64 | p[:l] -= z
65 | p[l:] += z
66 |
67 | w = np.zeros(self.n_features)
68 |
69 | if self.cache_size == 0:
70 | Q = np.matmul(X, X.T)
71 | Q2 = np.r_[Q, -Q]
72 | solver = Solver(np.c_[Q2, -Q2], p, y, self.C, self.tol)
73 | else:
74 | solver = SolverWithCache(p, y, self.C, self.tol, self.cache_size)
75 |
76 | def func(i):
77 | if i < l:
78 | Qi = np.matmul(X, X[i])
79 | else:
80 | Qi = -np.matmul(X, X[i - l])
81 | return np.r_[Qi, -Qi]
82 |
83 | for n_iter in range(self.max_iter):
84 | i, j = solver.working_set_select()
85 | if i < 0:
86 | break
87 |
88 | delta_i, delta_j = solver.update(i, j, func)
89 | w += (delta_i * y[i] * X[i if i < l else i - l] +
90 | delta_j * y[j] * X[j if j < l else j - l])
91 | else:
92 | print("LinearSVR not coverage with {} iterations".format(
93 | self.max_iter))
94 |
95 | self.coef_ = (w, solver.calculate_rho())
96 | return self
97 |
98 | def decision_function(self, X: np.ndarray):
99 | return super().decision_function(X)
100 |
101 | def predict(self, X: np.ndarray):
102 | '''预测函数,输出预测值'''
103 | return self.decision_function(X)
104 |
105 | def score(self, X: np.ndarray, y: np.ndarray):
106 | '''评估函数,给定特征和标签,输出r2系数'''
107 | return r2_score(y, self.predict(X))
108 |
109 |
110 | class KernelSVR(BiKernelSVC):
111 | r'''核支持向量回归
112 |
113 | Parameters
114 | ----------
115 | C : float, default=1
116 | SVM的正则化参数,默认为1;
117 | eps : float, default=0
118 | :math:`\varepsilon`-hinge损失的参数;
119 | kernel : {"linear", "poly", "rbf", "sigmoid"}, default="rbf"
120 | 核函数,默认径向基函数(RBF);
121 | degree : float, default=3
122 | 多项式核的次数,默认3;
123 | gamma : {"scale", "auto", float}, default="scale"
124 | rbf、ploy和sigmoid核的参数 :math:`\gamma`,如果用'scale',那么就是1 / (n_features * X.var()),如果用'auto',那么就是1 / n_features;
125 | coef0 : float, default=0.
126 | 核函数中的独立项。它只在"poly"和"sigmoid"中有意义;
127 | max_iter : int, default=1000
128 | SMO算法迭代次数,默认1000;
129 | rff : bool, default=False
130 | 是否采用随机傅里叶特征,默认为False;
131 | D : int, default=1000
132 | 随机傅里叶特征的采样次数,默认为1000;
133 | tol : float, default=1e-5
134 | SMO算法的容忍度参数,默认1e-5;
135 | cache_size : int, default=256
136 | lru缓存大小,默认256,如果为0则不使用缓存,计算Q矩阵然后求解.
137 | '''
138 | def __init__(self,
139 | C: int = 1.,
140 | eps: float = 0.,
141 | kernel: str = 'rbf',
142 | degree: float = 3,
143 | gamma: float = 'scale',
144 | coef0: float = 0.,
145 | max_iter: int = 1000,
146 | rff: bool = False,
147 | D: int = 1000,
148 | tol: float = 1e-5,
149 | cache_size: int = 256) -> None:
150 | super().__init__(C, kernel, degree, gamma, coef0, max_iter, rff, D,
151 | tol, cache_size)
152 | self.eps = eps
153 |
154 | def fit(self, X: np.ndarray, y: np.ndarray):
155 | X, z = np.array(X), np.array(y)
156 | l, self.n_features = X.shape
157 |
158 | y = np.empty(2 * l)
159 | y[:l], y[l:] = 1., -1.
160 |
161 | p = np.ones(2 * l) * self.eps
162 | p[:l] -= z
163 | p[l:] += z
164 |
165 | kernel_func = self.register_kernel(X.std())
166 |
167 | if self.cache_size == 0:
168 | Q = np.matmul(X, X.T)
169 | Q2 = np.r_[Q, -Q]
170 | solver = Solver(np.c_[Q2, -Q2], p, y, self.C, self.tol)
171 | else:
172 | solver = SolverWithCache(p, y, self.C, self.tol, self.cache_size)
173 |
174 | def func(i):
175 | if i < l:
176 | Qi = kernel_func(X, X[i:i + 1]).flatten()
177 | else:
178 | Qi = -kernel_func(X, X[i - l:i - l + 1]).flatten()
179 | return np.r_[Qi, -Qi]
180 |
181 | for n_iter in range(self.max_iter):
182 | i, j = solver.working_set_select()
183 | if i < 0:
184 | break
185 |
186 | solver.update(i, j, func)
187 | else:
188 | print("KernelSVR not coverage with {} iterations".format(
189 | self.max_iter))
190 |
191 | self.decision_function = lambda x: np.matmul(
192 | solver.alpha[:l] - solver.alpha[l:],
193 | kernel_func(X, x),
194 | ) - solver.calculate_rho()
195 |
196 | return self
197 |
198 | def predict(self, X: np.ndarray):
199 | '''预测函数,输出预测值'''
200 | return self.decision_function(np.array(X))
201 |
202 | def score(self, X: np.ndarray, y: np.ndarray):
203 | '''评估函数,给定特征和标签,输出r2系数'''
204 | return r2_score(y, self.predict(X))
205 |
206 |
207 | class NuSVR(KernelSVR):
208 | r'''NuSVM回归
209 |
210 | 对偶问题求解
211 |
212 | .. math:: \min_{\pmb{\alpha},\pmb{\alpha}^*}\quad&\dfrac12(\pmb{\alpha}-\pmb{\alpha}^*)^\top Q(\pmb{\alpha}-\pmb{\alpha}^*)+\pmb z^\top({\pmb\alpha}-{\pmb\alpha}^*)\\
213 | \text{s.t.}\quad&\pmb e^\top(\pmb{\alpha}-\pmb{\alpha}^*)=0,\pmb e^\top(\pmb\alpha+\pmb\alpha_i^*)\leqslant C\nu\\
214 | &0\leqslant\alpha_i,\alpha^*_i\leqslant C/l,i=1,\cdots ,l
215 |
216 | 处理方式和LinearSVR中的类似.
217 |
218 | Parameters
219 | ----------
220 | C : float, default=1
221 | SVM的正则化参数,默认为1;
222 | nu : float, default=0.5
223 | NuSVM的参数,控制支持向量的数量;
224 | kernel : {"linear", "poly", "rbf", "sigmoid"}, default="rbf"
225 | 核函数,默认径向基函数(RBF);
226 | degree : float, default=3
227 | 多项式核的次数,默认3;
228 | gamma : {"scale", "auto", float}, default="scale"
229 | rbf、ploy和sigmoid核的参数 :math:`\gamma`,如果用'scale',那么就是1 / (n_features * X.var()),如果用'auto',那么就是1 / n_features;
230 | coef0 : float, default=0.
231 | 核函数中的独立项。它只在"poly"和"sigmoid"中有意义;
232 | max_iter : int, default=1000
233 | SMO算法迭代次数,默认1000;
234 | rff : bool, default=False
235 | 是否采用随机傅里叶特征,默认为False;
236 | D : int, default=1000
237 | 随机傅里叶特征的采样次数,默认为1000;
238 | tol : float, default=1e-5
239 | SMO算法的容忍度参数,默认1e-5;
240 | cache_size : int, default=256
241 | lru缓存大小,默认256,如果为0则不使用缓存,计算Q矩阵然后求解.
242 | '''
243 | def __init__(self,
244 | C: float = 1.,
245 | nu: float = 0.5,
246 | kernel: str = 'rbf',
247 | degree: float = 3,
248 | gamma: float = 'scale',
249 | coef0: float = 0.,
250 | max_iter: int = 1000,
251 | rff: bool = False,
252 | D: int = 1000,
253 | tol: float = 1e-5,
254 | cache_size: int = 256) -> None:
255 | super().__init__(C, 0, kernel, degree, gamma, coef0, max_iter, rff, D,
256 | tol, cache_size)
257 | self.nu = nu
258 |
259 | def fit(self, X: np.ndarray, y: np.ndarray):
260 | X, z = np.array(X), np.array(y)
261 | l, self.n_features = X.shape
262 |
263 | y = np.empty(2 * l)
264 | y[:l], y[l:] = 1, -1
265 |
266 | p = np.empty(2 * l)
267 | p[:l], p[l:] = -z, z
268 |
269 | kernel_func = self.register_kernel(X.std())
270 |
271 | def func(i):
272 | if i < l:
273 | Qi = kernel_func(X, X[i:i + 1]).flatten()
274 | else:
275 | Qi = -kernel_func(X, X[i - l:i - l + 1]).flatten()
276 | return np.r_[Qi, -Qi]
277 |
278 | if self.cache_size == 0:
279 | Q = kernel_func(X, X)
280 | Q2 = np.r_[Q, -Q]
281 | solver = NuSolver(np.c_[Q2, -Q2], p, y, self.C * l * self.nu, self.C, self.tol)
282 | else:
283 | solver = NuSolverWithCache(p, y, self.C * l * self.nu, self.C,
284 | func, self.tol, self.cache_size)
285 |
286 | for n_iter in range(self.max_iter):
287 | i, j, Qi, Qj = solver.working_set_select(func)
288 | if i < 0:
289 | break
290 |
291 | solver.update(i, j, Qi, Qj)
292 | else:
293 | print("NuSVR not coverage with {} iterations".format(
294 | self.max_iter))
295 |
296 | rho, b = solver.calculate_rho_b()
297 | self.decision_function = lambda x: np.matmul(
298 | solver.alpha[:l] - solver.alpha[l:],
299 | kernel_func(X, x),
300 | ) + b
301 | return self
302 |
303 | def predict(self, X: np.ndarray):
304 | return super().predict(X)
305 |
306 | def score(self, X: np.ndarray, y: np.ndarray):
307 | return super().score(X, y)
308 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools #enables develop
2 |
3 | setuptools.setup(
4 | name='pysvm',
5 | version='0.2',
6 | description='PySVM : A NumPy implementation of SVM based on SMO algorithm',
7 | author="Welt",
8 | author_email="xingcy@smail.nju.edu.cn",
9 | maintainer="Welt",
10 | maintainer_email="xingcy@smail.nju.edu.cn",
11 | packages=['pysvm', 'pysvm/svm'],
12 | license='MIT License',
13 | long_description_content_type="text/markdown",
14 | long_description=open('README.md', encoding='utf-8').read(),
15 | install_requires=[ #自动安装依赖
16 | 'numpy', 'sklearn'
17 | ],
18 | url='https://github.com/Kaslanarian/PySVM',
19 | )
20 |
--------------------------------------------------------------------------------
/src/oc_svm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/src/oc_svm.png
--------------------------------------------------------------------------------
/src/visual_classify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/src/visual_classify.png
--------------------------------------------------------------------------------
/src/visual_regression.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WeltXing/PySVM/e890e9b92407af2c2c7b5c9451eae9ce9fd908e9/src/visual_regression.png
--------------------------------------------------------------------------------
/tests/dataset_classify.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from pysvm import LinearSVC, KernelSVC, NuSVC
3 | from sklearn.datasets import load_iris, load_breast_cancer, load_digits, load_wine
4 | from sklearn.preprocessing import StandardScaler
5 | from sklearn.model_selection import train_test_split
6 |
7 | np.random.seed(2022)
8 |
9 | score = np.zeros((3, 4))
10 | for i, load_dataset in enumerate(
11 | [load_iris, load_wine, load_breast_cancer, load_digits]):
12 | X, y = load_dataset(return_X_y=True)
13 | train_X, test_X, train_y, test_y = train_test_split(X, y)
14 | stder = StandardScaler().fit(train_X)
15 | train_X = stder.transform(train_X)
16 | test_X = stder.transform(test_X)
17 |
18 | for j, model in enumerate([LinearSVC, KernelSVC, NuSVC]):
19 | score[j, i] = model(
20 | n_jobs=6,
21 | max_iter=1000,
22 | ).fit(train_X, train_y).score(test_X, test_y)
23 |
24 | print(score)
--------------------------------------------------------------------------------
/tests/dataset_regression.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | from pysvm import LinearSVR, KernelSVR, NuSVR
3 | from sklearn.datasets import load_boston, load_diabetes
4 | from sklearn.preprocessing import StandardScaler
5 | from sklearn.model_selection import train_test_split
6 |
7 | np.random.seed(2022)
8 |
9 | score = np.zeros((3, 2))
10 | for i, load_dataset in enumerate([load_boston, load_diabetes]):
11 | X, y = load_dataset(return_X_y=True)
12 | train_X, test_X, train_y, test_y = train_test_split(X, y)
13 | stder = StandardScaler().fit(train_X)
14 | train_X = stder.transform(train_X)
15 | test_X = stder.transform(test_X)
16 |
17 | for j, model in enumerate([LinearSVR, KernelSVR, NuSVR]):
18 | score[j, i] = model(max_iter=1000).fit(train_X,
19 | train_y).score(test_X, test_y)
20 |
21 | print(score)
22 |
--------------------------------------------------------------------------------
/tests/visual_classify.py:
--------------------------------------------------------------------------------
1 | from sklearn.datasets import make_classification
2 | import matplotlib.pyplot as plt
3 | import numpy as np
4 | from pysvm import LinearSVC, KernelSVC
5 |
6 | try:
7 | import seaborn as sns
8 | sns.set()
9 | except:
10 | pass
11 |
12 | RANDOM_STATE = 2022
13 |
14 | X, y = make_classification(
15 | n_samples=250,
16 | n_classes=2,
17 | n_features=2,
18 | n_redundant=0,
19 | random_state=RANDOM_STATE,
20 | )
21 |
22 | x_min = np.min(X[:, 0])
23 | x_max = np.max(X[:, 0])
24 | y_min = np.min(X[:, 1])
25 | y_max = np.max(X[:, 1])
26 |
27 | plot_x = np.linspace(x_min - 1, x_max + 1, 1001)
28 | plot_y = np.linspace(x_min - 1, x_max + 1, 1001)
29 | xx, yy = np.meshgrid(plot_x, plot_y)
30 |
31 | clf = LinearSVC().fit(X, y)
32 | Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
33 | Z = Z.reshape(xx.shape)
34 |
35 | cmap = plt.cm.coolwarm
36 |
37 | plt.figure(figsize=(10, 10))
38 | plt.subplot(2, 2, 1)
39 | plt.contourf(xx, yy, Z, cmap=cmap)
40 | plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap)
41 | plt.xlabel('X')
42 | plt.ylabel('Y')
43 | plt.xlim(x_min, x_max)
44 | plt.ylim(y_min, y_max)
45 | plt.title('SVC with linear kernel(Decision function view)')
46 |
47 | Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
48 | Z = Z.reshape(xx.shape)
49 | plt.subplot(2, 2, 2)
50 | plt.contourf(xx, yy, Z, cmap=cmap)
51 | plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap)
52 | plt.xlabel('X')
53 | plt.ylabel('Y')
54 | plt.xlim(x_min, x_max)
55 | plt.ylim(y_min, y_max)
56 | plt.title('SVC with linear kernel(0-1 view)')
57 |
58 | clf = KernelSVC().fit(X, y)
59 | Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
60 | Z = Z.reshape(xx.shape)
61 |
62 | plt.subplot(2, 2, 3)
63 | plt.contourf(xx, yy, Z, cmap=cmap)
64 | plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap)
65 | plt.xlabel('X')
66 | plt.ylabel('Y')
67 | plt.xlim(x_min, x_max)
68 | plt.ylim(y_min, y_max)
69 | plt.title('SVC with Gaussian kernel(Decision function view)')
70 |
71 | Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
72 | Z = Z.reshape(xx.shape)
73 | plt.subplot(2, 2, 4)
74 | plt.contourf(xx, yy, Z, cmap=cmap)
75 | plt.scatter(X[:, 0], X[:, 1], c=y, cmap=cmap)
76 | plt.xlabel('X')
77 | plt.ylabel('Y')
78 | plt.xlim(x_min, x_max)
79 | plt.ylim(y_min, y_max)
80 | plt.title('SVC with Gaussian kernel(0-1 view)')
81 |
82 | plt.savefig("../src/visual_classify.png")
83 |
--------------------------------------------------------------------------------
/tests/visual_outlier.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import matplotlib.pyplot as plt
3 | from matplotlib.font_manager import FontProperties
4 | from pysvm import OneClassSVM
5 |
6 | try:
7 | import seaborn as sns
8 | sns.set()
9 | except:
10 | pass
11 |
12 | xx, yy = np.meshgrid(np.linspace(-5, 5, 500), np.linspace(-5, 5, 500))
13 |
14 | X = 0.3 * np.random.randn(100, 2)
15 | X_train = np.r_[X + 2, X - 2]
16 |
17 | X = 0.3 * np.random.randn(20, 2)
18 | X_test = np.r_[X + 2, X - 2]
19 |
20 | X_outliers = np.random.uniform(low=-4, high=4, size=(20, 2))
21 |
22 | clf = OneClassSVM(nu=0.1, kernel="rbf", gamma=0.1)
23 | clf.fit(X_train)
24 |
25 | y_pred_train = clf.predict(X_train)
26 | y_pred_test = clf.predict(X_test)
27 | y_pred_outliers = clf.predict(X_outliers)
28 |
29 | n_error_train = y_pred_train[y_pred_train == -1].size
30 | n_error_test = y_pred_test[y_pred_test == -1].size
31 | n_error_outliers = y_pred_outliers[y_pred_outliers == 1].size
32 |
33 | Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
34 | Z = Z.reshape(xx.shape)
35 |
36 | plt.title("Novelty Detection")
37 | plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), 0, 7), cmap=plt.cm.PuBu)
38 | a = plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors='darkred')
39 | plt.contourf(xx, yy, Z, levels=[0, Z.max()], colors='palevioletred')
40 |
41 | s = 40
42 | b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c='white', s=s, edgecolors='k')
43 | b2 = plt.scatter(X_test[:, 0],
44 | X_test[:, 1],
45 | c='blueviolet',
46 | s=s,
47 | edgecolors='k')
48 | c = plt.scatter(X_outliers[:, 0],
49 | X_outliers[:, 1],
50 | c='gold',
51 | s=s,
52 | edgecolors='k')
53 |
54 | plt.axis('tight')
55 | plt.xlim((-5, 5))
56 | plt.ylim((-5, 5))
57 |
58 | plt.legend([a.collections[0], b1, b2, c], [
59 | "learned frontier", "training data", "test regular data",
60 | "test abnormal data"
61 | ],
62 | loc="upper left",
63 | prop=FontProperties(size=11))
64 | plt.xlabel(
65 | "error train: %d/200 ; errors novel regular: %d/40 ; errors novel abnormal: %d/40"
66 | % (n_error_train, n_error_test, n_error_outliers))
67 | plt.savefig("../src/oc_svm.png")
68 |
--------------------------------------------------------------------------------
/tests/visual_regression.py:
--------------------------------------------------------------------------------
1 | from sklearn.datasets import make_regression
2 | import matplotlib.pyplot as plt
3 | import numpy as np
4 | from pysvm import LinearSVR, KernelSVR, NuSVR
5 |
6 | try:
7 | import seaborn as sns
8 | sns.set()
9 | except:
10 | pass
11 |
12 | RANDOM_STATE = 2022
13 |
14 | X, y = make_regression(n_features=1,
15 | noise=3,
16 | n_samples=50,
17 | random_state=RANDOM_STATE)
18 | plt.scatter(X.reshape(-1), y - 100, label="linear_data")
19 | plt.scatter(X.reshape(-1), 0.01 * y**2, label="squared_data")
20 | plt.scatter(X.reshape(-1), 100 * np.sin(0.01 * y) + 100, label="sin_data")
21 |
22 | model = LinearSVR(C=10)
23 | model.fit(X, y - 100)
24 | test_x = np.linspace(X.min(0), X.max(0), 2)
25 | pred = model.predict(test_x)
26 | plt.plot(test_x, pred, label="LinearSVR", color='red')
27 |
28 | model = NuSVR(kernel='poly', degree=2, C=10)
29 | model.fit(X, 0.01 * y**2)
30 | test_x = np.linspace(X.min(0), X.max(0), 100)
31 | pred = model.predict(test_x)
32 | plt.plot(test_x,
33 | pred,
34 | label="NuSVR(kernel=poly, degree=2)",
35 | color='yellowgreen')
36 |
37 | model = KernelSVR(C=10, gamma=0.25)
38 | model.fit(X, 100 * np.sin(0.01 * y) + 100)
39 | test_x = np.linspace(X.min(0), X.max(0), 100)
40 | pred = model.predict(test_x)
41 | plt.plot(test_x,
42 | pred,
43 | label="KernelSVR(kernel=rbf, gamma=0.25)",
44 | color='orange')
45 |
46 | plt.legend()
47 | plt.title("Regression visualization")
48 | plt.savefig("../src/visual_regression.png")
--------------------------------------------------------------------------------