Power series (with rational coefficients) by lazy evaluated demand channels. No goroutines leak!
Power series - with rational coefficients. As M. Douglas McIlroy says in his Squinting at Power Series:
Data streams are an ideal vehicle for handling power series. Stream implementations can be read off directly from simple recursive equations that define operations such as multiplication, substitution, exponentiation, and reversion of series. The bookkeeping that bedevils these algorithms when they are expressed in traditional languages is completely hidden when they are expressed in stream terms. Communicating processes are the key to the simplicity of the algorithms.
powser builds on advanced concurrent functionality:
lazy evaluated demand channels
represent the potentially infinite stream of coefficients,
which can be *big.Rat from "math/big" or simple int64 rationals (included).
Powser has simple conventions and provides:
- Upper-case for power series.
- Lower-case for coefficients.
- Input variables: From U,V,...
- Output variables: Into ...,Y,Z
Note: Use of coefficients from any other ring (such as square matrices) is easy to accomplish. It just takes minimal dedicated changes - given the arithmetic methods have suitable signature.
Note: powser is inspired by a test from the standard Go distribution (test/chan/powser1.go).
This implementation makes a clear separation between the power series themselves, and the coefficients and their demand channels, which live in separate packages.
And all the spawned goroutines do not leak! They all terminate. And close their channel. Both
- upon input being closed by the producer (lacking more data: a finite power series aka polynom) - and
- upon output being dropped by the consumer (as there is no need for further coefficients).
Great care was taken to get this right (which is not trivial).
And: The expression of the mathematical algorithms (e.g. in arithmetic) is more tight in this implementation thanks to the helpers and the channel handling package (even so some more lines need to cater for resource cleanup: Drop/Close).
Note: We use and chain methods here instead of nesting functions (as in the original paper). Thus: Sometimes a formula appears to be written backwards. Read carefully,
The overall result is too good, powerful and complete
as to serve as an example only in the related project pipe/s
and thus is given here as an independent and stand-alone repository in the hope to be useful for someone.
Last, but not least, power series are just one usecase for concurrency and demand channels.
Others, such as continued fractions await to be explored and conquered.
(Using generic tools from pipe/s might ease such undertaking.)
provides methods to combine power series:
-
basic helpers
CMulmultipliesUby a constantcand returnsc*U.MonMulmultipliesUby the monomialx^nand returnsx^n * U.XMulmultipliesUbyx(by the monomialx^1) and returnsx * U.Shiftreturnsc + x*U
-
Variadic algebraic operations:
Plus,LessandTimes
-
Substitution:
MonSubst: Monomial Substitution:U(c*x^n)Each Ui is multiplied byc^iand followed by n-1 zeros.Subst: Substitute V for x in U:U(V(x))(also called "composition").
-
The operators from differential calculus / analysis:
Deriv: DifferentiatesUand returns the derivative.Integ: Integrate, with const of integration.
-
further
Recip: the reciprocal of a power series:1 / UExpexponentiation of a power series (with constant term equal zero).
provides power series of given coefficient(s):
- Monomial:
c * x^n - Binomial:
(1+x)^c, a finite polynom iffcis a positive and an alternating infinite power series otherwise. - Polynom(a ...): converts coefficients, constant term first, to a (finite) power series, the polynom in the coefficients.
provides functions which return specific power series such as:
Factorialsstarting from zero: 1, 1, 2, 6, 24, 120, 720, 5040, 40.320 ...OneByFactorialstarting from zero: 1/1, 1/1, 1/2, 1/6, 1/120, 1/720 ...Fibonaccisstarting from zero: 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 114 ...OneByFibonaccistarting from zero: 1/1, 1/2, 1/3, 1/5, 1/8, 1/13, 1/21 ...Harmonics: 1, 1+ 1/2, 1+ 1/2+ 1/3, 1+ 1/2+ 1/3+ 1/4, 1+ 1/2+ 1/3+ 1/4+ 1/5 ...Sincosreturns the power series for sine and cosine (in radians).Sinreturns the power series for sine (in radians).Cosreturns the power series for cosine (in radians).Tanreturns the power series for tangens (in radians) asSin/Cos.ATanreturns the power series for tangens (in radians) asInteg( 1 / ( 1 + x°2 ) )Secreturns the power series for secans (in radians) as1/Cos.CscXreturns the power series for cosecans (in radians) * x as1/(Sin*1/x).CotXreturns the power series for cotangens (in radians) * x asCos/(Sin*1/x).TanRreturns the power series for tangens (in radians) asATan.Revert.
provides methods to evaluate or print a given power series such as:
EvalAtevaluates a power series atx=cfor up tonterms.EvalNevaluates a power series atx=cfor up tonterms in floating point.Printnprints up to n terms of a power series.Printerreturns a copy ofU, and concurrently prints up to n terms of it. Useful to inspect formulas as it can be chained.Printone billion terms. Use at Your own risk ;-)
provides the bridge between the types used within the package (Coefficient and PS) and their imported realization.
As of now, there are types.go.rat and types.go.math.big.
Whichever is copied to types.go determines the chosen realization.
There are wrappers to the underlying demand channel package:
Splitreturns a pair of power series identical to the given one.Appendall coefficients fromUintoInto.NextGetFromUforIntoand report success. Follow withInto.Send( f(c) ), iff ok.GetWithreturns each first value received from the two given power series together with their respective ok boolean.SendCfnFromapplies a functioncfn(From)to a coefficent received fromFrom, sends the result intoIntoand report success.
And for the latter one there are closure functions on some coefficient math - for convenient use with SendCfnFrom
Note: Such closures are used where it helps to tighten the implementation of an algorithm, in other places computions are intentionally written direct and explicit.
provides special (and non-exported) rational coefficients such a aZero or aOne.
Your suggestions, remarks, questions and/or contributions are welcome ;-)