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 ADDED
@@ -0,0 +1,3 @@
1
+ import importlib.metadata
2
+
3
+ __version__ = importlib.metadata.version("splineops")
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