splineops 0.3.4__py3-none-any.whl
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.
- splineops/__init__.py +3 -0
- splineops/bases/__init__.py +0 -0
- splineops/bases/bspline0basis.py +60 -0
- splineops/bases/bspline1basis.py +30 -0
- splineops/bases/bspline2basis.py +39 -0
- splineops/bases/bspline3basis.py +38 -0
- splineops/bases/bspline4basis.py +54 -0
- splineops/bases/bspline5basis.py +63 -0
- splineops/bases/bspline6basis.py +98 -0
- splineops/bases/bspline7basis.py +96 -0
- splineops/bases/bspline8basis.py +141 -0
- splineops/bases/bspline9basis.py +167 -0
- splineops/bases/keysbasis.py +42 -0
- splineops/bases/linearbasis.py +3 -0
- splineops/bases/nearestneighborbasis.py +4 -0
- splineops/bases/omoms0basis.py +4 -0
- splineops/bases/omoms1basis.py +3 -0
- splineops/bases/omoms2basis.py +94 -0
- splineops/bases/omoms3basis.py +46 -0
- splineops/bases/omoms4basis.py +162 -0
- splineops/bases/omoms5basis.py +84 -0
- splineops/bases/splinebasis.py +93 -0
- splineops/bases/utils.py +77 -0
- splineops/interpolate/__init__.py +0 -0
- splineops/interpolate/tensorspline.py +422 -0
- splineops/interpolate/utils.py +308 -0
- splineops/modes/__init__.py +0 -0
- splineops/modes/extensionmode.py +22 -0
- splineops/modes/finitesupportcoefficients.py +89 -0
- splineops/modes/narrowmirroring.py +54 -0
- splineops/modes/utils.py +35 -0
- splineops/utils/__init__.py +0 -0
- splineops/utils/interop.py +13 -0
- splineops-0.3.4.dist-info/METADATA +241 -0
- splineops-0.3.4.dist-info/RECORD +37 -0
- splineops-0.3.4.dist-info/WHEEL +4 -0
- splineops-0.3.4.dist-info/licenses/LICENSE +30 -0
splineops/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
3
|
+
|
|
4
|
+
from splineops.bases.splinebasis import SplineBasis
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BSpline0Basis(SplineBasis):
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
|
|
10
|
+
# Support and degree (no poles)
|
|
11
|
+
support = 1
|
|
12
|
+
degree = support - 1
|
|
13
|
+
|
|
14
|
+
# Call super constructor
|
|
15
|
+
super(BSpline0Basis, self).__init__(support=support, degree=degree)
|
|
16
|
+
|
|
17
|
+
# Methods
|
|
18
|
+
@staticmethod
|
|
19
|
+
def eval(x: npt.NDArray) -> npt.NDArray:
|
|
20
|
+
|
|
21
|
+
# Case 1/2 < |x|
|
|
22
|
+
y = np.zeros_like(x)
|
|
23
|
+
|
|
24
|
+
# Case -1/2 <= x < 1/2
|
|
25
|
+
# Note: Asymmetry introduced. This is a standard strategy to compute
|
|
26
|
+
# the indexes while keeping the smallest support length by avoiding
|
|
27
|
+
# averaging two values in special cases at interval limits [-1/2, 1/2].
|
|
28
|
+
# The exact symmetric case with a longer support is provided below.
|
|
29
|
+
y = np.where(np.logical_and(x >= -1 / 2, x < 1 / 2), 1, y)
|
|
30
|
+
|
|
31
|
+
return y
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class BSpline0SymBasis(SplineBasis):
|
|
35
|
+
def __init__(self) -> None:
|
|
36
|
+
|
|
37
|
+
# Support and degree (no poles)
|
|
38
|
+
support = 2
|
|
39
|
+
degree = 0
|
|
40
|
+
|
|
41
|
+
# Call super constructor
|
|
42
|
+
super(BSpline0SymBasis, self).__init__(support=support, degree=degree)
|
|
43
|
+
|
|
44
|
+
# Methods
|
|
45
|
+
@staticmethod
|
|
46
|
+
def eval(x: npt.NDArray) -> npt.NDArray:
|
|
47
|
+
|
|
48
|
+
# Pre-computations
|
|
49
|
+
x_abs = np.abs(x)
|
|
50
|
+
|
|
51
|
+
# Case 1/2 < |x|
|
|
52
|
+
y = np.zeros_like(x)
|
|
53
|
+
|
|
54
|
+
# Case |x| < 1/2 (i.e. 0 < |x| < 1/2)
|
|
55
|
+
y = np.where(x_abs < 1 / 2, 1, y)
|
|
56
|
+
|
|
57
|
+
# Case |x| == 1/2
|
|
58
|
+
y = np.where(x_abs == 1 / 2, 1 / 2, y)
|
|
59
|
+
|
|
60
|
+
return y
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
3
|
+
|
|
4
|
+
from splineops.bases.splinebasis import SplineBasis
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BSpline1Basis(SplineBasis):
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
|
|
10
|
+
# Support and degree (no poles)
|
|
11
|
+
support = 2
|
|
12
|
+
degree = support - 1
|
|
13
|
+
|
|
14
|
+
# Call super constructor
|
|
15
|
+
super(BSpline1Basis, self).__init__(support=support, degree=degree)
|
|
16
|
+
|
|
17
|
+
# Methods
|
|
18
|
+
@staticmethod
|
|
19
|
+
def eval(x: npt.NDArray) -> npt.NDArray:
|
|
20
|
+
|
|
21
|
+
# Pre-computations
|
|
22
|
+
x_abs = np.abs(x)
|
|
23
|
+
|
|
24
|
+
# Case 1 <= |x|
|
|
25
|
+
y = np.zeros_like(x)
|
|
26
|
+
|
|
27
|
+
# Case |x| < 1 (i.e. 0 <= |x| < 1)
|
|
28
|
+
y = np.where(x_abs < 1, 1 - x_abs, y)
|
|
29
|
+
|
|
30
|
+
return y
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
3
|
+
|
|
4
|
+
from splineops.bases.splinebasis import SplineBasis
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BSpline2Basis(SplineBasis):
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
|
|
10
|
+
# Support, degree and poles
|
|
11
|
+
support = 3
|
|
12
|
+
degree = support - 1
|
|
13
|
+
poles = (2 * np.sqrt(2) - 3,)
|
|
14
|
+
|
|
15
|
+
# Call super constructor
|
|
16
|
+
super(BSpline2Basis, self).__init__(support=support, degree=degree, poles=poles)
|
|
17
|
+
|
|
18
|
+
# Methods
|
|
19
|
+
@staticmethod
|
|
20
|
+
def eval(x: npt.NDArray) -> npt.NDArray:
|
|
21
|
+
|
|
22
|
+
# Pre-computations
|
|
23
|
+
x_abs = np.abs(x)
|
|
24
|
+
|
|
25
|
+
# Case 3/2 <= |x|
|
|
26
|
+
y = np.zeros_like(x)
|
|
27
|
+
|
|
28
|
+
# Case |x| < 3/2 (i.e. 1/2 <= |x| < 3/2)
|
|
29
|
+
y = np.where(
|
|
30
|
+
np.logical_and(x_abs >= 1 / 2, x_abs < 3 / 2),
|
|
31
|
+
# 1 / 8 * (3 - 2 * x_abs) * (3 - 2 * x_abs),
|
|
32
|
+
9 / 8 - (3 * x_abs) / 2 + x_abs * x_abs / 2,
|
|
33
|
+
y,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Case |x| < 1/2 (i.e. 0 <= |x| < 1/2)
|
|
37
|
+
y = np.where(x_abs < 1 / 2, 3 / 4 - x_abs * x_abs, y)
|
|
38
|
+
|
|
39
|
+
return y
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
3
|
+
|
|
4
|
+
from splineops.bases.splinebasis import SplineBasis
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BSpline3Basis(SplineBasis):
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
|
|
10
|
+
# Support, degree and poles
|
|
11
|
+
support = 4
|
|
12
|
+
degree = support - 1
|
|
13
|
+
poles = (np.sqrt(3) - 2,)
|
|
14
|
+
|
|
15
|
+
# Call super constructor
|
|
16
|
+
super(BSpline3Basis, self).__init__(support=support, degree=degree, poles=poles)
|
|
17
|
+
|
|
18
|
+
# Methods
|
|
19
|
+
@staticmethod
|
|
20
|
+
def eval(x: npt.NDArray) -> npt.NDArray:
|
|
21
|
+
|
|
22
|
+
# Pre-computations
|
|
23
|
+
x_abs = np.abs(x)
|
|
24
|
+
|
|
25
|
+
# Case 2 <= |x|
|
|
26
|
+
y = np.zeros_like(x)
|
|
27
|
+
|
|
28
|
+
# Case |x| < 2 (i.e. 1 <= |x| < 2)
|
|
29
|
+
y = np.where(
|
|
30
|
+
np.logical_and(x_abs >= 1, x_abs < 2),
|
|
31
|
+
1 / 6 * (2 - x_abs) * (2 - x_abs) * (2 - x_abs),
|
|
32
|
+
y,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# Case |x| < 1 (i.e. 0 <= |x| < 1)
|
|
36
|
+
y = np.where(x_abs < 1, 2 / 3 - 1 / 2 * x_abs * x_abs * (2 - x_abs), y)
|
|
37
|
+
|
|
38
|
+
return y
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
3
|
+
|
|
4
|
+
from splineops.bases.splinebasis import SplineBasis
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BSpline4Basis(SplineBasis):
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
|
|
10
|
+
# Support, degree and poles
|
|
11
|
+
support = 5
|
|
12
|
+
degree = support - 1
|
|
13
|
+
poles = (
|
|
14
|
+
np.sqrt(664 - np.sqrt(438976)) + np.sqrt(304) - 19,
|
|
15
|
+
np.sqrt(664 + np.sqrt(438976)) - np.sqrt(304) - 19,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# Call super constructor
|
|
19
|
+
super(BSpline4Basis, self).__init__(support=support, degree=degree, poles=poles)
|
|
20
|
+
|
|
21
|
+
# Methods
|
|
22
|
+
@staticmethod
|
|
23
|
+
def eval(x: npt.NDArray) -> npt.NDArray:
|
|
24
|
+
|
|
25
|
+
# Pre-computations
|
|
26
|
+
x_abs = np.abs(x)
|
|
27
|
+
|
|
28
|
+
# Case 5/2 <= |x|
|
|
29
|
+
y = np.zeros_like(x)
|
|
30
|
+
|
|
31
|
+
# Case |x| < 5/2 (i.e. 3/2 <= |x| < 5/2)
|
|
32
|
+
y = np.where(
|
|
33
|
+
np.logical_and(x_abs >= 3 / 2, x_abs < 5 / 2),
|
|
34
|
+
1
|
|
35
|
+
/ 384
|
|
36
|
+
* (625 + x_abs * (-1000 + x_abs * (600 + x_abs * (-160 + 16 * x_abs)))),
|
|
37
|
+
y,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Case |x| < 3/2 (i.e. 1/2 <= |x| < 3/2)
|
|
41
|
+
y = np.where(
|
|
42
|
+
np.logical_and(x_abs >= 1 / 2, x_abs < 3 / 2),
|
|
43
|
+
1 / 96 * (55 + x_abs * (20 + x_abs * (-120 + x_abs * (80 - 16 * x_abs)))),
|
|
44
|
+
y,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Case |x| < 1/2 (i.e. 0 <= |x| < 1/2)
|
|
48
|
+
y = np.where(
|
|
49
|
+
x_abs < 1 / 2,
|
|
50
|
+
1 / 192 * (115 + x_abs * x_abs * (-120 + 48 * x_abs * x_abs)),
|
|
51
|
+
y,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
return y
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
3
|
+
|
|
4
|
+
from splineops.bases.splinebasis import SplineBasis
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BSpline5Basis(SplineBasis):
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
|
|
10
|
+
# Support, degree and poles
|
|
11
|
+
support = 6
|
|
12
|
+
degree = support - 1
|
|
13
|
+
poles = (
|
|
14
|
+
np.sqrt(135 / 2 - np.sqrt(17745 / 4)) + np.sqrt(105 / 4) - 13 / 2,
|
|
15
|
+
np.sqrt(135 / 2 + np.sqrt(17745 / 4)) - np.sqrt(105 / 4) - 13 / 2,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# Call super constructor
|
|
19
|
+
super(BSpline5Basis, self).__init__(support=support, degree=degree, poles=poles)
|
|
20
|
+
|
|
21
|
+
# Methods
|
|
22
|
+
@staticmethod
|
|
23
|
+
def eval(x: npt.NDArray) -> npt.NDArray:
|
|
24
|
+
|
|
25
|
+
# Pre-computations
|
|
26
|
+
x_abs = np.abs(x)
|
|
27
|
+
|
|
28
|
+
# Case 3 <= |x|
|
|
29
|
+
y = np.zeros_like(x)
|
|
30
|
+
|
|
31
|
+
# Case |x| < 3 (i.e. 2 <= |x| < 3)
|
|
32
|
+
y = np.where(
|
|
33
|
+
np.logical_and(x_abs >= 2, x_abs < 3),
|
|
34
|
+
1
|
|
35
|
+
/ 120
|
|
36
|
+
* (
|
|
37
|
+
243
|
|
38
|
+
+ x_abs * (-405 + x_abs * (270 + x_abs * (-90 + x_abs * (15 - x_abs))))
|
|
39
|
+
),
|
|
40
|
+
y,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Case |x| < 2 (i.e. 1 <= |x| < 2)
|
|
44
|
+
y = np.where(
|
|
45
|
+
np.logical_and(x_abs >= 1, x_abs < 2),
|
|
46
|
+
1
|
|
47
|
+
/ 120
|
|
48
|
+
* (
|
|
49
|
+
51
|
|
50
|
+
+ x_abs
|
|
51
|
+
* (75 + x_abs * (-210 + x_abs * (150 + x_abs * (-45 + x_abs * 5))))
|
|
52
|
+
),
|
|
53
|
+
y,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Case |x| < 1 (i.e. 0 <= |x| < 1)
|
|
57
|
+
y = np.where(
|
|
58
|
+
x_abs < 1,
|
|
59
|
+
1 / 60 * (33 + x_abs * x_abs * (-30 + x_abs * x_abs * (15 - 5 * x_abs))),
|
|
60
|
+
y,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
return y
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
3
|
+
|
|
4
|
+
from splineops.bases.splinebasis import SplineBasis
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BSpline6Basis(SplineBasis):
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
|
|
10
|
+
# Support, degree and poles
|
|
11
|
+
support = 7
|
|
12
|
+
degree = support - 1
|
|
13
|
+
poles = (
|
|
14
|
+
-0.48829458930304475513011803888378906211227916123938,
|
|
15
|
+
-0.081679271076237512597937765737059080653379610398148,
|
|
16
|
+
-0.0014141518083258177510872439765585925278641690553467,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Call super constructor
|
|
20
|
+
super(BSpline6Basis, self).__init__(support=support, degree=degree, poles=poles)
|
|
21
|
+
|
|
22
|
+
# Methods
|
|
23
|
+
@staticmethod
|
|
24
|
+
def eval(x: npt.NDArray) -> npt.NDArray:
|
|
25
|
+
|
|
26
|
+
# Pre-computations
|
|
27
|
+
x_abs = np.abs(x)
|
|
28
|
+
|
|
29
|
+
# Case 7/2 <= |x|
|
|
30
|
+
y = np.zeros_like(x)
|
|
31
|
+
|
|
32
|
+
# Case 5/2 <= |x| < 7/2
|
|
33
|
+
# (7 - 2 x)^6/46080
|
|
34
|
+
# x^6/720 - (7 x^5)/240 + (49 x^4)/192 - (343 x^3)/288 + (2401 x^2)/768 - (16807 x)/3840 + 117649/46080
|
|
35
|
+
y = np.where(
|
|
36
|
+
np.logical_and(x_abs >= 5 / 2, x_abs < 7 / 2),
|
|
37
|
+
1 / 46080 * (7 - 2 * x_abs) ** 6,
|
|
38
|
+
y,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Case 3/2 <= |x| < 5/2
|
|
42
|
+
# -(192 x^6 - 2688 x^5 + 15120 x^4 - 42560 x^3 + 59220 x^2 - 30408 x - 4137)/23040
|
|
43
|
+
# (4137 - 4 x (x (4 x (3 x (4 (x - 14) x + 315) - 2660) + 14805) - 7602))/23040
|
|
44
|
+
y = np.where(
|
|
45
|
+
np.logical_and(x_abs >= 3 / 2, x_abs < 5 / 2),
|
|
46
|
+
1
|
|
47
|
+
/ 23040
|
|
48
|
+
* (
|
|
49
|
+
4137
|
|
50
|
+
- 4
|
|
51
|
+
* x_abs
|
|
52
|
+
* (
|
|
53
|
+
x_abs
|
|
54
|
+
* (
|
|
55
|
+
4
|
|
56
|
+
* x_abs
|
|
57
|
+
* (3 * x_abs * (4 * (x_abs - 14) * x_abs + 315) - 2660)
|
|
58
|
+
+ 14805
|
|
59
|
+
)
|
|
60
|
+
- 7602
|
|
61
|
+
)
|
|
62
|
+
),
|
|
63
|
+
y,
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Case 1/2 <= |x| < 3/2
|
|
67
|
+
# (23583 - 420 x - 16380 x^2 - 5600 x^3 + 15120 x^4 - 6720 x^5 + 960 x^6)/46080
|
|
68
|
+
# (20 x (x (4 x (3 x (4 (x - 7) x + 63) - 70) - 819) - 21) + 23583)/46080
|
|
69
|
+
y = np.where(
|
|
70
|
+
np.logical_and(x_abs >= 1 / 2, x_abs < 3 / 2),
|
|
71
|
+
1
|
|
72
|
+
/ 46080
|
|
73
|
+
* (
|
|
74
|
+
20
|
|
75
|
+
* x_abs
|
|
76
|
+
* (
|
|
77
|
+
x_abs
|
|
78
|
+
* (
|
|
79
|
+
4 * x_abs * (3 * x_abs * (4 * (x_abs - 7) * x_abs + 63) - 70)
|
|
80
|
+
- 819
|
|
81
|
+
)
|
|
82
|
+
- 21
|
|
83
|
+
)
|
|
84
|
+
+ 23583
|
|
85
|
+
),
|
|
86
|
+
y,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Case |x| < 1/2 (i.e., -(1/2) < x < 1/2)
|
|
90
|
+
# -(320 x^6 - 1680 x^4 + 4620 x^2 - 5887)/11520
|
|
91
|
+
# (5887 - 20 x^2 (16 x^4 - 84 x^2 + 231))/11520
|
|
92
|
+
y = np.where(
|
|
93
|
+
x_abs < 1 / 2,
|
|
94
|
+
1 / 11520 * (5887 - 20 * x_abs**2 * (16 * x_abs**4 - 84 * x_abs**2 + 231)),
|
|
95
|
+
y,
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
return y
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
3
|
+
|
|
4
|
+
from splineops.bases.splinebasis import SplineBasis
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BSpline7Basis(SplineBasis):
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
|
|
10
|
+
# Support, degree and poles
|
|
11
|
+
support = 8
|
|
12
|
+
degree = support - 1
|
|
13
|
+
poles = (
|
|
14
|
+
-0.53528043079643816554240378168164607183392315234269,
|
|
15
|
+
-0.12255461519232669051527226435935734360548654942730,
|
|
16
|
+
-0.0091486948096082769285930216516478534156925639545994,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
# Call super constructor
|
|
20
|
+
super(BSpline7Basis, self).__init__(support=support, degree=degree, poles=poles)
|
|
21
|
+
|
|
22
|
+
# Methods
|
|
23
|
+
@staticmethod
|
|
24
|
+
def eval(x: npt.NDArray) -> npt.NDArray:
|
|
25
|
+
|
|
26
|
+
# Pre-computations
|
|
27
|
+
x_abs = np.abs(x)
|
|
28
|
+
|
|
29
|
+
# Case 4 <= |x|
|
|
30
|
+
y = np.zeros_like(x)
|
|
31
|
+
|
|
32
|
+
# Case 3 <= x < 4
|
|
33
|
+
# -(-4 + x)^7/5040
|
|
34
|
+
y = np.where(
|
|
35
|
+
np.logical_and(x_abs >= 3, x_abs < 4), -1 / 5040 * (-4 + x_abs) ** 7, y
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Case 2 <= x < 3
|
|
39
|
+
# x^7/720 - x^6/36 + (7 x^5)/30 - (19 x^4)/18 + (49 x^3)/18 - (23 x^2)/6 + (217 x)/90 - 139/630
|
|
40
|
+
# (7 x (x (x (x (x ((x - 20) x + 168) - 760) + 1960) - 2760) + 1736) - 1112)/5040
|
|
41
|
+
y = np.where(
|
|
42
|
+
np.logical_and(x_abs >= 2, x_abs < 3),
|
|
43
|
+
1
|
|
44
|
+
/ 5040
|
|
45
|
+
* (
|
|
46
|
+
7
|
|
47
|
+
* x_abs
|
|
48
|
+
* (
|
|
49
|
+
x_abs
|
|
50
|
+
* (
|
|
51
|
+
x_abs
|
|
52
|
+
* (x_abs * (x_abs * ((x_abs - 20) * x_abs + 168) - 760) + 1960)
|
|
53
|
+
- 2760
|
|
54
|
+
)
|
|
55
|
+
+ 1736
|
|
56
|
+
)
|
|
57
|
+
- 1112
|
|
58
|
+
),
|
|
59
|
+
y,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
# Case 1 <= x < 2
|
|
63
|
+
# -(21 x^7 - 252 x^6 + 1176 x^5 - 2520 x^4 + 1960 x^3 + 504 x^2 + 392 x - 2472)/5040
|
|
64
|
+
# (2472 - 7 x (x (x (3 (x - 6) x ((x - 6) x + 20) + 280) + 72) + 56))/5040
|
|
65
|
+
y = np.where(
|
|
66
|
+
np.logical_and(x_abs >= 1, x_abs < 2),
|
|
67
|
+
1
|
|
68
|
+
/ 5040
|
|
69
|
+
* (
|
|
70
|
+
2472
|
|
71
|
+
- 7
|
|
72
|
+
* x_abs
|
|
73
|
+
* (
|
|
74
|
+
x_abs
|
|
75
|
+
* (
|
|
76
|
+
x_abs
|
|
77
|
+
* (3 * (x_abs - 6) * x_abs * ((x_abs - 6) * x_abs + 20) + 280)
|
|
78
|
+
+ 72
|
|
79
|
+
)
|
|
80
|
+
+ 56
|
|
81
|
+
)
|
|
82
|
+
),
|
|
83
|
+
y,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Case |x| < 1 (i.e., -1 < x < 1)
|
|
87
|
+
# (35 x^7 - 140 x^6 + 560 x^4 - 1680 x^2 + 2416)/5040
|
|
88
|
+
# 1/144 (x^5 - 4 x^4 + 16 x^2 - 48) x^2 + 151/315
|
|
89
|
+
y = np.where(
|
|
90
|
+
x_abs < 1,
|
|
91
|
+
1 / 144 * (x_abs**5 - 4 * x_abs**4 + 16 * x_abs**2 - 48) * x_abs**2
|
|
92
|
+
+ 151 / 315,
|
|
93
|
+
y,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return y
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.typing as npt
|
|
3
|
+
|
|
4
|
+
from splineops.bases.splinebasis import SplineBasis
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BSpline8Basis(SplineBasis):
|
|
8
|
+
def __init__(self) -> None:
|
|
9
|
+
|
|
10
|
+
# Support, degree and poles
|
|
11
|
+
support = 9
|
|
12
|
+
degree = support - 1
|
|
13
|
+
poles = (
|
|
14
|
+
-0.57468690924876543053013930412874542429066157804125,
|
|
15
|
+
-0.16303526929728093524055189686073705223476814550830,
|
|
16
|
+
-0.023632294694844850023403919296361320612665920854629,
|
|
17
|
+
-0.00015382131064169091173935253018402160762964054070043,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# Call super constructor
|
|
21
|
+
super(BSpline8Basis, self).__init__(support=support, degree=degree, poles=poles)
|
|
22
|
+
|
|
23
|
+
# Methods
|
|
24
|
+
@staticmethod
|
|
25
|
+
def eval(x: npt.NDArray) -> npt.NDArray:
|
|
26
|
+
|
|
27
|
+
# Pre-computations
|
|
28
|
+
x_abs = np.abs(x)
|
|
29
|
+
|
|
30
|
+
# Case 9/2 <= |x|
|
|
31
|
+
y = np.zeros_like(x)
|
|
32
|
+
|
|
33
|
+
# Case 7/2 <= |x| < 9/2
|
|
34
|
+
# (9 - 2 x)^8/10321920
|
|
35
|
+
# x^8/40320 - x^7/1120 + (9 x^6)/640 - (81 x^5)/640 + (729 x^4)/1024 - (6561 x^3)/2560 + (59049 x^2)/10240 - (531441 x)/71680 + 4782969/1146880
|
|
36
|
+
y = np.where(
|
|
37
|
+
np.logical_and(x_abs >= 7 / 2, x_abs < 9 / 2),
|
|
38
|
+
1 / 10321920 * (9 - 2 * x_abs) ** 8,
|
|
39
|
+
y,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Case 5/2 <= |x| < 7/2
|
|
43
|
+
# -(256 x^8 - 6912 x^7 + 80640 x^6 - 528192 x^5 + 2106720 x^4 - 5163984 x^3 + 7383600 x^2 - 5257836 x + 1104561)/1290240
|
|
44
|
+
# -((4 x (2 x (2 (x - 15) x + 171) - 879) + 3441) (8 x (x (2 (x - 12) x + 99) - 150) + 321))/1290240
|
|
45
|
+
y = np.where(
|
|
46
|
+
np.logical_and(x_abs >= 5 / 2, x_abs < 7 / 2),
|
|
47
|
+
-1
|
|
48
|
+
/ 1290240
|
|
49
|
+
* (
|
|
50
|
+
(
|
|
51
|
+
4 * x_abs * (2 * x_abs * (2 * (x_abs - 15) * x_abs + 171) - 879)
|
|
52
|
+
+ 3441
|
|
53
|
+
)
|
|
54
|
+
* (8 * x_abs * (x_abs * (2 * (x_abs - 12) * x_abs + 99) - 150) + 321)
|
|
55
|
+
),
|
|
56
|
+
y,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Case 3/2 <= |x| < 5/2
|
|
60
|
+
# x^8/1440 - x^7/80 + (3 x^6)/32 - (119 x^5)/320 + (207 x^4)/256 - (1127 x^3)/1280 + (195 x^2)/512 - (1457 x)/5120 + 145167/286720
|
|
61
|
+
# (56 x (2 x (2 x (x (4 x (2 x ((x - 18) x + 135) - 1071) + 9315) - 10143) + 8775) - 13113) + 1306503)/2580480
|
|
62
|
+
y = np.where(
|
|
63
|
+
np.logical_and(x_abs >= 3 / 2, x_abs < 5 / 2),
|
|
64
|
+
1
|
|
65
|
+
/ 2580480
|
|
66
|
+
* (
|
|
67
|
+
56
|
|
68
|
+
* x_abs
|
|
69
|
+
* (
|
|
70
|
+
2
|
|
71
|
+
* x_abs
|
|
72
|
+
* (
|
|
73
|
+
2
|
|
74
|
+
* x_abs
|
|
75
|
+
* (
|
|
76
|
+
x_abs
|
|
77
|
+
* (
|
|
78
|
+
4
|
|
79
|
+
* x_abs
|
|
80
|
+
* (2 * x_abs * ((x_abs - 18) * x_abs + 135) - 1071)
|
|
81
|
+
+ 9315
|
|
82
|
+
)
|
|
83
|
+
- 10143
|
|
84
|
+
)
|
|
85
|
+
+ 8775
|
|
86
|
+
)
|
|
87
|
+
- 13113
|
|
88
|
+
)
|
|
89
|
+
+ 1306503
|
|
90
|
+
),
|
|
91
|
+
y,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Case 1/2 <= |x| < 3/2
|
|
95
|
+
# -(1792 x^8 - 16128 x^7 + 48384 x^6 - 28224 x^5 - 90720 x^4 - 7056 x^3 + 365904 x^2 - 252 x - 584361)/1290240
|
|
96
|
+
# (584361 - 28 x (4 x (x (2 x (2 x (4 x ((x - 9) x + 27) - 63) - 405) - 63) + 3267) - 9))/1290240
|
|
97
|
+
y = np.where(
|
|
98
|
+
np.logical_and(x_abs >= 1 / 2, x_abs < 3 / 2),
|
|
99
|
+
1
|
|
100
|
+
/ 1290240
|
|
101
|
+
* (
|
|
102
|
+
584361
|
|
103
|
+
- 28
|
|
104
|
+
* x_abs
|
|
105
|
+
* (
|
|
106
|
+
4
|
|
107
|
+
* x_abs
|
|
108
|
+
* (
|
|
109
|
+
x_abs
|
|
110
|
+
* (
|
|
111
|
+
2
|
|
112
|
+
* x_abs
|
|
113
|
+
* (
|
|
114
|
+
2
|
|
115
|
+
* x_abs
|
|
116
|
+
* (4 * x_abs * ((x_abs - 9) * x_abs + 27) - 63)
|
|
117
|
+
- 405
|
|
118
|
+
)
|
|
119
|
+
- 63
|
|
120
|
+
)
|
|
121
|
+
+ 3267
|
|
122
|
+
)
|
|
123
|
+
- 9
|
|
124
|
+
)
|
|
125
|
+
),
|
|
126
|
+
y,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Case |x| < 1/2 (i.e., -(1/2) < x < 1/2)
|
|
130
|
+
# (8960 x^8 - 80640 x^6 + 433440 x^4 - 1456560 x^2 + 2337507)/5160960
|
|
131
|
+
# ((16 x^6 - 144 x^4 + 774 x^2 - 2601) x^2)/9216 + 259723/573440
|
|
132
|
+
y = np.where(
|
|
133
|
+
x_abs < 1 / 2,
|
|
134
|
+
1
|
|
135
|
+
/ 9216
|
|
136
|
+
* ((16 * x_abs**6 - 144 * x_abs**4 + 774 * x_abs**2 - 2601) * x_abs**2)
|
|
137
|
+
+ 259723 / 573440,
|
|
138
|
+
y,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
return y
|