pyANOVAapprox 2.0.3__tar.gz → 2.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/.github/workflows/documentation.yml +12 -4
- pyanovaapprox-2.0.4/.github/workflows/format.yml +42 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/.gitignore +4 -1
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/PKG-INFO +1 -1
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/docs/source/conf.py +16 -2
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/docs/source/index.rst +2 -3
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/pyproject.toml +1 -1
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/exampleWavelet.py +12 -6
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/analysis.py +16 -29
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/approx.py +52 -39
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/bandwidth.py +14 -6
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/errors.py +11 -23
- pyanovaapprox-2.0.3/.github/workflows/format.yml +0 -27
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/.github/workflows/ci.yml +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/.github/workflows/release.yml +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/LICENSE +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/README.md +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/docs/Makefile +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/docs/source/Analysis.rst +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/docs/source/Approximation.rst +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/docs/source/Errors.rst +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/TestFunctionPeriodic.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/exampleAutoapproximate.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/exampleCheb.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/exampleClassification.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/exampleNonPeriodic.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/examplePeriodic.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/__init__.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/fista.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/trafos.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/TestFunctionCheb.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/TestFunctionPeriodic.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/cheb_fista.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/cheb_lsqr.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/per_fista.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/per_lsqr.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/run_tests.py +0 -0
- {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/wav_lsqr.py +0 -0
|
@@ -10,20 +10,28 @@ jobs:
|
|
|
10
10
|
runs-on: ubuntu-latest
|
|
11
11
|
steps:
|
|
12
12
|
- uses: actions/checkout@v4
|
|
13
|
+
|
|
13
14
|
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
|
|
14
18
|
- name: Install dependencies
|
|
15
19
|
run: |
|
|
16
20
|
pip install sphinx sphinx_rtd_theme myst_parser
|
|
21
|
+
# WICHTIG: Wenn dein Code Abhängigkeiten hat (z.B. numpy, scipy),
|
|
22
|
+
# installiere sie hier, sonst kann 'autodoc' den Code nicht importieren!
|
|
23
|
+
# pip install -e .
|
|
24
|
+
|
|
17
25
|
- name: Sphinx build
|
|
18
26
|
run: |
|
|
19
27
|
cd docs
|
|
20
28
|
sphinx-apidoc -o ./source ../src -f
|
|
21
29
|
make html
|
|
30
|
+
|
|
22
31
|
- name: Deploy to GitHub Pages
|
|
23
|
-
uses: peaceiris/actions-gh-pages@
|
|
32
|
+
uses: peaceiris/actions-gh-pages@v4
|
|
24
33
|
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
|
25
34
|
with:
|
|
26
|
-
publish_branch: gh-pages
|
|
27
35
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
28
|
-
publish_dir: docs/build/html
|
|
29
|
-
force_orphan: true
|
|
36
|
+
publish_dir: docs/build/html
|
|
37
|
+
force_orphan: true
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Format Python Code
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- '**' # Läuft bei jedem Push auf absolut jeden Branch...
|
|
7
|
+
tags-ignore:
|
|
8
|
+
- '**' # ...ABER ignoriert jeden Push, der ein Tag (Release) ist.
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
python-code-format:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
permissions:
|
|
14
|
+
contents: write
|
|
15
|
+
pull-requests: write
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
architecture: "x64"
|
|
23
|
+
|
|
24
|
+
- name: Display Python version
|
|
25
|
+
run: python --version
|
|
26
|
+
|
|
27
|
+
- name: Install packages
|
|
28
|
+
run: pip install black isort
|
|
29
|
+
|
|
30
|
+
- name: Formatter
|
|
31
|
+
run: |
|
|
32
|
+
black .
|
|
33
|
+
isort .
|
|
34
|
+
- name: Create Pull Request
|
|
35
|
+
uses: peter-evans/create-pull-request@v6
|
|
36
|
+
with:
|
|
37
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
38
|
+
commit-message: "style: auto code format"
|
|
39
|
+
title: "Fixes by format action"
|
|
40
|
+
body: "This is an auto-generated PR with code formatting fixes."
|
|
41
|
+
labels: automated pr
|
|
42
|
+
branch: python-code-format-patches
|
|
@@ -7,6 +7,7 @@ dist/
|
|
|
7
7
|
__pycache__/
|
|
8
8
|
venv/
|
|
9
9
|
venv2/
|
|
10
|
+
.venv/
|
|
10
11
|
|
|
11
12
|
bin/
|
|
12
13
|
/lib64/
|
|
@@ -17,4 +18,6 @@ src/pyNFFT3/lib/AVX2/libgomp-1.dll
|
|
|
17
18
|
src/pyNFFT3/lib/AVX2/libgcc_s_seh-1.dll
|
|
18
19
|
src/pyNFFT3/lib/AVX2/libwinpthread-1.dll
|
|
19
20
|
simpleTest/venv/
|
|
20
|
-
bandwidth_detection
|
|
21
|
+
bandwidth_detection*
|
|
22
|
+
cross_validation*
|
|
23
|
+
/src/pyANOVAapprox/.ipynb_checkpoints/
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
# For the full list of built-in configuration values, see the documentation:
|
|
4
4
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
5
5
|
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
# -- Path setup --------------------------------------------------------------
|
|
10
|
+
# Macht den src-Ordner für Sphinx und autodoc auffindbar
|
|
11
|
+
sys.path.insert(0, os.path.abspath("../../src"))
|
|
12
|
+
|
|
6
13
|
# -- Project information -----------------------------------------------------
|
|
7
14
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
|
8
15
|
|
|
@@ -14,7 +21,13 @@ release = "29.07.2025"
|
|
|
14
21
|
# -- General configuration ---------------------------------------------------
|
|
15
22
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
# Erweiterungen hinzugefügt, damit automodule, Mathe und Markdown funktionieren
|
|
25
|
+
extensions = [
|
|
26
|
+
"sphinx.ext.autodoc",
|
|
27
|
+
"sphinx.ext.napoleon", # Unterstützt Google/NumPy-Style Docstrings
|
|
28
|
+
"sphinx.ext.mathjax",
|
|
29
|
+
"myst_parser",
|
|
30
|
+
]
|
|
18
31
|
|
|
19
32
|
templates_path = ["_templates"]
|
|
20
33
|
exclude_patterns = []
|
|
@@ -23,5 +36,6 @@ exclude_patterns = []
|
|
|
23
36
|
# -- Options for HTML output -------------------------------------------------
|
|
24
37
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
|
25
38
|
|
|
26
|
-
|
|
39
|
+
# Auf das im Workflow genutzte Theme umgestellt
|
|
40
|
+
html_theme = "sphinx_rtd_theme"
|
|
27
41
|
html_static_path = ["_static"]
|
|
@@ -74,20 +74,23 @@ anova_model = ANOVAapprox.approx(X, y, ds=q, basis=basis, N=N)
|
|
|
74
74
|
|
|
75
75
|
#### Do approximation by least-squares ###
|
|
76
76
|
anova_model.approximate(lam=lambdas, solver="lsqr")
|
|
77
|
-
print(
|
|
77
|
+
print(
|
|
78
|
+
"Total number of used parameters = "
|
|
79
|
+
+ str(len(anova_model.getFc()[lambdas[0]].vec()))
|
|
80
|
+
)
|
|
78
81
|
|
|
79
82
|
#######################
|
|
80
83
|
## Analyze the model ##
|
|
81
84
|
#######################
|
|
82
85
|
|
|
83
86
|
### Do sensitivity analysis ####
|
|
84
|
-
anova_model.get_GSI(
|
|
87
|
+
gsis = anova_model.get_GSI(
|
|
85
88
|
lam=0.0
|
|
86
|
-
) # calculates indices for importance of terms (gsis is vector, with indices belonging to terms in anova_model.U)
|
|
87
|
-
anova_model.get_GSI(lam=0.0, Dict=
|
|
89
|
+
) # calculates indices for importance of terms (gsis is vector, with indices belonging to terms in anova_model.getSetting().U)
|
|
90
|
+
anova_model.get_GSI(lam=0.0, Dict=True)
|
|
88
91
|
|
|
89
92
|
y_min_calc = 10 ** (np.min(np.log10(gsis)) - 0.5)
|
|
90
|
-
label = list(anova_model.U[1:])
|
|
93
|
+
label = list(anova_model.getSetting().U[1:])
|
|
91
94
|
l = len(label)
|
|
92
95
|
plt.figure()
|
|
93
96
|
x_values = np.arange(1, l + 1)
|
|
@@ -128,7 +131,10 @@ anova_model = anova_model.approx(
|
|
|
128
131
|
X=X, y=y, U=U, N=[i + 2 for i in N], basis=basis
|
|
129
132
|
) # increase number of paramers in N for the important terms
|
|
130
133
|
anova_model.approximate(lam=lambdas)
|
|
131
|
-
print(
|
|
134
|
+
print(
|
|
135
|
+
"Total number of used parameters = "
|
|
136
|
+
+ str(len(anova_model.getFc()[lambdas[0]].vec()))
|
|
137
|
+
)
|
|
132
138
|
mse_train = anova_model.get_mse(lam=0.0)
|
|
133
139
|
mse_test = anova_model.get_mse(X=X_test, y=y_test, lam=0.0)
|
|
134
140
|
print("MSE on test points after ANOVA truncation: " + str(mse_test))
|
|
@@ -3,22 +3,22 @@ import numpy as np
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
def _variances(self, settingnr, lam, Dict): # helpfunction for get_variances
|
|
6
|
-
setting = self.getSetting(settingnr)
|
|
6
|
+
setting = self.getSetting(settingnr, lam)
|
|
7
7
|
if setting.basis.startswith("chui"):
|
|
8
|
-
variances = self.getFc(settingnr)[lam].norms(
|
|
8
|
+
variances = self.getFc(settingnr, lam)[lam].norms(
|
|
9
9
|
Dict=False, m=int(setting.basis[-1])
|
|
10
10
|
)
|
|
11
11
|
else:
|
|
12
|
-
variances = self.getFc(settingnr)[lam].norms()
|
|
12
|
+
variances = self.getFc(settingnr, lam)[lam].norms()
|
|
13
13
|
|
|
14
14
|
variances = variances[1:]
|
|
15
15
|
if Dict:
|
|
16
16
|
if a.basis.startswith("chui"):
|
|
17
|
-
variances = self.getFc(settingnr)[lam].norms(
|
|
17
|
+
variances = self.getFc(settingnr, lam)[lam].norms(
|
|
18
18
|
Dict=True, m=int(setting.basis[-1])
|
|
19
19
|
)
|
|
20
20
|
else:
|
|
21
|
-
variances = self.getFc(settingnr)[lam].norms(Dict=True)
|
|
21
|
+
variances = self.getFc(settingnr, lam)[lam].norms(Dict=True)
|
|
22
22
|
|
|
23
23
|
return {u: variances[u] for u in list(variances)}
|
|
24
24
|
else:
|
|
@@ -37,31 +37,28 @@ def get_variances(self, settingnr=None, lam=None, Dict=False):
|
|
|
37
37
|
elif (
|
|
38
38
|
lam == None
|
|
39
39
|
): # get_variances( a::approx; dict::Bool = false )::Dict{Float64,Union{Vector{Float64},Dict{Vector{Int},Float64}}}
|
|
40
|
-
return {
|
|
41
|
-
l: self._variances(settingnr, l, Dict)
|
|
42
|
-
for l in self.getSetting(settingnr).lam
|
|
43
|
-
}
|
|
40
|
+
return {l: self._variances(settingnr, l, Dict) for l in self.lam.keys()}
|
|
44
41
|
|
|
45
42
|
|
|
46
43
|
def _GSI(self, settingnr, lam, Dict): # helpfunction for get_GSI
|
|
47
|
-
setting = self.getSetting(settingnr)
|
|
44
|
+
setting = self.getSetting(settingnr, lam)
|
|
48
45
|
if setting.basis.startswith("chui"):
|
|
49
46
|
variances = np.square(
|
|
50
|
-
self.getFc(settingnr)[lam].norms(Dict=False, m=int(setting.basis[-1]))
|
|
47
|
+
self.getFc(settingnr, lam)[lam].norms(Dict=False, m=int(setting.basis[-1]))
|
|
51
48
|
)
|
|
52
49
|
else:
|
|
53
|
-
variances = np.square(self.getFc(settingnr)[lam].norms())
|
|
50
|
+
variances = np.square(self.getFc(settingnr, lam)[lam].norms())
|
|
54
51
|
|
|
55
52
|
variances = variances[1:]
|
|
56
53
|
variance_f = sum(variances)
|
|
57
54
|
|
|
58
55
|
if Dict:
|
|
59
56
|
if setting.basis.startswith("chui"):
|
|
60
|
-
variances = self.getFc(settingnr)[lam].norms(
|
|
57
|
+
variances = self.getFc(settingnr, lam)[lam].norms(
|
|
61
58
|
Dict=True, m=int(setting.basis[-1])
|
|
62
59
|
)
|
|
63
60
|
else:
|
|
64
|
-
variances = self.getFc(settingnr)[lam].norms(Dict=True)
|
|
61
|
+
variances = self.getFc(settingnr, lam)[lam].norms(Dict=True)
|
|
65
62
|
return {u: (variances[u] ** 2) / variance_f for u in list(variances)}
|
|
66
63
|
|
|
67
64
|
else:
|
|
@@ -78,9 +75,7 @@ def get_GSI(self, settingnr=None, lam=None, Dict=False):
|
|
|
78
75
|
): # get_GSI(a::approx, λ::Float64; dict::Bool = false,)::Union{Vector{Float64},Dict{Vector{Int},Float64}}
|
|
79
76
|
return self._GSI(settingnr, lam, Dict)
|
|
80
77
|
else: # get_GSI( a::approx; dict::Bool = false )::Dict{Float64,Union{Vector{Float64},Dict{Vector{Int},Float64}}}
|
|
81
|
-
return {
|
|
82
|
-
l: self._GSI(settingnr, l, Dict) for l in self.getSetting(settingnr).lam
|
|
83
|
-
}
|
|
78
|
+
return {l: self._GSI(settingnr, l, Dict) for l in self.lam.keys()}
|
|
84
79
|
|
|
85
80
|
|
|
86
81
|
def _AttributeRanking(self, settingnr, lam): # helpfunction for get_AttributeRanking
|
|
@@ -120,17 +115,14 @@ def get_AttributeRanking(self, settingnr=None, lam=None):
|
|
|
120
115
|
if (
|
|
121
116
|
lam is None
|
|
122
117
|
): # get_AttributeRanking( a::approx, λ::Float64 )::Dict{Float64,Vector{Float64}}
|
|
123
|
-
return {
|
|
124
|
-
l: self._AttributeRanking(settingnr, l)
|
|
125
|
-
for l in self.getSetting(settingnr).lam
|
|
126
|
-
}
|
|
118
|
+
return {l: self._AttributeRanking(settingnr, l) for l in self.lam.keys()}
|
|
127
119
|
else: # get_AttributeRanking( a::approx, λ::Float64 )::Vector{Float64}
|
|
128
120
|
return self._AttributeRanking(settingnr, lam)
|
|
129
121
|
|
|
130
122
|
|
|
131
123
|
def _ActiveSet(self, eps, settingnr, lam): # helpfunction for get_ActiveSet
|
|
132
124
|
|
|
133
|
-
U = self.getSetting(settingnr).U[1:]
|
|
125
|
+
U = self.getSetting(settingnr, lam).U[1:]
|
|
134
126
|
lengths = [len(u) for u in U]
|
|
135
127
|
ds = max(lengths)
|
|
136
128
|
|
|
@@ -162,10 +154,7 @@ def get_ActiveSet(self, eps, settingnr=None, lam=None):
|
|
|
162
154
|
if (
|
|
163
155
|
lam is None
|
|
164
156
|
): # get_ActiveSet(a::approx, eps::Vector{Float64})::Dict{Float64,Vector{Vector{Int}}}
|
|
165
|
-
return {
|
|
166
|
-
l: self._ActiveSet(eps, settingnr, l)
|
|
167
|
-
for l in self.getSetting(settingnr).lam
|
|
168
|
-
}
|
|
157
|
+
return {l: self._ActiveSet(eps, settingnr, l) for l in self.lam.keys()}
|
|
169
158
|
else: # get_ActiveSet(a::approx, eps::Vector{Float64}, λ::Float64)::Vector{Vector{Int}}
|
|
170
159
|
return self._ActiveSet(eps, settingnr, lam)
|
|
171
160
|
|
|
@@ -190,9 +179,7 @@ def get_ShapleyValues(self, settingnr=None, lam=None):
|
|
|
190
179
|
This function returns the Shapley values of the approximation for all reg. parameters ``\lambda``, if lam == None, as a dictionary of vectors of length `a.d`. Otherwise for the provided lam as a vector of length `a.d`.
|
|
191
180
|
"""
|
|
192
181
|
if lam is None: # get_ShapleyValues(a::approx)::Dict{Float64,Vector{Float64}}
|
|
193
|
-
return {
|
|
194
|
-
l: self._ShapleyValues(settingnr, l) for l in self.getSetting(settingnr).lam
|
|
195
|
-
}
|
|
182
|
+
return {l: self._ShapleyValues(settingnr, l) for l in self.lam.keys()}
|
|
196
183
|
else: # get_ShapleyValues(a::approx, λ::Float64)::Vector{Float64}
|
|
197
184
|
return self._ShapleyValues(settingnr, lam)
|
|
198
185
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import copy
|
|
2
|
+
import warnings
|
|
2
3
|
|
|
3
4
|
import pyANOVAapprox.analysis as ANOVAanalysis
|
|
4
5
|
import pyANOVAapprox.bandwidth as ANOVAbandwidth
|
|
@@ -186,6 +187,11 @@ class approx:
|
|
|
186
187
|
lam={0.0},
|
|
187
188
|
):
|
|
188
189
|
|
|
190
|
+
if type(lam) is np.ndarray:
|
|
191
|
+
lam = {float(i) for i in lam}
|
|
192
|
+
if type(lam) is list:
|
|
193
|
+
lam = set(lam)
|
|
194
|
+
|
|
189
195
|
self.X = X
|
|
190
196
|
|
|
191
197
|
if X.shape[0] != y.shape[0]:
|
|
@@ -222,6 +228,9 @@ class approx:
|
|
|
222
228
|
self.trafo = [None]
|
|
223
229
|
self.fc = [{}]
|
|
224
230
|
self.aktsetting = 0
|
|
231
|
+
self.lam = {}
|
|
232
|
+
for i in lam:
|
|
233
|
+
self.lam[i] = [0]
|
|
225
234
|
|
|
226
235
|
if setting.N is not None:
|
|
227
236
|
self.addTrafo()
|
|
@@ -233,17 +242,24 @@ class approx:
|
|
|
233
242
|
self.trafo.append(None)
|
|
234
243
|
self.fc.append({})
|
|
235
244
|
|
|
236
|
-
def getSettingNr(self, settingnr=None):
|
|
237
|
-
|
|
245
|
+
def getSettingNr(self, settingnr=None, lam=None, warn=True):
|
|
246
|
+
if lam is None:
|
|
247
|
+
return self.aktsetting if settingnr is None else settingnr
|
|
248
|
+
else:
|
|
249
|
+
if lam in self.lam.keys():
|
|
250
|
+
return self.lam[lam][-1] if settingnr is None else settingnr
|
|
251
|
+
else:
|
|
252
|
+
warnings.warn("Not yet approximated for this lambda")
|
|
253
|
+
return self.aktsetting if settingnr is None else settingnr
|
|
238
254
|
|
|
239
|
-
def getSetting(self, settingnr=None):
|
|
240
|
-
return self.setting[self.getSettingNr(settingnr)]
|
|
255
|
+
def getSetting(self, settingnr=None, lam=None):
|
|
256
|
+
return self.setting[self.getSettingNr(settingnr, lam)]
|
|
241
257
|
|
|
242
|
-
def getTrafo(self, settingnr=None):
|
|
243
|
-
return self.trafo[self.getSettingNr(settingnr)]
|
|
258
|
+
def getTrafo(self, settingnr=None, lam=None):
|
|
259
|
+
return self.trafo[self.getSettingNr(settingnr, lam)]
|
|
244
260
|
|
|
245
|
-
def getFc(self, settingnr=None):
|
|
246
|
-
return self.fc[self.getSettingNr(settingnr)]
|
|
261
|
+
def getFc(self, settingnr=None, lam=None):
|
|
262
|
+
return self.fc[self.getSettingNr(settingnr, lam)]
|
|
247
263
|
|
|
248
264
|
def addTrafo(self, settingnr=None):
|
|
249
265
|
setting = self.getSetting(settingnr)
|
|
@@ -356,6 +372,7 @@ class approx:
|
|
|
356
372
|
If lam is a np.ndarray of dtype float, this function computes the approximation for the regularization parameters contained in lam.
|
|
357
373
|
If lam is a float, this function computes the approximation for the regularization parameter lam.
|
|
358
374
|
"""
|
|
375
|
+
|
|
359
376
|
setting = self.getSetting(settingnr)
|
|
360
377
|
|
|
361
378
|
if lam is None:
|
|
@@ -393,6 +410,7 @@ class approx:
|
|
|
393
410
|
solver_verbose,
|
|
394
411
|
solver_tol,
|
|
395
412
|
):
|
|
413
|
+
settingnrs = []
|
|
396
414
|
setting = self.getSetting(settingnr)
|
|
397
415
|
|
|
398
416
|
n = len(self.y)
|
|
@@ -407,7 +425,8 @@ class approx:
|
|
|
407
425
|
os.mkdir("log")
|
|
408
426
|
with open("log/log.csv", "w", newline="") as csvfile:
|
|
409
427
|
csv.writer(csvfile, delimiter=",").writerow(["it"] + setting.U)
|
|
410
|
-
|
|
428
|
+
if verbosity > 2:
|
|
429
|
+
print("B =", B)
|
|
411
430
|
for idx in range(maxiter):
|
|
412
431
|
if verbosity > 0:
|
|
413
432
|
print("===== Iteration ", str(idx + 1), " =====")
|
|
@@ -415,6 +434,7 @@ class approx:
|
|
|
415
434
|
if setting.N is not None:
|
|
416
435
|
self.addSetting(setting)
|
|
417
436
|
settingnr = self.aktsetting
|
|
437
|
+
settingnrs = settingnrs + [settingnr]
|
|
418
438
|
setting = self.getSetting(settingnr)
|
|
419
439
|
|
|
420
440
|
setting.N = [bw[i] for i in setting.U]
|
|
@@ -469,7 +489,12 @@ class approx:
|
|
|
469
489
|
wr.writerow(
|
|
470
490
|
["t in it" + str(idx + 1)] + [str(t[i]) for i in setting.U]
|
|
471
491
|
)
|
|
472
|
-
|
|
492
|
+
|
|
493
|
+
if all([math.isnan(j) for j in sum([D[i] for i in D], [])]) and all(
|
|
494
|
+
[math.isnan(j) for j in sum([t[i] for i in D], [])]
|
|
495
|
+
):
|
|
496
|
+
break
|
|
497
|
+
return settingnrs
|
|
473
498
|
|
|
474
499
|
def autoapproximate(
|
|
475
500
|
self,
|
|
@@ -484,18 +509,21 @@ class approx:
|
|
|
484
509
|
solver_verbose=False,
|
|
485
510
|
solver_tol=1e-8,
|
|
486
511
|
):
|
|
512
|
+
settingnr = self.getSettingNr(settingnr)
|
|
487
513
|
setting = self.getSetting(settingnr)
|
|
488
514
|
|
|
489
515
|
if lam is None:
|
|
490
516
|
lam = setting.lam
|
|
491
517
|
else:
|
|
518
|
+
if isinstance(lam, np.ndarray):
|
|
519
|
+
lam = {float(l) for l in lam}
|
|
492
520
|
if not isinstance(lam, set):
|
|
493
521
|
lam = {lam}
|
|
494
522
|
setting.lam = lam
|
|
495
523
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
524
|
+
for l in lam:
|
|
525
|
+
settingnrs = self._autoapproximate(
|
|
526
|
+
l,
|
|
499
527
|
settingnr=settingnr,
|
|
500
528
|
B=B,
|
|
501
529
|
maxiter=maxiter,
|
|
@@ -506,22 +534,7 @@ class approx:
|
|
|
506
534
|
solver_verbose=solver_verbose,
|
|
507
535
|
solver_tol=solver_tol,
|
|
508
536
|
)
|
|
509
|
-
|
|
510
|
-
return {
|
|
511
|
-
l: self._autoapproximate(
|
|
512
|
-
l,
|
|
513
|
-
settingnr=settingnr,
|
|
514
|
-
B=B,
|
|
515
|
-
maxiter=maxiter,
|
|
516
|
-
solver=solver,
|
|
517
|
-
verbosity=verbosity,
|
|
518
|
-
solver_max_iter=solver_max_iter,
|
|
519
|
-
solver_weights=solver_weights,
|
|
520
|
-
solver_verbose=solver_verbose,
|
|
521
|
-
solver_tol=solver_tol,
|
|
522
|
-
)
|
|
523
|
-
for l in lam
|
|
524
|
-
}
|
|
537
|
+
self.lam[l] = self.lam[l] + settingnrs
|
|
525
538
|
|
|
526
539
|
def evaluate(self, settingnr=None, lam=None, X=None):
|
|
527
540
|
"""
|
|
@@ -532,7 +545,7 @@ class approx:
|
|
|
532
545
|
- If only lam is given: evaluate at self.X for specific lam.
|
|
533
546
|
- If neither are given: evaluate at self.X for all lam.
|
|
534
547
|
"""
|
|
535
|
-
setting = self.getSetting(settingnr)
|
|
548
|
+
setting = self.getSetting(settingnr, lam)
|
|
536
549
|
|
|
537
550
|
if X is not None:
|
|
538
551
|
if setting.basis == "per" and (np.min(X) < -0.5 or np.max(X) >= 0.5):
|
|
@@ -550,14 +563,14 @@ class approx:
|
|
|
550
563
|
basis_vect=setting.basis_vect,
|
|
551
564
|
)
|
|
552
565
|
else:
|
|
553
|
-
trafo = self.getTrafo(settingnr)
|
|
566
|
+
trafo = self.getTrafo(settingnr, lam)
|
|
554
567
|
|
|
555
568
|
if (
|
|
556
569
|
lam is not None
|
|
557
570
|
): # evaluate( a::approx; X::Matrix{Float64}, λ::Float64 )::Union{Vector{ComplexF64},Vector{Float64}}
|
|
558
|
-
return trafo @ self.getFc(settingnr)[lam]
|
|
571
|
+
return trafo @ self.getFc(settingnr, lam)[lam]
|
|
559
572
|
else: # evaluate( a::approx; X::Matrix{Float64} )::Dict{Float64,Union{Vector{ComplexF64},Vector{Float64}}}
|
|
560
|
-
return {λ: trafo @ self.getFc(settingnr)[λ] for λ in
|
|
573
|
+
return {λ: trafo @ self.getFc(settingnr, lam)[λ] for λ in self.lam.keys()}
|
|
561
574
|
|
|
562
575
|
def evaluateANOVAterms(self, settingnr=None, X=None, lam=None):
|
|
563
576
|
"""
|
|
@@ -566,7 +579,7 @@ class approx:
|
|
|
566
579
|
- If lam is given: evaluate at X for specific lam.
|
|
567
580
|
- If lam is not given: evaluate at X for all lam.
|
|
568
581
|
"""
|
|
569
|
-
setting = self.getSetting(settingnr)
|
|
582
|
+
setting = self.getSetting(settingnr, lam)
|
|
570
583
|
if X is None:
|
|
571
584
|
X = self.X
|
|
572
585
|
|
|
@@ -598,14 +611,14 @@ class approx:
|
|
|
598
611
|
lam is not None
|
|
599
612
|
): # evaluateANOVAterms( a::approx; X::Matrix{Float64}, λ::Float64 )::Union{Matrix{ComplexF64},Matrix{Float64}}
|
|
600
613
|
for j, u in enumerate(setting.U):
|
|
601
|
-
values[:, j] = trafo[u] @ self.getFc(settingnr)[lam][u]
|
|
614
|
+
values[:, j] = trafo[u] @ self.getFc(settingnr, lam)[lam][u]
|
|
602
615
|
return values
|
|
603
616
|
else: # evaluateANOVAterms( a::approx; X::Matrix{Float64} )::Dict{Float64,Union{Matrix{ComplexF64},Matrix{Float64}}}
|
|
604
617
|
results = {}
|
|
605
|
-
for λ in
|
|
618
|
+
for λ in self.lam.keys():
|
|
606
619
|
vals = np.zeros_like(values)
|
|
607
620
|
for j, u in enumerate(setting.U):
|
|
608
|
-
vals[:, j] = trafo[u] @ self.getFc(settingnr)[λ][u]
|
|
621
|
+
vals[:, j] = trafo[u] @ self.getFc(settingnr, lam)[λ][u]
|
|
609
622
|
results[λ] = vals
|
|
610
623
|
return results
|
|
611
624
|
|
|
@@ -616,7 +629,7 @@ class approx:
|
|
|
616
629
|
- If lam is given: evaluate at X for specific lam.
|
|
617
630
|
- If lam is not given: evaluate at X for all lam.
|
|
618
631
|
"""
|
|
619
|
-
setting = self.getSetting(settingnr)
|
|
632
|
+
setting = self.getSetting(settingnr, lam)
|
|
620
633
|
|
|
621
634
|
if X is None:
|
|
622
635
|
X = self.X
|
|
@@ -646,7 +659,7 @@ class approx:
|
|
|
646
659
|
|
|
647
660
|
else: # evaluateSHAPterms( a::approx; X::Matrix{Float64} )::Dict{Float64,Union{Matrix{ComplexF64},Matrix{Float64}}}
|
|
648
661
|
results = {}
|
|
649
|
-
for l in
|
|
662
|
+
for l in self.lam.keys():
|
|
650
663
|
terms = self.evaluateANOVAterms(X, l)
|
|
651
664
|
|
|
652
665
|
Dtype = np.complex128 if setting.basis == "per" else np.float64
|
|
@@ -30,6 +30,9 @@ def getaxissum(ghat, u, j, system):
|
|
|
30
30
|
else:
|
|
31
31
|
raise ValueError("For this basis is estimate rates not implemented")
|
|
32
32
|
# fcuj = np.concatenate(fcuj[math.ceil(bws[j]/2):] + [fcuj[0]]) + fcuj[math.ceil(bws[j]/2)-1::-1]
|
|
33
|
+
|
|
34
|
+
fcuj = np.cumsum(fcuj[::-1])[::-1]
|
|
35
|
+
|
|
33
36
|
return fcuj
|
|
34
37
|
|
|
35
38
|
|
|
@@ -43,7 +46,8 @@ def compute_bandwidth(B, D, t):
|
|
|
43
46
|
raise ValueError(f"Budget too small: {B} < {minfreqs}")
|
|
44
47
|
|
|
45
48
|
def fun_lmbda_u(lmbda, u):
|
|
46
|
-
p1 = math.prod((bw[u][j] - 1) for j in range(len(u)) if math.isnan(t[u][j]))
|
|
49
|
+
p1 = math.prod((bw[u][j] - 1) for j in range(len(u)) if not math.isnan(t[u][j]))
|
|
50
|
+
|
|
47
51
|
p2 = math.prod(
|
|
48
52
|
((2 * t[u][j] * D[u][j]) / lmbda) ** (0.5 / t[u][j])
|
|
49
53
|
for j in range(len(u))
|
|
@@ -69,7 +73,7 @@ def compute_bandwidth(B, D, t):
|
|
|
69
73
|
bwuj = ((2 * t[u][j] * D[u][j]) / (lmbda * sizeIu)) ** (
|
|
70
74
|
0.5 / t[u][j]
|
|
71
75
|
) + 1
|
|
72
|
-
bw[u][j] = 2 * round(0.5 * bwuj)
|
|
76
|
+
bw[u][j] = max(6, 2 * round(0.5 * bwuj))
|
|
73
77
|
|
|
74
78
|
return bw
|
|
75
79
|
|
|
@@ -158,13 +162,12 @@ def estimate_rates(self, lam, settingnr=None, verbosity=0):
|
|
|
158
162
|
|
|
159
163
|
y = np.cumsum(axissum[::-1])[::-1]
|
|
160
164
|
ax.plot(
|
|
161
|
-
|
|
162
|
-
|
|
165
|
+
axissumnum,
|
|
166
|
+
axissum,
|
|
163
167
|
label=u[j],
|
|
164
168
|
marker="o",
|
|
165
169
|
# color=j
|
|
166
170
|
)
|
|
167
|
-
|
|
168
171
|
if (idx is None) or idx >= len(axissum):
|
|
169
172
|
D[u][j] = math.nan
|
|
170
173
|
t[u][j] = math.nan
|
|
@@ -186,11 +189,16 @@ def estimate_rates(self, lam, settingnr=None, verbosity=0):
|
|
|
186
189
|
# plt.figure(figsize=(12, 9))
|
|
187
190
|
# for ax in ps:
|
|
188
191
|
# plt.sca(ax)
|
|
192
|
+
time = ""
|
|
193
|
+
if verbosity > 8:
|
|
194
|
+
from datetime import datetime
|
|
195
|
+
|
|
196
|
+
time = str(round(datetime.timestamp(datetime.now())))
|
|
189
197
|
fig.savefig(
|
|
190
198
|
os.path.join(
|
|
191
199
|
"log",
|
|
192
200
|
"figures",
|
|
193
|
-
str(num).strip() + "_rates_" + str(u).strip() + ".png",
|
|
201
|
+
time + "_" + str(num).strip() + "_rates_" + str(u).strip() + ".png",
|
|
194
202
|
)
|
|
195
203
|
)
|
|
196
204
|
num = num + 1
|
|
@@ -37,10 +37,7 @@ def get_l2_error(self, settingnr=None, X=None, y=None, lam=None):
|
|
|
37
37
|
if lam is not None:
|
|
38
38
|
return self._l2_error(settingnr, lam, X, y)
|
|
39
39
|
else:
|
|
40
|
-
return {
|
|
41
|
-
l: self._l2_error(settingnr, l, X, y)
|
|
42
|
-
for l in self.getSetting(settingnr).lam
|
|
43
|
-
}
|
|
40
|
+
return {l: self._l2_error(settingnr, l, X, y) for l in self.lam.keys()}
|
|
44
41
|
|
|
45
42
|
|
|
46
43
|
def _mse(self, settingnr, lam, X, y): # helpfunction for get_mse
|
|
@@ -77,9 +74,7 @@ def get_mse(self, settingnr=None, X=None, y=None, lam=None):
|
|
|
77
74
|
if lam is not None:
|
|
78
75
|
return self._mse(settingnr, lam, X, y)
|
|
79
76
|
else:
|
|
80
|
-
return {
|
|
81
|
-
l: self._mse(settingnr, l, X, y) for l in self.getSetting(settingnr).lam
|
|
82
|
-
}
|
|
77
|
+
return {l: self._mse(settingnr, l, X, y) for l in self.lam.keys()}
|
|
83
78
|
|
|
84
79
|
|
|
85
80
|
def _mad(self, settingnr, lam, X, y): # helpfunction for get_mad
|
|
@@ -116,21 +111,21 @@ def get_mad(self, settingnr=None, X=None, y=None, lam=None):
|
|
|
116
111
|
if lam is not None:
|
|
117
112
|
return self._mad(settingnr, lam, X, y)
|
|
118
113
|
else:
|
|
119
|
-
return {
|
|
120
|
-
l: self._mad(settingnr, l, X, y) for l in self.getSetting(settingnr).lam
|
|
121
|
-
}
|
|
114
|
+
return {l: self._mad(settingnr, l, X, y) for l in self.lam.keys()}
|
|
122
115
|
|
|
123
116
|
|
|
124
117
|
def _L2_error(self, norm, bc_fun, settingnr, lam):
|
|
125
118
|
# print(settingnr)
|
|
126
|
-
if self.getSetting(settingnr).basis in {"per", "cos", "cheb", "std", "mixed"}:
|
|
119
|
+
if self.getSetting(settingnr, lam).basis in {"per", "cos", "cheb", "std", "mixed"}:
|
|
127
120
|
error = norm**2
|
|
128
|
-
index_set = gt.get_IndexSet(
|
|
121
|
+
index_set = gt.get_IndexSet(
|
|
122
|
+
self.getTrafo(settingnr, lam).settings, self.X.shape[1]
|
|
123
|
+
)
|
|
129
124
|
|
|
130
125
|
for i in range(index_set.shape[1]):
|
|
131
126
|
k = index_set[:, i]
|
|
132
127
|
error += (
|
|
133
|
-
abs(bc_fun(k) - self.getFc(settingnr)[lam][i]) ** 2
|
|
128
|
+
abs(bc_fun(k) - self.getFc(settingnr, lam)[lam][i]) ** 2
|
|
134
129
|
- abs(bc_fun(k)) ** 2
|
|
135
130
|
)
|
|
136
131
|
|
|
@@ -153,10 +148,7 @@ def get_L2_error(self, norm, bc_fun, settingnr=None, lam=None):
|
|
|
153
148
|
if lam is not None:
|
|
154
149
|
return self._L2_error(norm, bc_fun, settingnr, lam)
|
|
155
150
|
else:
|
|
156
|
-
return {
|
|
157
|
-
l: self._L2_error(norm, bc_fun, settingnr, l)
|
|
158
|
-
for l in self.getSetting(settingnr).lam
|
|
159
|
-
}
|
|
151
|
+
return {l: self._L2_error(norm, bc_fun, settingnr, l) for l in self.lam.keys()}
|
|
160
152
|
|
|
161
153
|
|
|
162
154
|
def _acc(self, settingnr, lam, X, y): # helpfunction for get_acc
|
|
@@ -176,9 +168,7 @@ def get_acc(self, settingnr=None, X=None, y=None, lam=None):
|
|
|
176
168
|
if lam is not None:
|
|
177
169
|
return self._acc(settingnr, lam, X, y)
|
|
178
170
|
else:
|
|
179
|
-
return {
|
|
180
|
-
l: self._acc(settingnr, l, X, y) for l in self.getSetting(settingnr).lam
|
|
181
|
-
}
|
|
171
|
+
return {l: self._acc(settingnr, l, X, y) for l in self.lam.keys()}
|
|
182
172
|
|
|
183
173
|
|
|
184
174
|
def auc_score(y_true, y_pred_proba):
|
|
@@ -240,9 +230,7 @@ def get_auc(self, settingnr=None, X=None, y=None, lam=None):
|
|
|
240
230
|
if lam is not None:
|
|
241
231
|
return self._auc(settingnr, lam, X, y)
|
|
242
232
|
else:
|
|
243
|
-
return {
|
|
244
|
-
l: self._auc(settingnr, l, X, y) for l in self.getSetting(settingnr).lam
|
|
245
|
-
}
|
|
233
|
+
return {l: self._auc(settingnr, l, X, y) for l in self.lam.keys()}
|
|
246
234
|
|
|
247
235
|
|
|
248
236
|
__all__ = [
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
name: Format Python Code
|
|
2
|
-
on: push
|
|
3
|
-
jobs:
|
|
4
|
-
python-code-format:
|
|
5
|
-
runs-on: ubuntu-latest
|
|
6
|
-
steps:
|
|
7
|
-
- uses: actions/checkout@v2
|
|
8
|
-
- uses: actions/setup-python@v4
|
|
9
|
-
with:
|
|
10
|
-
python-version: "3.12"
|
|
11
|
-
architecture: "x64"
|
|
12
|
-
- name: Display Python version
|
|
13
|
-
run: python --version
|
|
14
|
-
- name: Install packages
|
|
15
|
-
run: pip install black isort
|
|
16
|
-
- name: Formatter
|
|
17
|
-
run: |
|
|
18
|
-
black .
|
|
19
|
-
isort .
|
|
20
|
-
- name: Create Pull Request
|
|
21
|
-
uses: peter-evans/create-pull-request@v3
|
|
22
|
-
with:
|
|
23
|
-
commit-message: Auto code format
|
|
24
|
-
title: Fixes by format action
|
|
25
|
-
body: This is an auto-generated PR with fixes.
|
|
26
|
-
labels: automated pr
|
|
27
|
-
branch: python-code-format-patches
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|