%% $Id: pst-func.pro 694 2023-04-05 19:17:32Z herbert $
%%
%% This is file `pst-func.pro',
%%
%% IMPORTANT NOTICE:
%%
%% Package `pst-func'
%%
%% Herbert Voss <
[email protected]>
%%
%% This program can be redistributed and/or modified under the terms
%% of the LaTeX Project Public License Distributed from CTAN archives
%% in directory macros/latex/base/lppl.txt.
%%
%% DESCRIPTION:
%% `pst-func' is a PSTricks package to plot special math functions
%%
%%
%% version 0.20 / 2023-04-04 Herbert Voss
%
/tx@FuncDict 100 dict def
tx@FuncDict begin
%
/eps4 1.0e-04 def
/eps5 1.0e-05 def
/eps8 1.0e-08 def
%
/PiHalf 1.57079632679489661925640 def
/CEuler 0.5772156649 def % Euler-Mascheroni constant
%
/factorialR {
dup 1e32 gt { pop 1e32 } {
dup 0 eq % check for the argument being 0
{ pop 1 } % if so, the result is 1
{ dup 1 sub factorial % call recursively with n - 1
mul % multiply the result with n
} ifelse
} ifelse
} def
%
%Iterative
/factorial {
1 % initial value for the product
1 1 % for's start value and increment
4 -1 roll % bring the argument to the top as for's end value
{ mul } for
} def
%
%
/MoverN { % m n on stack, returns the binomial coefficient m over n
2 dict begin
/n exch def /m exch def
n 0 eq { 1 }{
m n eq { 1 }{
m factorial n factorial m n sub factorial mul div } ifelse } ifelse
end
} def
%
/Pascal [
[ 1 ] % 0
[ 1 1 ] % 1
[ 1 2 1 ] % 2
[ 1 3 3 1 ] % 3
[ 1 4 6 4 1 ] % 4
[ 1 5 10 10 5 1 ] % 5
[ 1 6 15 20 15 6 1 ] % 6
[ 1 7 21 35 35 21 7 1 ] % 7
[ 1 8 28 56 70 56 28 8 1 ] % 8
[ 1 9 36 84 126 126 84 36 9 1 ] % 9
] def
%
/GetBezierCoor { % t on stack
10 dict begin % hold all local
/t ED
/t1 1 t sub def % t1=1-t
/Coeff Pascal BezierType get def % get the coefficients
0 0 % initial values for x y
BezierType -1 0 { % BezierType,...,2,1,0
/I ED % I=BezierType,...,2,1,0
/J BezierType I sub def % J=0,1,2,...,BezierType
/T t I exp Coeff J get mul def % coeff(J)*t^I
/T1 t1 J exp def % t1^J
Points I dup add 1 add get % y(2*I+1)
T mul T1 mul add % the y coordinate
exch % y x
Points I dup add get % x(2*I)
T mul T1 mul add % the x coordinate
exch % x y
} for % x y on stack
end
} def
/BezierCurve { % on stack [ coors psk@plotpoints BezierType
% 10 dict begin
/BezierType ED % 2,3,4,5,6,...
1 exch div /epsilon ED % step for Bezier =1/plotpoints
] % [ yi xi ... y3 x3 y2 x2 y1 x1 y0 x0]
ps@ReverseOrderOfPoints % [y0 x0 y1 x1 ... yi xi]
/Points ED % save Points array
epsilon GetBezierCoor % next Bezier point
Points 0 get Points 1 get % starting point
ArrowA lineto
epsilon epsilon 1 epsilon sub { % on stack is the loop variable
GetBezierCoor lineto
} for
1 epsilon sub GetBezierCoor
1 GetBezierCoor
ArrowB lineto moveto
% end
} def
/Bernstein { % on stack tStart tEnd plotpoints i n
12 dict begin % hold all local
/envelope ED % plot envelope?
/n ED
/i ED
/ni n i sub def
/epsilon ED % step=1/plotpoints
/tEnd ED
/tStart ED
%
% B_{i,n}(t)=\binom{n}{i}t^i(1-t)^{n-i} (Bernstein)
% f_n(x)=\frac{1}{\sqrt{\pi n\cdot x(1-x)}} (envelope)
%
n i MoverN /noveri ED % \binom{n}{i}
[ % for the array of points
tStart epsilon tEnd {
dup dup /t ED % leave one on stack
neg 1 add /t1 ED % t1=1-t
envelope
{ t t1 mul 4 mul PiHalf mul n mul sqrt 1 exch Div } % envelope
{ noveri t i exp mul t1 ni exp mul } ifelse % t f(t)
ScreenCoor % convert to screen coor
} for
end
false /Lineto /lineto load def Line
} def
%%
/Si { % integral sin from 0 to x (arg on stack)
10 dict begin % hold all local
dup 0 eq
{ pop 0 }
{
/arg exch def % x
/arg2 arg dup mul def
/Sum arg def %
/sign -1 def
/I 3 def
/Frac arg2 arg mul 6 div def
{ % a sequence of x - x^3/(3*3!) + x^5/(5*5!) -...+...
Frac I div sign mul
dup abs eps5 lt { pop exit } if
Sum add /Sum exch def
/sign sign neg def
/I I 2 add def
Frac arg2 mul I 1 sub I mul div /Frac ED
% arg I Power dup abs 1e30 gt { pop exit } if
% I factorial div I div sign mul
% dup abs eps8 lt { pop exit } if
% Sum add /Sum exch def
% /sign sign neg def
% /I I 2 add def
} loop
Sum
} ifelse
end
} def
%
/si { % integral sin from x to infty -> si(x)=Si(x)-pi/2
Si PiHalf sub
} def
%
/Ci { % integral cosin from x to infty (arg on stack)
10 dict begin % hold all local
abs /arg exch def
arg 0 eq { 0 } {
/arg2 arg dup mul def
/Sum CEuler arg ln add def
/sign -1 def
/I 2 def
/Frac arg2 2 div def % first fraction
{ Frac I div sign mul
dup abs eps5 lt { pop exit } if
Sum add /Sum exch def
/sign sign neg def
/I I 2 add def
Frac arg2 mul I 1 sub I mul div /Frac ED
} loop
Sum
} ifelse
end
} def
%
/ci { % integral cosin from x to infty -> ci(x)=-Ci(x)+ln(x)+CEuler
dup Ci neg exch abs ln add CEuler add
} def
%
/MaxIter 255 def
/func { coeff Derivation FuncValue } def
/func' { coeff Derivation 1 add FuncValue } def
/func'' { coeff Derivation 2 add FuncValue } def
%
/NewtonMehrfach {% the start value must be on top of the stack
/Nx exch def
/Iter 0 def
{
/Iter Iter 1 add def
Nx func /F exch def % f(Nx)
F abs eps4 lt { exit } if
Nx func' /FS exch def % f'(Nx)
FS 0 eq { /FS 1.0e-06 def } if
Nx func'' /F2S exch def % f''(Nx)
1.0 1.0 F F2S mul FS dup mul div sub div /J exch def
J F mul FS div /Diff exch def
/Nx Nx Diff sub def
Diff abs eps5 lt Iter MaxIter gt or { exit } if
} loop
Nx % the returned value ist the zero point
} def
/Steffensen {% the start value must be on top of the stack
/y0 exch def % the start value
/Iter 0 def /MaxIter 200 def
{ pstack
y0 func /F exch def
F abs eps4 lt { exit } if
y0 F sub /Phi exch def
Phi func /F2 exch def
F2 abs eps4 le { exit }{
Phi y0 sub dup mul Phi F2 sub 2 Phi mul sub y0 add Div /Diff exch def
y0 Diff sub /y0 exch def
Diff abs eps5 le { exit } if
} ifelse
/Iter Iter 1 add def
Iter MaxIter gt { exit } if
} loop
y0 28 mul % the returned value ist the zero point
0
3 0 360 arc gsave 0 0 1 setrgbcolor fill grestore 1 setlinewidth stroke
} def
%
/Horner {% x [coeff] must be on top of the stack
aload length
dup 2 add -1 roll
exch 1 sub {
dup 4 1 roll
mul add exch
} repeat
pop % the y value is on top of the stack
} def
%
/FuncValue {% x [coeff] Derivation must be on top of the stack
{
aload % a0 a1 a2 ... a(n-1) [array]
length % a0 a1 a2 ... a(n-1) n
1 sub /grad exch def % a0 a1 a2 ... a(n-1)
grad -1 1 { % for n=grad step -1 until 1
/n exch def % Laufvariable speichern
n % a0 a1 a2 ... a(n-1) n
mul % a0 a1 a2 ... a(n-1)*n
grad 1 add % a0 a1 a2 ... a(n-1)*n grad+1
1 roll % an*na0 a1 a2 ... a(n-2)
} for
pop % loesche a0
grad array astore % [ a1 a2 ... a(n-2)]
} repeat
Horner
} def
%
/FindZeros { % dxN dxZ must be on top of the stack (x0..x1 the intervall) => []
12 dict begin
/dxZ exch def /dxN exch def
/pstZeros [] def
x0 dxZ x1 { % suche Nullstellen
/xWert exch def
xWert NewtonMehrfach
%xWert Steffensen
/xNull exch def
pstZeros aload length /Laenge exch def % now test if value is a new one
Laenge 0 eq
{ xNull 1 }
{ /newZero true def
Laenge {
xNull sub abs dxN lt { /newZero false def } if
} repeat
pstZeros aload pop
newZero { xNull Laenge 1 add } { Laenge } ifelse } ifelse
array astore
/pstZeros exch def
} for
pstZeros % the end array is now on the stack
end
} def
%
/Simpson { % on stack must be a b M useXVal --- simple version ---
% /SFunc must be defined
/useX ED % for algebraic functions which uses f(x)
/M ED /b ED /a ED
/h b a sub M 2 mul div def
/s1 0 def
/s2 0 def
1 1 M {
/simp_k exch def
/xVal simp_k 2 mul 1 sub h mul a add def
/s1 s1 xVal useX { /x exch def } if SFunc add def
} for
1 1 M 1 sub {
/simp_k exch def
/xVal simp_k 2 mul h mul a add def
/s2 s2 xVal useX { /x exch def } if SFunc add def
} for
/I a useX { /x exch def } if SFunc b useX { /x exch def } if SFunc add s1 4 mul add s2 2 mul add 3 div h mul def
} def
%
%
/LogGamma { 5 dict begin % z on stack
/z ED
/sum 0 def
/logGamma_k 1 def
{
z logGamma_k div dup 1 add ln sub dup
abs eps8 lt { pop exit } if
sum add /sum exch def
/logGamma_k logGamma_k 1 add def
} loop
sum z ln sub CEuler z mul sub
end
} def
%
/ChebyshevT {
5 dict begin % z on stack
/xtmp exch def
/n exch def
0 0 1 n .5 mul floor {
/cheb_k exch def
xtmp xtmp mul 1 sub cheb_k exp
xtmp n 2 cheb_k mul sub exp mul
n 2 cheb_k mul MoverN mul
add
} for
end
} def
%
/ChebyshevU {
5 dict begin % z on stack
/xtmp exch def
/n exch def
0 0 1 n .5 mul floor {
/cheb_k exch def
xtmp xtmp mul 1 sub cheb_k exp
xtmp n 2 cheb_k mul sub exp mul
n 1 add 2 cheb_k mul 1 add MoverN mul
add
} for
end
} def
%
/vasicek{ %density=sqrt((1-R2)/R2)*exp(1/2*(norminv(x)2 - (1/sqrt(R2)*((sqrt(1-R2)*norminv(x)-norminv(pd)))2))
2 dict begin
/pd where { pop }{ /pd 0.22 def } ifelse % element of (0,1) probability of default of portfolio
/R2 where { pop }{ /R2 0.11 def } ifelse % element of (0,1) R_Squared of portfolio
dup % x x
norminv % x norminv(x)
dup mul % x norminv(x)^2
exch % norminv(x)2 x
norminv % norminv(x)2 norminv(x)
1 R2 sub sqrt mul % norminv(x)2 sqrt(1-R2)*norminv(x)
pd norminv sub % norminv(x)2 sqrt(1-R2)*norminv(x)-norminv(pd)
R2 sqrt div % norminv(x)2 1/sqrt(R2)*(sqrt(1-R2)*norminv(x)-norminv(pd))
dup mul % norminv(x)2 (1/sqrt(R2)*(sqrt(1-R2)*norminv(x)-norminv(pd)))2
sub % norminv(x)2 -(1/sqrt(R2)*(sqrt(1-R2)*norminv(x)-norminv(pd)))2
2 div % 1/2*(norminv(x)2 -(1/sqrt(R2)*(sqrt(1-R2)*norminv(x)-norminv(pd)))2)
ENeperian exch exp % exp(1/2*(norminv(x)2 -(1/sqrt(R2)*(sqrt(1-R2)*norminv(x)-norminv(pd)))2)
1 R2 sub % exp(1/2*(norminv(x)2 -(1/sqrt(R2)*(sqrt(1-R2)*norminv(x)-norminv(pd)))2) 1-R2
R2 div % exp(1/2*(norminv(x)2 -(1/sqrt(R2)*(sqrt(1-R2)*norminv(x)-norminv(pd)))2) (1-R2)/R2
sqrt % exp(1/2*(norminv(x)2 -(1/sqrt(R2)*(sqrt(1-R2)*norminv(x)-norminv(pd)))2) sqrt((1-R2)/R2)
mul % sqrt((1-R2)/R2)*exp(1/2*(norminv(x)2 - (1/sqrt(R2)*((sqrt(1-R2)*norminv(x)-norminv(pd)))2))
end
} def
%end{vasicek density}
%
%
https://mathworld.wolfram.com/ConfluentHypergeometricFunctionoftheFirstKind.html
/ConfHyperFunc { % Confluent Hypergeometric Funtion of the First Kind
% on stack must be a b z
15 dict begin
/z ED /b ED /a ED
/sum 1 def
/k 0 def
/nom 1 def
/denom 1 def
{
nom a k add mul z mul /nom ED
denom b k add mul k 1 add mul /denom ED
nom denom div /diff ED
sum diff add /sum ED
diff 1e-5 lt { exit } { k 1 add /k ED } ifelse
k 1000 ge { (Error ConfHyperFunc: k =1000) == exit } if
} loop
sum
end
} def
%
%
https://mathworld.wolfram.com/BetaFunction.html
/BETA {% BETA function ((p-1)!(q-1)!)/(p+q-1)!
% on stack must be p q
2 dict begin
/q ED
/p ED
p 1 sub factorial q 1 sub factorial
mul
p q add 1 sub factorial
div
end
} def
%
end
%
/arraySum { % on stack the array
5 dict begin
dup length 0 eq
{}
{ /xArray exch def
/xSum 0 def
/i 0 def
xArray length {
/xSum xSum xArray i get add def
/i i 1 add def
} repeat
} ifelse
xSum
end
} def
%
/arrayProd { % on stack the array
5 dict begin
dup length 0 eq
{}
{ /xArray exch def
/xProd 1 def
/i 0 def
xArray length {
/xProd xProd xArray i get mul def
/i i 1 add def
} repeat
} ifelse
xProd
end
} def
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% subroutines for complex numbers, given as an array [a b]
% which is a+bi = Real+i Imag
%% Global defined
%
/cxadd { % [a1 b1] [a2 b2] = [a1+a2 b1+b2]
dup 0 get % [a1 b1] [a2 b2] a2
3 -1 roll % [a2 b2] a2 [a1 b1]
dup 0 get % [a2 b2] a2 [a1 b1] a1
3 -1 roll % [a2 b2] [a1 b1] a1 a2
add % [a2 b2] [a1 b1] a1+a2
3 1 roll % a1+a2 [a2 b2] [a1 b1]
1 get % a1+a2 [a2 b2] b1
exch 1 get % a1+a2 b1 b2
add 2 array astore
} def
%
/cxneg { % [a b]
dup 1 get % [a b] b
exch 0 get % b a
neg exch neg % -a -b
2 array astore
} def
%
/cxsub { cxneg cxadd } def % same as negative addition
%
% [a1 b1][a2 b2] = [a1a2-b1b2 a1b2+b1a2] = [a3 b3]
/cxmul { % [a1 b1] [a2 b2]
dup 0 get % [a1 b1] [a2 b2] a2
exch 1 get % [a1 b1] a2 b2
3 -1 roll % a2 b2 [a1 b1]
dup 0 get % a2 b2 [a1 b1] a1
exch 1 get % a2 b2 a1 b1
dup % a2 b2 a1 b1 b1
5 -1 roll dup % b2 a1 b1 b1 a2 a2
3 1 roll mul % b2 a1 b1 a2 b1a2
5 -2 roll dup % b1 a2 b1a2 b2 a1 a1
3 -1 roll dup % b1 a2 b1a2 a1 a1 b2 b2
3 1 roll mul % b1 a2 b1a2 a1 b2 a1b2
4 -1 roll add % b1 a2 a1 b2 b3
4 2 roll mul % b1 b2 b3 a1a2
4 2 roll mul sub % b3 a3
exch 2 array astore
} def
%
% [a b]^2 = [a^2-b^2 2ab] = [a2 b2]
/cxsqr { % [a b] square root
dup 0 get exch 1 get % a b
dup dup mul % a b b^2
3 -1 roll % b b^2 a
dup dup mul % b b^2 a a^2
3 -1 roll sub % b a a2
3 1 roll mul 2 mul % a2 b2
2 array astore
} def
%
/cxsqrt { % [a b]
% dup cxnorm sqrt /r exch def
% cxarg 2 div RadtoDeg dup cos r mul exch sin r mul cxmake2
cxlog % log[a b]
2 cxrdiv % log[a b]/2
aload pop exch % b a
2.781 exch exp % b exp(a)
exch cxconv exch % [Re +iIm] exp(a)
cxrmul %
} def
%
/cxarg { % [a b]
aload pop % a b
exch atan % arctan b/a
DegtoRad % arg(z)=atan(b/a)
} def
%
% log[a b] = [a^2-b^2 2ab] = [a2 b2]
/cxlog { % [a b]
dup % [a b][a b]
cxnorm % [a b] |z|
log % [a b] log|z|
exch % log|z|[a b]
cxarg % log|z| Theta
cxmake2 % [log|z| Theta]
} def
%
% square of magnitude of complex number
/cxnorm2 { % [a b]
dup 0 get exch 1 get % a b
dup mul % a b^2
exch dup mul add % a^2+b^2
} def
%
/cxnorm { % [a b]
cxnorm2 sqrt
} def
%
/cxconj { % conjugent complex
dup 0 get exch 1 get % a b
neg 2 array astore % [a -b]
} def
%
/cxre { 0 get } def % real value
/cxim { 1 get } def % imag value
%
% 1/[a b] = ([a -b]/(a^2+b^2)
/cxrecip { % [a b]
dup cxnorm2 exch % n2 [a b]
dup 0 get exch 1 get % n2 a b
3 -1 roll % a b n2
dup % a b n2 n2
4 -1 roll exch div % b n2 a/n2
3 1 roll div % a/n2 b/n2
neg 2 array astore
} def
%
/cxmake1 { 0 2 array astore } def % make a complex number, real given
/cxmake2 { 2 array astore } def % dito, both given
%
/cxdiv { cxrecip cxmul } def
%
% multiplikation by a real number
/cxrmul { % [a b] r
exch aload pop % r a b
3 -1 roll dup % a b r r
3 1 roll mul % a r b*r
3 1 roll mul % b*r a*r
exch 2 array astore % [a*r b*r]
} def
%
% division by a real number
/cxrdiv { % [a b] r
1 exch div % [a b] 1/r
cxrmul
} def
%
% exp(i theta) = cos(theta)+i sin(theta) polar<->cartesian
/cxconv { % theta
RadtoDeg dup sin exch cos cxmake2
} def
%
% cxexp z^k with k as a natural number
/cxexp { % z k
3 dict begin
dup 0 eq { pop pop [1 0] }{
/k ED
/z ED
/sol [1 0] def
k { sol z cxmul /sol ED } repeat
sol } ifelse
end
} def
%