Skip to content

Commit fee66fc

Browse files
jmh5309il
andauthored
Add monic polynomial (#453)
* Add monic polynomial * Adjust monic to be normal function instead of return ref-counted struct * Remove commented Monic struct * Fixups for monic polynomial * Add poly function * Remove poly/monic slice overloads and reconfigure unit tests * Remove monic * Unify poly into a single function * Unify poly with Polynomial * Adjust poly signature to scope const F * Update polynomial.d * Update polynomial.d --------- Co-authored-by: Ilia Ki <ki9ilia@gmail.com>
1 parent d6a3c5e commit fee66fc

File tree

1 file changed

+154
-24
lines changed

1 file changed

+154
-24
lines changed

source/mir/polynomial.d

Lines changed: 154 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -41,27 +41,7 @@ struct Polynomial(F)
4141
+/
4242
@optmath typeof(F.init * X.init * 1f + F.init) opCall(X)(in X x) const
4343
{
44-
import mir.internal.utility: Iota;
45-
auto ret = cast(typeof(return))0;
46-
if (coefficients)
47-
{
48-
ptrdiff_t i = coefficients.length - 1;
49-
assert(i >= 0);
50-
auto c = cast()coefficients[i];
51-
static foreach (d; Iota!derivative)
52-
c *= i - d;
53-
ret = cast(typeof(return)) c;
54-
while (--i >= cast(ptrdiff_t)derivative)
55-
{
56-
assert(i < coefficients.length);
57-
c = cast()coefficients[i];
58-
static foreach (d; Iota!derivative)
59-
c *= i - d;
60-
ret *= x;
61-
ret += c;
62-
}
63-
}
64-
return ret;
44+
return x.poly!derivative(this.coefficients[]);
6545
}
6646
}
6747
}
@@ -81,9 +61,9 @@ version (mir_test) @safe pure nothrow @nogc unittest
8161
auto a = rcarray!(const double)(3.0, 4.5, 1.9, 2);
8262
auto p = a.polynomial;
8363

84-
alias f = (x) => 3.0 + 4.5 * x^^1 + 1.9 * x^^2 + 2 * x^^3;
85-
alias df = (x) => 4.5 + 2 * 1.9 * x^^1 + 3 * 2 * x^^2;
86-
alias d2f = (x) => 2 * 1.9 + 6 * 2 * x^^1;
64+
alias f = (x) => 3.0 + 4.5 * x^^1 + 1.9 * x^^2 + 2 * x^^3;
65+
alias df = (x) => 4.5 + 2 * 1.9 * x^^1 + 3 * 2 * x^^2;
66+
alias d2f = (x) => 2 * 1.9 + 6 * 2 * x^^1;
8767

8868
assert(p(3.3).approxEqual(f(3.3)));
8969
assert(p(7.2).approxEqual(f(7.2)));
@@ -94,3 +74,153 @@ version (mir_test) @safe pure nothrow @nogc unittest
9474
assert(p.opCall!2(3.3).approxEqual(d2f(3.3)));
9575
assert(p.opCall!2(7.2).approxEqual(d2f(7.2)));
9676
}
77+
78+
/++
79+
Evaluate polynomial.
80+
81+
Coefficients assumed to be in the order a0 + a1 * x ^^ 1 + ... + aN * x ^^ N
82+
83+
Params:
84+
F = controls type of output
85+
derivative = order of derivatives (default = 0)
86+
87+
Returns:
88+
Value of the polynomial, evaluated at `x`
89+
90+
See_also:
91+
$(WEB en.wikipedia.org/wiki/Polynomial, Polynomial).
92+
+/
93+
template poly(uint derivative = 0)
94+
{
95+
import std.traits: ForeachType;
96+
/++
97+
Params:
98+
x = value to evaluate
99+
coefficients = coefficients of polynomial
100+
+/
101+
@optmath typeof(F.init * X.init * 1f + F.init) poly(X, F)(in X x, scope const F[] coefficients...)
102+
{
103+
import mir.internal.utility: Iota;
104+
auto ret = cast(typeof(return))0;
105+
if (coefficients.length > 0)
106+
{
107+
ptrdiff_t i = coefficients.length - 1;
108+
assert(i >= 0);
109+
auto c = cast()coefficients[i];
110+
static foreach (d; Iota!derivative)
111+
c *= i - d;
112+
ret = cast(typeof(return)) c;
113+
while (--i >= cast(ptrdiff_t)derivative)
114+
{
115+
assert(i < coefficients.length);
116+
c = cast()coefficients[i];
117+
static foreach (d; Iota!derivative)
118+
c *= i - d;
119+
ret *= x;
120+
ret += c;
121+
}
122+
}
123+
return ret;
124+
}
125+
}
126+
127+
///
128+
version (mir_test) @safe pure nothrow unittest
129+
{
130+
import mir.math.common: approxEqual;
131+
132+
double[] x = [3.0, 4.5, 1.9, 2];
133+
134+
alias f = (x) => 3.0 + 4.5 * x^^1 + 1.9 * x^^2 + 2 * x^^3;
135+
alias df = (x) => 4.5 + 2 * 1.9 * x^^1 + 3 * 2 * x^^2;
136+
alias d2f = (x) => 2 * 1.9 + 6 * 2 * x^^1;
137+
138+
assert(poly(3.3, x).approxEqual(f(3.3)));
139+
assert(poly(7.2, x).approxEqual(f(7.2)));
140+
141+
assert(poly!1(3.3, x).approxEqual(df(3.3)));
142+
assert(poly!1(7.2, x).approxEqual(df(7.2)));
143+
144+
assert(poly!2(3.3, x).approxEqual(d2f(3.3)));
145+
assert(poly!2(7.2, x).approxEqual(d2f(7.2)));
146+
}
147+
148+
// static array test
149+
version (mir_test) @safe pure @nogc nothrow unittest
150+
{
151+
import mir.math.common: approxEqual;
152+
153+
double[4] x = [3.0, 4.5, 1.9, 2];
154+
155+
alias f = (x) => 3.0 + 4.5 * x^^1 + 1.9 * x^^2 + 2 * x^^3;
156+
alias df = (x) => 4.5 + 2 * 1.9 * x^^1 + 3 * 2 * x^^2;
157+
alias d2f = (x) => 2 * 1.9 + 6 * 2 * x^^1;
158+
159+
assert(poly(3.3, x).approxEqual(f(3.3)));
160+
assert(poly(7.2, x).approxEqual(f(7.2)));
161+
162+
assert(poly!1(3.3, x).approxEqual(df(3.3)));
163+
assert(poly!1(7.2, x).approxEqual(df(7.2)));
164+
165+
assert(poly!2(3.3, x).approxEqual(d2f(3.3)));
166+
assert(poly!2(7.2, x).approxEqual(d2f(7.2)));
167+
}
168+
169+
// Check coefficient.length = 3
170+
version (mir_test) @safe pure nothrow unittest
171+
{
172+
import mir.math.common: approxEqual;
173+
174+
double[] x = [3.0, 4.5, 1.9];
175+
176+
alias f = (x) => 3.0 + 4.5 * x^^1 + 1.9 * x^^2;
177+
alias df = (x) => 4.5 + 2 * 1.9 * x^^1;
178+
alias d2f = (x) => 2 * 1.9;
179+
180+
assert(poly(3.3, x).approxEqual(f(3.3)));
181+
assert(poly(7.2, x).approxEqual(f(7.2)));
182+
183+
assert(poly!1(3.3, x).approxEqual(df(3.3)));
184+
assert(poly!1(7.2, x).approxEqual(df(7.2)));
185+
186+
assert(poly!2(3.3, x).approxEqual(d2f(3.3)));
187+
assert(poly!2(7.2, x).approxEqual(d2f(7.2)));
188+
}
189+
190+
// Check coefficient.length = 2
191+
version (mir_test) @safe pure nothrow unittest
192+
{
193+
import mir.math.common: approxEqual;
194+
195+
double[] x = [3.0, 4.5];
196+
197+
alias f = (x) => 3.0 + 4.5 * x^^1;
198+
alias df = (x) => 4.5;
199+
alias d2f = (x) => 0.0;
200+
201+
assert(poly(3.3, x).approxEqual(f(3.3)));
202+
assert(poly(7.2, x).approxEqual(f(7.2)));
203+
204+
assert(poly!1(3.3, x).approxEqual(df(3.3)));
205+
assert(poly!1(7.2, x).approxEqual(df(7.2)));
206+
207+
assert(poly!2(3.3, x).approxEqual(d2f(3.3)));
208+
assert(poly!2(7.2, x).approxEqual(d2f(7.2)));
209+
}
210+
211+
// Check coefficient.length = 1
212+
version (mir_test) @safe pure nothrow unittest
213+
{
214+
import mir.math.common: approxEqual;
215+
216+
double[] x = [3.0];
217+
218+
alias f = (x) => 3.0;
219+
alias df = (x) => 0.0;
220+
221+
assert(poly(3.3, x).approxEqual(f(3.3)));
222+
assert(poly(7.2, x).approxEqual(f(7.2)));
223+
224+
assert(poly!1(3.3, x).approxEqual(df(3.3)));
225+
assert(poly!1(7.2, x).approxEqual(df(7.2)));
226+
}

0 commit comments

Comments
 (0)