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.
Files changed (38) hide show
  1. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/.github/workflows/documentation.yml +12 -4
  2. pyanovaapprox-2.0.4/.github/workflows/format.yml +42 -0
  3. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/.gitignore +4 -1
  4. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/PKG-INFO +1 -1
  5. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/docs/source/conf.py +16 -2
  6. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/docs/source/index.rst +2 -3
  7. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/pyproject.toml +1 -1
  8. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/exampleWavelet.py +12 -6
  9. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/analysis.py +16 -29
  10. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/approx.py +52 -39
  11. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/bandwidth.py +14 -6
  12. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/errors.py +11 -23
  13. pyanovaapprox-2.0.3/.github/workflows/format.yml +0 -27
  14. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/.github/workflows/ci.yml +0 -0
  15. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/.github/workflows/release.yml +0 -0
  16. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/LICENSE +0 -0
  17. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/README.md +0 -0
  18. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/docs/Makefile +0 -0
  19. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/docs/source/Analysis.rst +0 -0
  20. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/docs/source/Approximation.rst +0 -0
  21. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/docs/source/Errors.rst +0 -0
  22. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/TestFunctionPeriodic.py +0 -0
  23. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/exampleAutoapproximate.py +0 -0
  24. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/exampleCheb.py +0 -0
  25. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/exampleClassification.py +0 -0
  26. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/exampleNonPeriodic.py +0 -0
  27. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/simpleTest/examplePeriodic.py +0 -0
  28. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/__init__.py +0 -0
  29. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/fista.py +0 -0
  30. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/src/pyANOVAapprox/trafos.py +0 -0
  31. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/TestFunctionCheb.py +0 -0
  32. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/TestFunctionPeriodic.py +0 -0
  33. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/cheb_fista.py +0 -0
  34. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/cheb_lsqr.py +0 -0
  35. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/per_fista.py +0 -0
  36. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/per_lsqr.py +0 -0
  37. {pyanovaapprox-2.0.3 → pyanovaapprox-2.0.4}/tests/run_tests.py +0 -0
  38. {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@v3
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.py
21
+ bandwidth_detection*
22
+ cross_validation*
23
+ /src/pyANOVAapprox/.ipynb_checkpoints/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyANOVAapprox
3
- Version: 2.0.3
3
+ Version: 2.0.4
4
4
  Summary: Approximation Package for High-Dimensional Functions
5
5
  Project-URL: Homepage, https://github.com/NFFT/pyGroupedTransforms
6
6
  Author-email: Felix Wirth <fwi012001@gmail.com>
@@ -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
- extensions = ["sphinx.ext.mathjax"]
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
- html_theme = "alabaster"
39
+ # Auf das im Workflow genutzte Theme umgestellt
40
+ html_theme = "sphinx_rtd_theme"
27
41
  html_static_path = ["_static"]
@@ -16,6 +16,5 @@ documentation for details.
16
16
  :caption: Contents:
17
17
 
18
18
  Analysis
19
- Approximation
20
- Errors
21
-
19
+ modules
20
+ Errors
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pyANOVAapprox"
7
- version = "2.0.3"
7
+ version = "2.0.4"
8
8
  authors = [
9
9
  { name="Felix Wirth", email="fwi012001@gmail.com" },
10
10
  ]
@@ -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("Total number of used parameters = " + str(len(anova_model.fc[lambdas[0]].vec())))
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=true)
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("Total number of used parameters = " + str(len(anova_model.fc[lambdas[0]].vec())))
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
- return self.aktsetting if settingnr is None else settingnr
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
- return D, t
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
- if len(lam) == 1:
497
- return self._autoapproximate(
498
- lam.pop(),
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
- else:
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 setting.lam}
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 setting.lam:
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 setting.lam:
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
- range(1, len(y) + 1),
162
- y,
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(self.getTrafo(settingnr).settings, self.X.shape[1])
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