#######################################################################
# APPL Software (c) 2001,2002,2008  Andrew Glen, Larry Leemis, Diane Evans
# Version 2.3, dated 11 March April 2008
#1111111111222222222233333333334444444444555555555566666666667777777777#  
#  Filename: startup6.map
#
#  Procedure name: None
#
#  Other APPL Procedures Called: None
#             
#  Date Revised: March 20, 2001
#
#  Purpose:  Start up file for APPL   
#
#  Arguments: None
#

#
#  Unprotect the Maple system name Product, so we can name the product
#  of 2 random variables the procedure Product
#
unprotect(Product):
print(`PROCEDURES:`):
print(`AllPermutations(n)`, `AllCombinations(n, k)`, `Benford(X)`,
    `BootstrapRV(Data)`, 
    `CDF:CHF:HF:IDF:PDF:SF(X, [x]))`, `CoefOfVar(X)`, 
    `Convolution(X, Y)`, `ConvolutionIID(X, n)`, 
    `CriticalPoint(X, prob)`, `Determinant(MATRIX)`, 
    `Difference(X, Y)`, `Display(X)`, `ExpectedValue(X, [g])`, 
    `KSTest(X, Data, Parameters)`, `Kurtosis(X)`, `Maximum(X, Y)`,
    `MaximumIID(X, n)`, `Mean(X)`, `MGF(X)`, `Minimum(X, Y)`,
    `MinimumIID(X, n)`, `Mixture(MixParameters, MixRVs)`, 
    `MLE(X, Data, Parameters, [Rightcensor])`, 
    `MLENHPP(X, Data, Parameters, obstime)`,
    `MLEWeibull(Data, [Rightcensor])`, `MOM(X, Data, Parameters)`,
    `NextCombination(Previous, size)`, `NextPermutation(Previous)`,
    `OrderStat(X, n, r, ["wo"])`, `PlotDist(X, [low], [high])`, 
    `PlotEmpCDF(Data, [low], [high])`,  
    `PlotEmpCIF(Data, [low], [high])`, `PlotEmpSF(Data, Censor)`,
    `PlotEmpVsFittedCDF(X, Data, Parameters, [low], [high])`,
    `PlotEmpVsFittedCDF(X, Data, Parameters, [low], [high])`,
    `PlotEmpVsFittedSF(X, Data, Parameters, Censor, low, high)`, 
    `PPPlot(X, Data, Parameters)`, `Product(X, Y)`, 
    `ProductIID(X, n)`, `QQPlot(X, Data, Parameters)`, 
    `RangeStat(X, n, ["wo"])`, 
    `Skewness(X)`, `Transform(X, g)`, `Truncate(X, low, high)`,
    `Variance(X)`, `VerifyPDF(X)`):
print(``):
print(`Procedure Notation:`):
print(`X and Y are random variables`):
print(`Greek letters are numeric or symbolic parameters`):
print(`x is numeric or symbolic`):
print(`n and r are positive integers, n >= r`):
print(`low and high are numeric`):
print(`g is a function`):
print(`Brackets [] denote optional parameters`):
print(`"double quotes" denote character strings`):
print(`MATRIX is a 2 x 2 array of random variables`):
print(`A capitalized parameter indicates that it must be`): 
print(`entered as a list --> ex. Data := [1, 12.4, 34, 52.45, 63]`):
print(``):

print(`Variate Generation:`):
print(`ArcTanVariate(alpha, phi)`, `BinomialVariate(n, p, m)`,
    `ExponentialVariate(lambda)`, `NormalVariate(mu, sigma)`,
    `UniformVariate()`,
    `WeibullVariate(lambda, kappa, m)`):
print(``):


print(`DATA SETS:`):
print(`BallBearing`, `HorseKickFatalities`, `Hurricane`, `MP6`,
    `RatControl`, `RatTreatment`, `USSHalfBeak`):
DataSets():
print(``):


# 
#  Define structured types for discrete random variables
#
#
#  9/5/2000: `type/dot` is Maple's type range
#
`type/dot` := {constant .. constant, symbol .. constant, constant ..
    symbol, symbol .. symbol}: 
#
#  Define binary type as integers 0 or 1
#
`type/binary` := {0, 1}:
#
#  Constructs an indexing function that returns infinity for all
#  unassigned entries in an array (similar to the sparse indexing
#  function which returns zero) 
#
`index/infinity` := proc(Idx :: list, Tbl :: table, Entry :: list)
  if (nargs = 2) then
    if (assigned(Tbl[op(Idx)])) then 
      Tbl[op(Idx)]:
    else 
      infinity:
    fi:
  elif Entry = [infinity] then     
    infinity:
  else
    Tbl[op(Idx)] := op(Entry);
  fi:
end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: allcombos3.map
#
AllCombinations := proc(n :: posint, k :: posint)
local A, i, MoveLeft, h, m:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 2) then
  print(`ERROR(AllCombinations): This procedure requires 2 arguments`):
  print(`k items chosen from n`):
  RETURN():
fi:
#
#  Check that k is no greater than n
#
if (k > n) then
  print(`ERROR(AllCombinations): k must be less than or equal to n`):
  RETURN():
fi:

A := [seq(i, i = 1 .. k)]:
print(`A is`, A):

while (A[1] <> n - k + 1) do
  if (A[k] <> n) then
    A[k] := A[k] + 1:
  else
    MoveLeft := true:
    for h from 1 to (k - 1) while (MoveLeft = true) do
      if (A[k - h] < n - h) then
        A[k - h] := A[k - h] + 1:
        for m from (h - 1) to 0 by -1 do
          A[k - m] := A[k - (m + 1)] + 1:
        od:
      MoveLeft := false:
      fi:
    od:
  fi:
  print(`A is`, A):
od:

end:
    
 
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: allperms1.map
#
AllPermutations := proc(n :: posint)
local A, i, Continue, All, swapped, j, OrigVal, MiniMaxIndex, k, Temp1,
    l, Temp2, m:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 1) then
  print(`ERROR(AllPermutations): This procedure requires 1 argument:`):
  print(`n, the number of items to be permuted`):
  RETURN():
fi:

A := [seq(i, i = 1 .. n)]:
print(`A is`, A):
Continue := true:
for All from 1 to n! - 1 do
  swapped := false:
  for j from n - 1 to 1 by -1 while (Continue = true) do
    # print(A[j]):
    # print(A[j + 1]):

    if ((A[j] < A[j + 1]) and not(swapped)) then
      OrigVal := A[j]:
      MiniMaxIndex := j + 1:
      # print(`MiniMaxIndex is`, MiniMaxIndex):
      for k from n to j + 1 by -1 do
        # print(`swapping is needed since A[j] < A[j + 1]`):
        swapped := true:

        if ((A[k] < A[MiniMaxIndex]) and (A[k] > OrigVal)) then
          # print(`A[k] is`, A[k]):
          # print(`A[Mini] is`, A[MiniMaxIndex]):
          MiniMaxIndex := k:
        fi:
      od:
      Temp1 := A[MiniMaxIndex]:
      A[MiniMaxIndex] := A[j]:
      A[j] := Temp1:
      # print(`A after swap is`, A):
#
# don't need to reverse if haven't swapped
#
      if (swapped = true) then
      for l from j + 1 to n do
        Temp2[l] := A[l]:
      od:
      for m from j + 1 to n do
        A[m] := Temp2[n + j + 1 - m]:
      od: 
      # print(`A after reversal is`, A):
      fi:
    fi:
    # Continue := false:
  od:
  # Continue := true:
  print(`A is`, A):
od:
RETURN(): 
end:

#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: arctanvariate1.map
#  
#  Procedure Name: ArcTanVariate(alpha, phi)
#
#  Other APPL Procedures Called: None
#
#  Date: June 1, 1999
#
#  Purpose: 
#
#  Arguments:
#
#  Algorithm:
#
ArcTanVariate := proc(alpha, phi)
local variate:

variate := phi + 1 / alpha * tan(Pi / 2 - (1 - (rand() / 1000000000000))
* (arctan(alpha * phi) + Pi / 2)):
RETURN(variate):

end:

#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: benford7.map
#
#  Procedure Name: Benford(X)
#
#  Other APPL Procedures Called: PDF, CDF, TruncateRV, Transform,
#                                MixtureRV
#
#  Date: May 28, 1999
#
#  Purpose: Given a continuous random variable X, this procedure returns
#           the PDF of Z, as defined in Leemis, Schmeiser, and Evans
#           (2000)
#
#  Arguments: X: A continuous random variable.
# 
#  Algorithm:
#    1.  Check for 1 argument, the RV X
#    2.  Check that the RV X is in the list of 3 lists format
#    3.  Check that the RV X is continuous 
#    4.  Convert the RV X to PDF form
#    5.  Check that the RV supports are numeric and finite
#    6.  Compute the lower and upper summation limits
#    7.  Create lists Weight, TruncX, and Xprime that will hold 
#        (Hi - Lo + 1) elements
#    8.  Compute each "weight" and "truncated distribution" for the
#        intervals [Lo, Lo + 1], [Lo + 1, Lo + 2], ..., [d, d + 1], ...,
#        [Hi - 2, Hi - 1], [Hi - 1, Hi] 
#    9.  For each value d, where d is a value s.t. Lo <= d <= Hi,
#        transform the truncated distribution by the function x -> x - d
#    10. Send the list of weights along with its list of truncated
#        distributions to the procedure Mixture to compute the PDF of Z,
#        as defined in Leemis, Schmeiser, and Evans (2000)
#
Benford := proc(X :: list(list))
local NumLists, fX, NumSegs, Lo, Hi, Weight, i, TruncX, Xprime, counter,
    d, n, NewWt, BenfX: 
#
#  Check for 1 argument, the RV X
#
if (nargs <> 1) then
  print(`ERROR(Benford): This procedure requires 1 argument:`):
  print(`A random variable`):
  RETURN():
fi:
#
#  Check that the random variable is in the list of 3 lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(Benford): The RV must be in a list of 3 lists format`):
  RETURN():
fi:
#
#  Check that the random variable is continuous  
#
if not(X[3][1] = "Continuous") then
  print(`ERROR(Benford): Random variable must be continuous`):
  RETURN():
fi:
#
#  Convert RV to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
    fX := X:
elif ((X[3][2] = "CDF") or
      (X[3][2] = "CHF") or
      (X[3][2] = "HF") or
      (X[3][2] = "IDF") or
      (X[3][2] = "SF")) then
    fX := PDF(X):
else
  print(`ERROR(Benford): RV must be given as`):
  print(`CDF, CHF, ,HF, IDF, PDF, or SF`):
  RETURN():
fi:
#
#  Check that the RV supports are numeric and finite
#
NumSegs := nops(fX[1]):
for i from 1 to (NumSegs + 1) do
  if (type(evalf(fX[2][i]), {symbol, infinity})) then
    print(`ERROR(Benford): Must specify numeric values for the`): 
    print(`supports of the RV X`):
    RETURN():
  fi:
od:
#
#  Compute the lower and upper summation limits
#
Lo := floor(fX[2][1]):
Hi := ceil(fX[2][NumSegs + 1]) - 1:
#
#  Create lists Weight, TruncX, and Xprime that will hold (Hi - Lo + 1)
#  elements
#
Weight := []:
TruncX := [seq(0, i = 1 .. (Hi - Lo + 1))]:
Xprime := [seq(0, i = 1 .. (Hi - Lo + 1))]:
counter := 1:
#
#  Compute each "weight" and "truncated distribution" for the intervals
#  [Lo, Lo + 1], [Lo + 1, Lo + 2], ...,  [d, d + 1], ..., 
#  [Hi - 2, Hi - 1], [Hi - 1, Hi] 
#  For each value d, where d is a value s.t. Lo <= d <= Hi, transform
#  the truncated distribution by the function x -> x - d
#
for d from Lo to Hi do
  for n from 1 to NumSegs do
    if (evalf(floor(fX[2][n])) <= evalf(d) and 
        evalf(d + 1) <= evalf(ceil(fX[2][n + 1]))) then
      NewWt := CDF(fX, d + 1) - CDF(fX, d):
    fi:
  od:
  Weight := [op(Weight), NewWt]:
  TruncX[counter] := Truncate(fX, d, d + 1):
  Xprime[counter] := Transform(TruncX[counter], [[x -> x - d], [-infinity,
      infinity]]):
  counter := counter + 1:
od:
#
#  Send the list of weights along with its list of truncated distributions 
#  to the procedure MixtureRV to compute the PDF of Z
#
BenfX := Mixture(Weight, Xprime):
end:#1111111111222222222233333333334444444444555555555566666666667777777777#  
#  Filename: binomialvariate1.map
#
#  Procedure name: BinomialVariate(n, p, m)
#
#  Other APPL Procedures Called: UniformVariate
#             
#  Date Revised: September 12, 1999
#
#  Purpose: Given the parameters n and p for the binomial distribution,
#           BinomialVariate returns m binomial variates, and the mean and variance
#           of the m binomial variates 
#
#  NOTE: only works for n = 16 at this moment
#
BinomialVariate := proc(n :: posint, p :: positive, m :: posint)
local pdf, pdfvalue, i, cdfvalue, counter, BinVars, k, U, BinVar, mean, j, variance:

pdf := n! / ((n - x)! * x!) * p ^ x * (1 - p) ^ (n - x): 
pdfvalue := [seq(0, i = 1 .. n)]:

for i from 1 to n do  
  pdfvalue[i] := subs(x = i, pdf):
od:
# print(pdfvalue):

cdfvalue := [seq(0, i = 1 .. n)]:
cdfvalue[n] := 1 - pdfvalue[n]:
counter := n - 1:

while (counter > 0) do
  cdfvalue[counter] := cdfvalue[counter + 1] - pdfvalue[counter]:
  counter := counter - 1:
od:
# print(cdfvalue):

BinVars := array(1 .. m):
for k from 1 to m do
  U := UniformVariate():
  if ((U >= 0) and (U < cdfvalue[1])) then
    BinVar := 0:
  elif ((U >= cdfvalue[1]) and (U < cdfvalue[2])) then
    BinVar := 1:
  elif ((U >= cdfvalue[2]) and (U < cdfvalue[3])) then
    BinVar := 2:
  elif ((U >= cdfvalue[3]) and (U < cdfvalue[4])) then
    BinVar := 3:
  elif ((U >= cdfvalue[4]) and (U < cdfvalue[5])) then
    BinVar := 4:
  elif ((U >= cdfvalue[5]) and (U < cdfvalue[6])) then
    BinVar := 5:
  elif ((U >= cdfvalue[6]) and (U < cdfvalue[7])) then
    BinVar := 6:
  elif ((U >= cdfvalue[7]) and (U < cdfvalue[8])) then
    BinVar := 7:
  elif ((U >= cdfvalue[8]) and (U < cdfvalue[9])) then
    BinVar := 8:
  elif ((U >= cdfvalue[9]) and (U < cdfvalue[10])) then
    BinVar := 9:
  elif ((U >= cdfvalue[10]) and (U < cdfvalue[11])) then
    BinVar := 10:
  elif ((U >= cdfvalue[11]) and (U < cdfvalue[12])) then
    BinVar := 11:
  elif ((U >= cdfvalue[12]) and (U < cdfvalue[13])) then
    BinVar := 12:
  elif ((U >= cdfvalue[13]) and (U < cdfvalue[14])) then
    BinVar := 13:
  elif ((U >= cdfvalue[14]) and (U < cdfvalue[15])) then
    BinVar := 14:
  elif ((U >= cdfvalue[15]) and (U < cdfvalue[16])) then
    BinVar := 15:
  elif ((U >= cdfvalue[16]) and (U <= 1)) then
    BinVar := 16:
  fi:
  BinVars[k] := BinVar:
od:
# print(BinVars):

mean := sum(BinVars[j], j = 1 .. m) / m:
variance := sum((BinVars[j] - mean) ^ 2, j = 1 .. m) / (m - 1):
print(`Mean is `, mean):
print(`Variance is `, variance):
RETURN():

end:
#  Filename: bootstraprv1.map
#
#  Procedure Name: BootstrapRV(Data)
#
#  Date: May 6, 2001
#
#  Purpose: 
#
#  Arguments: Data: list of data
# 
#  Algorithm:
#
BootstrapRV := proc(Data :: list)
local n, sublist1, i, sublist2, sublist3:

n := nops(Data):
sublist1 := [seq(1 / n, i = 1 .. n)]:
# print(sublist1):
sublist2 := Data:
sublist3 := ["Discrete", "PDF"]:
return([sublist1, sublist2, sublist3]):
end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: bruteforceconvolutionmethod1.map
#
#  Procedure Name: BruteForceConvolutionMethod()
#
#  Other APPL Procedures Called: HeapSort
#
#  Date: October 4, 2000
#
#  Purpose: 
#
#  Arguments: X, Y: Continuous random variables
#
#  Algorithm:
BruteForceConvolutionMethod := proc() 
global fX, fY:
local n, m, fV, s, Probs, k, i, j:

n := nops(fX[1]):
m := nops(fY[1]):

# 
#  If n = 1 and m = 1, return the convolution immediately and avoid
#  sending a small one element array to HeapSort
#
if (n = 1) and (m = 1) then
  s := [fX[2][1] + fY[2][1]]:
  Probs := [1]: 
  return(s, Probs):
fi:
s := array(1 .. n * m):
Probs := array(1 .. n * m):
k := 1:
for i from 1 to n do
  for j from 1 to m do
    s[k] := fX[2][i] + fY[2][j]: 
    Probs[k] := fX[1][i] * fY[1][j]:
    k := k + 1:
  od:
od:
s := convert(s, list):
Probs := convert(Probs, list):
# print(`s is`, s):
# print(`Probs is`, Probs):
return(HeapSort(s, Probs)):

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: bruteforceproductmethod1.map
#
#  Procedure Name: BruteForceProductMethod()
#
#  Other APPL Procedures Called: HeapSort
#
#  Date: October 4, 2000
#
#  Purpose: 
#
#  Arguments: X, Y: Continuous random variables
#
#  Algorithm:
BruteForceProductMethod := proc() 
global fX, fY:
local n, m, fV, s, Probs, k, i, j:

n := nops(fX[1]):
m := nops(fY[1]):
# 
#  If n = 1 and m = 1, return the convolution immediately and avoid
#  sending a small one element array to HeapSort
#  
#  Also return the convolution immediately if either fX = 0 or fY = 0
#
if (n = 1) and (m = 1) or (n = 1 and fX[2][1] = 0) or 
     (m = 1 and fY[2][1] = 0) then
  s := [fX[2][1] * fY[2][1]]:
  Probs := [1]: 
  return(s, Probs):
fi:
s := array(1 .. n * m):
Probs := array(1 .. n * m):
k := 1:
for i from 1 to n do
  for j from 1 to m do
    s[k] := fX[2][i] * fY[2][j]: 
    Probs[k] := fX[1][i] * fY[1][j]:
    k := k + 1:
  od:
od:
s := convert(s, list):
Probs := convert(Probs, list):
return(HeapSort(s, Probs)):

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: bruteforceproductq1q31.map
#
#  Procedure Name: BruteForceProductQ1Q3()
#
#  Other APPL Procedures Called: HeapSort
#
#  Date: January 9, 2001
#
#  Purpose: 
#
#  Arguments: X, Y: Continuous random variables
#
#  Algorithm:
BruteForceProductQ1Q3 := proc() 
global fXNeg, fXPos, fYNeg, fYPos:
local xneg, xpos, yneg, ypos, Q1Prod, Q1Prob, Q3Prod, Q3Prob, k, i1,
    j1, i3, j3, Q1Q3Prod, Q1Q3Prob:

xneg := nops(fXNeg[1]):
xpos := nops(fXPos[1]):
yneg := nops(fYNeg[1]):
ypos := nops(fYPos[1]):
Q1Prod := array(1 .. xpos * ypos):
Q1Prob := array(1 .. xpos * ypos):
Q3Prod := array(1 .. xneg * yneg):
Q3Prob := array(1 .. xneg * yneg):
k := 1:
for i1 from 1 to xpos do
  for j1 from 1 to ypos do
    Q1Prod[k] := fXPos[2][i1] * fYPos[2][j1]: 
    Q1Prob[k] := fXPos[1][i1] * fYPos[1][j1]:
    k := k + 1:
  od:
od:
k := 1:
for i3 from 1 to xneg do
  for j3 from 1 to yneg do
    Q3Prod[k] := fXNeg[2][i3] * fYNeg[2][j3]: 
    Q3Prob[k] := fXNeg[1][i3] * fYNeg[1][j3]:
    k := k + 1:
  od:
od:
Q1Prod := convert(Q1Prod, list):
Q1Prob := convert(Q1Prob, list):
Q3Prod := convert(Q3Prod, list):
Q3Prob := convert(Q3Prob, list):
Q1Q3Prod := [op(Q1Prod), op(Q3Prod)]:
Q1Q3Prob := [op(Q1Prob), op(Q3Prob)]:
return(HeapSort(Q1Q3Prod, Q1Q3Prob)):

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: bruteforceproductq2q41.map
#
#  Procedure Name: BruteForceProductQ2Q4()
#
#  Other APPL Procedures Called: HeapSort
#
#  Date: January 9, 2001
#
#  Purpose: 
#
#  Arguments: X, Y: Continuous random variables
#
#  Algorithm:
BruteForceProductQ2Q4 := proc() 
global fXNeg, fXPos, fYNeg, fYPos:
local xneg, xpos, yneg, ypos, Q2Prod, Q2Prob, Q4Prod, Q4Prob, k, i2,
    j2, i4, j4, Q2Q4Prod, Q2Q4Prob:

xneg := nops(fXNeg[1]):
xpos := nops(fXPos[1]):
yneg := nops(fYNeg[1]):
ypos := nops(fYPos[1]):
Q2Prod := array(1 .. xneg * ypos):
Q2Prob := array(1 .. xneg * ypos):
Q4Prod := array(1 .. xpos * yneg):
Q4Prob := array(1 .. xpos * yneg):
k := 1:
for i2 from 1 to xneg do
  for j2 from 1 to ypos do
    Q2Prod[k] := fXNeg[2][i2] * fYPos[2][j2]: 
    Q2Prob[k] := fXNeg[1][i2] * fYPos[1][j2]:
    k := k + 1:
  od:
od:
k := 1:
for i4 from 1 to xpos do
  for j4 from 1 to yneg do
    Q4Prod[k] := fXPos[2][i4] * fYNeg[2][j4]: 
    Q4Prob[k] := fXPos[1][i4] * fYNeg[1][j4]:
    k := k + 1:
  od:
od:
Q2Prod := convert(Q2Prod, list):
Q2Prob := convert(Q2Prob, list):
Q4Prod := convert(Q4Prod, list):
Q4Prob := convert(Q4Prob, list):
Q2Q4Prod := [op(Q2Prod), op(Q4Prod)]:
Q2Q4Prob := [op(Q2Prob), op(Q4Prob)]:
return(HeapSort(Q2Q4Prod, Q2Q4Prob)):

end:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: cdf17.map
#  
#  Procedure Name: CDF(X, [x])
#
#  Other APPL Procedures Called: PDF, Convert
#
#  Date: March 19, 2001
#
#  Purpose: CDF is a procedure that:
#          (1) Returns the cumulative distribution function of a 
#              random variable X in the APPL list of 3 lists format if
#              the only argument given is X, or
#          (2) Returns the value Pr(X <= x) if it is given the optional
#              argument x in addition to the RV X
#
#  Arguments: X: A continuous or discrete random variable; 
#             x (optional argument): A numeric value entered when
#                trying to determine Pr(X <= x)
#
#  Algorithm: 1. Perform error checking on user entered arguments
#             2. The CDF of X is determined by sending it to its 
#                appropriate category, which is based on whether:
#                A. X is continuous or discrete
#                B. X is entered in its PDF, CDF, SF, HF, CHF, or IDF
#                   format 
#             3. If only 1 argument (the random variable X) is entered
#                by the user, return the cumulative density function of
#                X in the APPL list of 3 lists format 
#             4. If 2 arguments are provided, return the value 
#                Pr(X <= x)
#
CDF := proc(X :: list(list), st)
local numlists, nsegments, FX, supp, fX, FCUM, i, FFX, t, prob, Y, Range,
    lo, hi, incr, transf, hf, SX, chf, sf, pdf, idf, pieces, numops, 
    noceil, ceilpiece, solns, nsolns, cdf, val, invfound, j, idfval, 
    losupp, hisupp, sublist1, n, IDX2, notfound, count, k:
#
#  Check for the appropriate number of arguments
#
if ((nargs <> 1) and (nargs <> 2)) then
  print(`ERROR(CDF): This procedure requires 1 or 2 arguments:`):
  print(`A random variable X and an optional argument x for`):
  print(`computing Pr(X <= x)`):
  return:
fi:
#
#  Check that the RV X is in the list of 3 lists format
#
numlists := nops(X):
if (numlists <> 3) then
  print(`ERROR(CDF): The RV X must be a list of 3 lists`):
  return:
fi:
#
#  Make sure X is given as a PDF, CDF, SF, HF, CHF, or IDF
#
if not(member(X[3][2], {"PDF", "CDF", "SF", "HF", "CHF", "IDF"})) then
  print(`ERROR(CDF): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
#
#  If the RV X is continuous, find and return the CDF of X
#
if (X[3][1] = "Continuous") then
  nsegments := nops(X[1]):
  if (X[3][2] = "CDF") then
    FX := X[1]:
    supp := X[2]:
  else
    fX := PDF(X):
    # print(`fX is`):
    # print(fX):
    FX := []:
    supp := fX[2]:
    FCUM := 0:
    for i from 1 to nsegments do 
      # print(`i is`): print(i): print(fX[2][i]):
      FFX := unapply(FCUM + int(fX[1][i](t), t = fX[2][i] .. x), x):
      # print(FFX):
      if (i < nsegments) then 
        FCUM := FFX(fX[2][i + 1]):
      fi:
      FX := [op(FX), unapply(simplify(FFX(x)), x)]:
      # print(FX): 
    od:
  fi:
#
#  Only 1 argument, X, given for the procedure
#
  if (nargs = 1) then
    return([FX, supp, ["Continuous", "CDF"]]):
#
#  Two arguments, X and x, provided for the procedure
#
  elif (nargs = 2) then
    if not(type(evalf(st), {numeric, infinity})) then
      if nsegments = 1 then
        prob := FX[1](st):
        return(prob):
      else
        print(`ERROR(CDF): Symbolic second arguments with a piecewise`):
        print(`CDF is not allowable in APPL at this time`):
        return:
      fi:
    fi:
    if (evalf(st) < evalf(supp[1])) then return(0):
    elif (evalf(st) >= evalf(supp[nsegments + 1])) then return(1) fi:
    for i from 1 to nsegments do 
      if ((evalf(st) >= evalf(supp[i])) and (evalf(st) < evalf(supp[i
          + 1]))) then
        break:
      fi:
    od:
    prob := FX[i](st):
    return(prob):
  fi:
#
#  If the RV X is discrete, find and return the CDF of X
#
elif (X[3][1] = "Discrete") then
#
#  If the RV X is discrete, then call the procedure Convert(X) to
#  convert the discrete random variable's support to a standard APPL
#  discrete RV support format. Assign the converted random variable
#  to the Maple variable Y.
#
  Y := Convert(X):
  FX[1] := Y[1]:
  FX[2] := Y[2]:
#
# X has dot support
#
  if type(Y[2][1], range) then
    Range := Y[2][1]:
    lo := lhs(Range):
    hi := rhs(Range):
    if member(Y[3][2], {"PDF", "CDF", "SF", "HF", "CHF"}) then
      incr := Y[2][2]:
      transf := Y[2][3]:
#
#  Report the support of new random variable back to the user in its
#  simplest form
#
      if (incr = 1 and unapply(transf(x))(x) = x) then
        FX[2] := [Range]:
      elif (not(incr = 1) and unapply(transf(x))(x) = x) then
        FX[2] := [Range, incr]:
      elif (incr = 1 and not(unapply(transf(x))(x) = x)) then
        FX[2] := [Range, Y[2][3]]:
      else 
        FX[2] := [Range, incr, Y[2][3]]:
      fi:
    fi:
#
#  APPL is not programmed to convert to a CDF format when the increment
#  is not 1 and/or the transformation is not x -> x
#
#      elif not(incr = 1 or unapply(transf(x))(x) = x) then
#        print(`ERROR(CDF): APPL is currently unable to evaluate`):
#        print(`this RV`):
#        return:
#      fi:
#    fi:
#
#  If X is given in its PDF or SF form
#
    if member(Y[3][2], {"PDF", "SF"}) then
      fX := PDF(X):
      FX[1] := [unapply(simplify(sum(op(unapply(fX[1](w))(w)), 
          w = lo .. x)), x)]:
#
#  If X is given in its CDF form, then nothing needs to be done to X.
#
    elif (Y[3][2] = "CDF") then 
#
#  The RV X is given in its HF form
#
    elif (Y[3][2] = "HF") then
      hf := unapply(op(Y[1])(w))(w):
      # assume(x < hi):
      sf := simplify(product(1 - hf, w = lo .. (x - 1))):
      # print(sf):
      FX[1] := [unapply(simplify(1 - sf), x)]:
      # SX[1] := [unapply(product(1 - hf, w = lo .. (x - 1)), x)]:
      # print(SX[1]):
      # SX := [SX[1], Y[2], ["Discrete", "SF"]]:
      # fX := PDF(SX):
      # FX[1] := [unapply(simplify(sum(op(unapply(fX[1](w))(w)), 
      #     w = lo .. x)), x)]:
#
#  If X is given in its CHF form
#
    elif (Y[3][2] = "CHF") then
      chf := unapply(op(Y[1])(x))(x):
      sf := exp(-chf):
      pdf := simplify(subs(x = w, sf) - subs(x = w + 1, sf)):
      FX[1] := [unapply(simplify(sum(pdf, w = lo .. x)), x)]:
#
#  If X is given in its IDF form
#
    elif (Y[3][2] = "IDF") then
      # need to look for a ceil function here!
      idf := unapply(op(Y[1])(y))(y):
      # print(`idf is`, idf):
      # print(`[op(idf)] is`, [op(idf)]):
      pieces := [op(idf)]:
      numops := nops(pieces):
      # print(numops):
      noceil := true:
      for i from 1 to numops while noceil do
        if has(pieces, ceil) then
          # print(`has ceil`):
          noceil := false:
          ceilpiece := i:
        fi:
      od:
      if not(noceil) then
        # print(pieces[ceilpiece]):
        pieces[ceilpiece] := op(pieces[ceilpiece]):
        idf := sum(pieces[k], k = 1 .. numops):
      fi:
      solns := [solve(idf = x, y)]:
      # print(solns):
      nsolns := nops(solns):
      # Find the correct inverse
      if (nsolns = 1) then 
        # If there is only one inverse, assign it to cdf.
        cdf := solns[1]:
      else
        if lo = -infinity then
          if hi = infinity then
            val := 0:
          else 
            val := hi:
          fi: 
        else
          val := lo:  
        fi:   
        # print(`val is`, val):
        invfound := false:
        for j from 1 to nsolns do 
          # Evaluate each inverse of the IDF at the value "val" assigned
          # above. If CDF(IDF(val)) = val, then assign idf equal to that
          # inverse. 
          idfval := subs(x = val, idf):
          if evalf(subs(x = idfval, solns[j])) = evalf(val) then
            cdf := solns[j]:
            invfound := true:
            break:
          fi: 
        od:
        if not(invfound) then       
          print(`ERROR(CDF): Could not find the appropriate inverse`):
        fi:  
      fi:
      FX[1] := [unapply(cdf, x)]:
#  CAUTION: losupp is incorrect in some cases -- currently don't know
#  how to fix this, need to be able to retrieve the first cdf value and
#  sub it into idf as lo
      losupp := evalf(subs(y = lo, idf)):
      hisupp := evalf(subs(y = hi, idf)): 
      FX[2] := [losupp .. hisupp]:
    fi:
#
#  X has no dot support
#
  else
    sublist1 := Y[1]:
    n := nops(sublist1):
#
#  If X is given in its PDF, HF, or CHF form
#
    if member(Y[3][2], {"PDF", "HF", "CHF"}) then
      fX := PDF(Y):
      # print(fX):
      FX[1][n] := 1:
      for i from n - 1 to 1 by -1 do 
        FX[1][i] :=  FX[1][i + 1] - fX[1][i + 1]:
      od:
#
#  If X is given in its CDF form, then nothing needs to be done to X.
#
    elif (Y[3][2] = "CDF") then
#
#  If X is given in its SF form
#
    elif (Y[3][2] = "SF") then 
      for i from 1 to n - 1 do
        FX[1][i] := 1 - sublist1[i + 1]:
      od:
      FX[1][n] := 1:
#
#  If X is given in its IDF form
#
    elif (Y[3][2] = "IDF") then
      IDX2 := Y[1]:
      FX[1] := FX[2]:
      FX[2] := IDX2:
    fi:
  fi:
#
#  Only 1 argument, X, given for the procedure
#
  if (nargs = 1) then
    return([FX[1], FX[2], ["Discrete", "CDF"]]):
#
#  Two arguments, X and x, provided for the procedure
#
  elif (nargs = 2) then
    if type(Y[2][1], range) then
      if (evalf(st) < lo) then
        prob := 0:
      elif (evalf(st) >= hi) then
        prob := 1:
      else
        cdf := op(unapply(FX[1](w))(w)):
        cdf := subs(w = floor(x), cdf):
        # prob := op(FX[1](st)): 
        # need an evalf to get a float value with floor or ceil
        prob := evalf(subs(x = st, cdf)):
      fi:
    else
      # print(`FX[2][n] is`, FX[2][n]):
      if (evalf(st) < FX[2][1]) then
        prob := 0:
      elif (evalf(st) >= FX[2][n]) then
        prob := 1:
      else
        prob := 0:
        notfound := true:
        count := 1:
        # print(`n is`, n):
        for k from 1 to n - 1 while notfound do
          if (evalf(st) < evalf(FX[2][k + 1])) and 
             (evalf(st) >= evalf(FX[2][k]))   then
            # print(`st is`, st):
            notfound := false:
            prob := FX[1][k]: 
            # print(`prob for k`, k):
            # print(prob):
          fi:
          count := count + 1:
        od:
      fi:
    fi:
    return(prob):
  fi:
#
#  X is neither continuous nor discrete
#
else
  print(`ERROR(CDF): The random variable X must be continuous or`):
  print(`discrete`):
fi:
end: #1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: chf6.map
#
#  Procedure Name: CHF(X, [x])
#
#  Other APPL Procedures Called: HF, Convert, SF
#
#  Date: March 20, 2001
#
#  Purpose: CHF is a procedure that:
#          (1) Returns the cumulative hazard function of a distribution
#              in the APPL list of 3 sublists form if given only the one
#              argument X, or
#          (2) Returns the value -log(1 - Pr(X <= x)) if it is given the
#              optional argument x in addition to the RV X
#
#  Arguments: X: A continuous or discrete random variable; 
#             x (optional argument): A numeric value entered when
#                trying to determine -log(1 - Pr(X <= x))
#
#  Algorithm: 1. Perform error checking on user entered arguments
#             2. The CHF of X is determined by sending it to its 
#                appropriate category, which is based on whether:
#                A. X is continuous or discrete
#                B. X is entered in its PDF, CDF, SF, HF, CHF, or IDF
#                   format 
#             3. If only 1 argument (the random variable X) is entered
#                by the user, return the cumulative hazard function of 
#                X in the APPL list of 3 lists format 
#             4. If 2 arguments are provided, return the value 
#                -log(1 - Pr(X <= x))
#
CHF := proc(X :: list(list), st)
local numlists, nsegments, hX, supp, CHX, HCUM, i, HHX, prob, Y, Range,
    lo, hi, incr, transf, SX, sf, chf, hf, idf, pieces, numops,
    noceil, ceilpiece, solns, nsolns, cdf, val, invfound, j, idfval,
    pdf, losupp, hisupp, sublist1, n, notfound, count, k:
#
#  Check for the appropriate number of arguments
#
if ((nargs <> 1) and (nargs <> 2)) then
  print(`ERROR(CHF): This procedure requires 1 or 2 arguments:`):
  print(`A random variable X and an optional argument x for`):
  print(`computing -log(1 - Pr(X <= x))`):
  return:
fi:
#
#  Check that the RV X is in the list of 3 sublists format
#
numlists := nops(X):
if (numlists <> 3) then
  print(`ERROR(CHF): The RV X must be a list of 3 lists`):
  return:
fi:
#
#  Make sure X is given as a PDF, CDF, SF, HF, CHF, or IDF
#
if not(member(X[3][2], {"PDF", "CDF", "SF", "HF", "CHF", "IDF"})) then
  print(`ERROR(CHF): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
#
#  If the RV X is continuous, find and return the CHF of X
#
if (X[3][1] = "Continuous") then
  nsegments := nops(X[1]):
  if (X[3][2] = "HF") then
    hX := X:
  else
    hX := HF(X):
  fi:
  supp := hX[2]:
  CHX := []:
  HCUM := 0:
  for i from 1 to nsegments do 
    HHX := unapply(HCUM + int(hX[1][i](index), 
        index = hX[2][i] .. x), x):
    if (i < nsegments) then 
      HCUM := HHX(hX[2][i + 1]):
    fi:
    CHX := [op(CHX), op([unapply(simplify(HHX(x)), x)])]: 
  od:
#
#  Only 1 argument, X, given for the procedure
#
  if (nargs = 1) then
    return([CHX, supp, ["Continuous", "CHF"]]):
#
#  Two arguments, X and x, provided for the procedure
#
  elif (nargs = 2) then
    if not(type(evalf(st), {numeric, infinity})) then
      if nsegments = 1 then
        prob := CHX[1](st):
        return(prob):
      else
        print(`ERROR(CHF): Symbolic second arguments with a piecewise`):
        print(`CHF are not allowable in APPL at this time`):
        return:
      fi:    
    fi:
    for i from 1 to nsegments do 
      if ((evalf(st) >= evalf(supp[i])) and (evalf(st) < 
          evalf(supp[i + 1]))) then
        break:
      fi:
    od:
    prob := CHX[i](st):
    return(prob):
  fi:
#
#  The RV X is a discrete random variable
#
elif (X[3][1] = "Discrete") then
#
#  If the RV X is discrete, then call the procedure Convert(X) to
#  convert the discrete random variable's support to a standard APPL
#  discrete RV support format. Assign the converted random variable
#  to the Maple variable Y.
#
  Y := Convert(X):
  CHX[1] := Y[1]:
  CHX[2] := Y[2]:
#
# X has dot support
#
  if type(Y[2][1], range) then
    Range := Y[2][1]:
    lo := lhs(Range):
    hi := rhs(Range):
    if member(Y[3][2], {"PDF", "CDF", "SF", "HF", "CHF"}) then
      incr := Y[2][2]:
      transf := Y[2][3]:
#
#  Report the support of new random variable back to the user in its
#  simplest form
#
      if (incr = 1 and unapply(transf(x))(x) = x) then
        CHX[2] := [Range]:
#
#  APPL is not programmed to convert to a PDF format when the increment
#  is not 1 and/or the transformation is not x -> x
#
      elif not(incr = 1 or unapply(transf(x))(x) = x) then
        print(`ERROR(CHF): APPL is currently unable to evaluate`):
        print(`this RV`):
        return:
      fi:
    fi:
#
#  X is given in its PDF, CDF, or SF form
#
    if member(Y[3][2], {"PDF", "CDF", "SF"}) then
      SX := SF(Y):
      sf := unapply(op(SX[1])(x))(x):
      chf := -log(sf):
      CHX[1] := [unapply(chf, x)]:
#
#  X is given in its HF form
#
    elif (Y[3][2] = "HF") then
      hf := unapply(op(Y[1])(w))(w):
      SX[1] := [unapply(product(1 - hf, w = lo .. (x - 1)), x)]:
      sf := unapply(op(SX[1])(x))(x):
      chf := -log(sf):
      CHX[1] := [unapply(chf, x)]:
#
#  If X is given in its CHF form, then nothing needs to be done to X.
#
    elif (Y[3][2] = "CHF") then
#
#  X is given in its IDF form
#
    elif (Y[3][2] = "IDF") then
      # need to look for a ceil function here!
      idf := unapply(op(Y[1])(y))(y):
      # print(`idf is`, idf):
      pieces := [op(idf)]:
      numops := nops(pieces):
      # print(numops):
      noceil := true:
      for i from 1 to numops while noceil do
        if has(pieces, ceil) then
          # print(`has ceil`):
          noceil := false:
          ceilpiece := i:
        fi:
      od:
      if not(noceil) then
        # print(pieces[ceilpiece]):
        pieces[ceilpiece] := op(pieces[ceilpiece]):
        idf := sum(pieces[k], k = 1 .. numops):
      fi:
      solns := [solve(idf = x, y)]:
      # print(solns):
      nsolns := nops(solns):
      # Find the correct inverse
      if (nsolns = 1) then 
        # If there is only one inverse, assign it to cdf.
        cdf := solns[1]:
      else
        if lo = -infinity then
          if hi = infinity then
            val := 0:
          else 
            val := hi:
          fi: 
        else
          val := lo:  
        fi:   
        # print(`val is`, val):
        invfound := false:
        for j from 1 to nsolns do 
          # Evaluate each inverse of the IDF at the value "val" assigned
          # above. If CDF(IDF(val)) = val, then assign idf equal to that
          # inverse. 
          idfval := subs(x = val, idf):
          if evalf(subs(x = idfval, solns[j])) = evalf(val) then
            cdf := solns[j]:
            invfound := true:
            break:
          fi: 
        od:
        if not(invfound) then       
          print(`ERROR(CHF): Could not find the appropriate inverse`):
        fi:  
      fi:
      pdf := simplify(subs(x = w, cdf) - subs(x = w - 1, cdf)):
      sf := 1 - sum(pdf, w = lo .. x - 1): 
      chf := -log(sf):
      CHX[1] := [unapply(chf, x)]:
#  CAUTION: losupp is incorrect in some cases -- currently don't know
#  how to fix this, need to be able to retrieve the first cdf value and
#  sub it into idf as lo
      losupp := evalf(subs(y = lo, idf)):
      hisupp := evalf(subs(y = hi, idf)): 
      CHX[2] := [losupp .. hisupp]:
    fi:
#
#  X has no dot support
#
  else
    sublist1 := Y[1]:
    n := nops(sublist1):
#
#  If X is given in its PDF, CDF, SF, or HF form, convert X to its HF
#  form.  Then compute its cumulative hazard function.
#
    if member(Y[3][2], {"PDF", "CDF", "SF", "HF"}) then
      hX := HF(Y):
      CHX[1][1] := 0:
      for i from 2 to n do
        CHX[1][i] := CHX[1][i - 1] - log(1 - hX[1][i - 1]):
      od:
#
#  If X is given in its CHF form, then nothing needs to be done to X.
#
    elif (Y[3][2] = "CHF") then
#
#  X is given in its IDF form
#
    elif (Y[3][2] = "IDF") then
      hX := HF(Y):
      CHX[1][1] := 0:
      for i from 2 to n do
        CHX[1][i] := Y[1][i - 1] - log(1 - hX[1][i - 1]):
      od:
      CHX[2] := hX[2]:
    fi:
  fi:
#
#  Only 1 argument, X, given for the procedure
#
  if (nargs = 1) then
    return([CHX[1], CHX[2], ["Discrete", "CHF"]]):
#
#  Two arguments, X and x, provided for the procedure
#
  elif (nargs = 2) then
    if type(Y[2][1], range) then
      prob := op(CHX[1](st)): 
    else
      prob := 0:
      notfound := true:
      count := 1:
      for k from 1 to n while notfound do
        if evalf(CHX[2][k]) = evalf(st) then
          notfound := false:
          prob := CHX[1][count]: 
        fi:
        count := count + 1:
      od:
    fi:
    return(prob):
  fi:
#
#  X is neither continuous nor discrete
else
  print(`ERROR(CHF): The random variable X must be continuous or`):
  print(`discrete`):
fi:
end: 
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: cleanup1.map
#
#  Procedure name: CleanUp(X)
#
#  Other APPL Procedures Called:
# 
#  Date: August 8, 2000
#
#  NEED TO WORK ON COMMENTS AT A LATER TIME (6/28/2000)
#
#  Purpose: Clean up the list of sublists data structure
#
#  Arguments: X: Random variable
#
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#
CleanUp := proc(X :: list(list))
local fX, nsegs, i:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 1) then
  print(`ERROR(CleanUp): This procedure requires 1 argument`):
  RETURN():
fi:

fX := X:
nsegs := nops(fX[1]):
#
#  Construct the list y
#
for i from 1 to (nsegs - 1) do
  # print(fX[1][i]):
  # print(unapply(fX[1][i](x))(x)):
  # print(evalb(fX[1][i] = fX[1][i + 1])):
  if evalb(fX[1][i] = fX[1][i + 1]) then
    fX[1] := [op(fX[1][1 .. i]), op(fX[1][i + 2 .. nsegs])]:
    fX[2] := [op(fX[2][1 .. i]), op(fX[2][i + 2 .. (nsegs + 1)])]:
  fi:
od:

RETURN(fX):
end:
#11111111112222222222333333333344444444445555555555666666666677777777778888#
#  Filename: coefofvar1.map
#
#  Procedure Name: CoefOfVar(X)
#
#  Other APPL Procedures Called: 
#
#  Updated: June 30, 2000
#
#  Purpose: Returns the 
#
#  Arguments: X: Random Variable
# 
#  Algorithm:
CoefOfVar := proc(X :: list(list))
local NumLists, fX, mu, sigma, cov:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 1) then
  print(`ERROR(CovOfVar): This procedure requires 1 argument:`):
  print(`A random variable`):
  RETURN():
fi:
#
#  Check that the RV X is in a list of 3 lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(Skewness): The RV X must be in a list of 3 lists format`):
  RETURN():
fi:
#
#  Convert X to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
    fX := X:
else
  if ((X[3][2] = "CDF") or
      (X[3][2] = "CHF") or
      (X[3][2] = "HF") or
      (X[3][2] = "IDF") or
      (X[3][2] = "SF")) then
    fX := PDF(X):
  else
    print(`ERROR(CoefOfVar): RV must be given as`):
    print(`CDF, CHF, HF, IDF, PDF, or SF`):
    RETURN():
  fi:
fi:

mu := Mean(fX):
# print(`mu is`, mu):
sigma := Variance(fX):
# print(`sigma is`, sigma):
cov := sqrt(sigma) / mu:
RETURN(cov):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#
#  NOTE (Jan. 21, 2000):  error checking parameters with statements
#  like lambda :: {symbol, positive} can have its problem, since 
#  lambda will not allowed to be entered as something like 3 ^ 2
#  (7/25/00) -- no longer a problem in Maple 6 (8/3/2000) -- Yes, still
#  a problem with some examples: WeibullRV(sqrt(Pi) / 6, 2.0)
#
#  7/25/00:
#  (1) if have thing :: {finite, symbol}, then infinity will make it
#      thru as thing since infinity is of type symbol, so thing ::
#      {finite, symbol} means that thing can either be of type finite OR
#      symbol
#
#  (2) added double quotes to "Continuous" and "PDF"
#
#  (3) made parameters global variables
#
#  (4) type(x, infinity) returns true if x is infinity or -infinity in
#      Maple 6
#
#  Filename: contdist2.map
#
#  Procedure names:
#             ArcSinRV
#             ArcTanRV
#             BetaRV
#             CauchyRV
#             ChiRV
#             ChiSquareRV
#             DoublyNoncentralFRV
#             DoublyNoncentralTRV
#             ErlangRV
#             ErrorRV
#             ExponentialRV
#             ExponentialPowerRV
#             ExtremeValueRV
#             FRV
#             GammaRV
#             GeneralizedParetoRV
#             GompertzRV
#             HyperbolicSecantRV
#             HyperExponentialRV
#             HypoExponentialRV
#             IDBRV
#             InverseGaussianRV
#             InvertedGammaRV
#             KSRV
#             LaPlaceRV
#             LogGammaRV
#             LogisticRV
#             LogLogisticRV
#             LogNormalRV
#             LomaxRV
#             MakehamRV
#             MuthRV
#             NoncentralChiSquareRV
#             NoncentralFRV
#             NoncentralTRV
#             NormalRV
#             ParetoRV
#             RayleighRV
#             StandardCauchyRV
#             StandardNormalRV
#             StandardTriangularRV
#             StandardUniformRV
#             TRV
#             TriangularRV
#             UniformRV
#             WeibullRV
#
#  Other APPL Procedures Called: HypoExponentialRV calls 
#                                ExponentialRV and Convolution
#
#  Date:  July 25, 2000
#  Stopped making changes at Inverse Gaussian ... 
#  pick up there in the future
#  Re-examine Hypo and Hyperexponential in the future
#
#  Purpose:  Define the common parametric continuous univariate
#            probability distributions shown below:
#
#  Distribution      Support        Parameters     ParameterRestrictions    
#  ------------      -------        ----------     ---------------------
#  ArcSin            0 < x < 1      none
#  ArcTan            x >= 0         alpha, phi     alpha > 0; 
#                                                  -inf < phi < inf
#  Beta              0 <= x <= 1    Shape alpha,   alpha > 0; beta > 0
#                                   shape beta
#  Cauchy            -inf < x < inf Location a,    -inf < a < inf; 
#                                   Scale alpha    alpha > 0 
#  Chi               x >= 0         Shape n        positive integer n
#  ChiSquare         x >= 0         Shape n        positive integer n
#  DblyNoncentralF
#  DblyNoncentralT
#  Erlang            x >= 0         Scale lambda,  lambda > 0
#                                   shape n        positive integer n
#  Error             -inf < x < inf mu, alpha,     mu > 0; alpha >= 1;
#                                   location d     -inf < d < inf
#  Exponential       x >= 0         Scale lambda   lambda > 0
#  Exponent Pwr      x >= 0         Scale lambda,  lambda > 0; kappa > 0
#                                   shape kappa
#  ExtremeValue      -inf < x < inf Scale ? alpha, alpha > 0; beta > 0
#                                   shape ? beta
#  F                 x >= 0         Shape n1,      positive ints n1, n2
#                                   shape n2
#  Gamma             x >= 0         Scale lambda,  lambda > 0; kappa > 0
#                                   shape kappa
#  GenPareto         x >= 0         gamma, delta,  kappa
#  Gompertz          x >= 0         Shape delta,   delta > 0; kappa > 1
#                                   shape kappa
#  HyperbolicSecant  -inf < x < inf none
#  HyperExponential  x >= 0         list p, list l all elts of list p: 
#                                                  0 <= p <= 1
#                                                  all elts of list l:
#                                                  l > 0
#  HypoExponential   x >= 0         list l         all elts of list l:
#                                                  l > 0
#  IDB               x >= 0         Shape gamma,   gamma, delta >= 0, 
#                                   delta, kappa   kappa >= 0
#  InverseGaussian   x > 0          Scale lambda,  lambda > 0; mu > 0
#                                   location mu
#  InvertedGamma     x >= 0         alpha, beta    alpha > 0; beta > 0
#  KS
#  LaPlace           -inf < x < inf omega, theta   omega > 0
#  LogGamma          -inf < x < inf alpha, beta    alpha > 0; beta > 0
#  Logistic          -inf < x < inf Scale kappa    kappa > 0; lambda > 0
#                                   shape (?) lambda
#  Log logistic      x >= 0         Scale lambda,  lambda > 0; kappa > 0
#                                   shape kappa
#  LogNormal         x >= 0         Scale mu,      -inf < mu < inf; 
#                                   shape sigma    sigma > 0
#  Lomax             x > 0          kappa, lambda  kappa > 0; lambda > 0
#  Makeham           x >= 0         Shape gamma,   gamma, delta > 0;
#                                   delta, kappa   kappa > 1
#  Muth              x >= 0         Shape kappa    0 < kappa <= 1
#  NoncentralChiSqre 0 <= x <= 1
#  NoncentralF       0 <= x <= 1
#  NoncentralT       0 <= x <= 1
#  Normal            -inf < x < inf Location mu,   -inf < mu < inf;
#                                   scale sigma    sigma > 0
#  Pareto            x >= lambda    Location lambda,  
#                                   shape kappa    lambda > 0; kappa > 0
#  Rayleigh          x > 0          Scale lambda   lambda > 0
#  StandardCauchy    -inf < x < inf none
#  StandardNormal    -inf < x < inf none
#  StandardTriangular0 <= x <= 1    m              0 <= m <= 1
#  StandardUniform   0 <= x <= 1    none
#  T                 -inf < x < inf Shape n        positive integer n
#  Triangular        a <= x <= b    Min a, mode m, a < m < b
#                                   max b
#  Uniform           a <= x <= b    Min a, max b   -inf < a < b < inf
#  Weibull           x >= 0         Scale lambda,  lambda > 0; kappa > 0
#                                   shape kappa
#
#  Arguments:  The parameters of the distribution of the random variable
#
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Check parameter space when parameters are numeric
#    3.  Check to see that the parameters are finite
#    4.  Make assumptions about any symbolic parameters
#    5.  Assign a list of lists in the following format:
#        [[f(x)], [support], ["Continuous", "XXX"]]
#        where XXX is one of the following:  PDF, CDF, IDF, SF, HF, CHF
#    6.  Return the list of lists
#                                                                               
#print(`CONTINUOUS DISTRIBUTIONS:`):
# `DoublyNoncentralFRV()`, `DoublyNoncentralTRV()`, 
# `NoncentralChiSquareRV()`, `NoncentralFRV()`, `NoncentralTRV()`,
#print(`ArcSinRV()`, `ArcTanRV(alpha, phi)`, `BetaRV(alpha, beta)`,

print(`ArcSinRV()`, `ArcTanRV(alpha, phi)`, `BetaRV(alpha, beta)`,
    `CauchyRV(a, alpha)`, `ChiRV(n)`, `ChiSquareRV(n)`,
    `ErlangRV(lambda, n)`, `ErrorRV(mu, alpha, d)`, 
    `ExponentialRV(lambda)`, `ExponentialPowerRV(lambda, kappa)`, 
    `ExtremeValueRV(alpha, beta)`, `FRV(n1, n2)`, 
    `GammaRV(lambda, kappa)`, 
    `GeneralizedParetoRV(gamma, delta, kappa)`, 
    `GompertzRV(delta, kappa)`, 
    `HyperbolicSecantRV()`, `HyperExponentialRV(p, l)`,
    `HypoExponentialRV(l)`, `IDBRV(gamma, delta, kappa)`,
    `InverseGaussianRV(lambda, mu)`, `InvertedGammaRV(alpha, beta)`,
    `KSRV(n)`, `LaPlaceRV(omega, theta)`, `LogGammaRV(alpha, beta)`,
    `LogisticRV(kappa, lambda)`, `LogLogisticRV(lambda, kappa)`, 
    `LogNormalRV(mu, sigma)`, `LomaxRV(kappa, lambda)`, 
    `MakehamRV(gamma, delta, kappa)`, `MuthRV(kappa)`,  
    `NormalRV(mu, sigma)`, `ParetoRV(lambda, kappa)`, 
    `RayleighRV(lambda)`, `StandardCauchyRV()`, `StandardNormalRV()`,
    `StandardTriangularRV(m)`, `StandardUniformRV()`, `TRV(n)`,
    `TriangularRV(a, m, b)`, `UniformRV(a, b)`, 
    `WeibullRV(lambda, kappa)`):
print(``):
#
#  ArcSin distribution (special case of beta with both parameters 1 / 2)
#
ArcSinRV := proc()
local ListOfLists, x:
if (nargs <> 0) then
  print(`ERROR(ArcSinRV): This procedure requires no arguments`):
  RETURN():
fi:
ListOfLists := [[unapply(1 / (Pi * sqrt(x * (1 - x))), x)], [0, 1], 
    ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  ArcTan distribution
#
ArcTanRV := proc(alpha :: {positive, symbol}, phi :: {numeric,
    symbol})
local ListOfLists, x:
global alpha1, phi1:
alpha1 := alpha:
phi1 := phi:
if (nargs <> 2) then
  print(`ERROR(ArcTanRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (type(alpha1, infinity) or type(phi1, infinity)) then
  print(`ERROR(ArcTanRV): Both parameters must be finite`):
  RETURN():
fi:
if type(alpha1, symbol) then
  assume(alpha1, positive):
  about(alpha1):
fi:
if type(phi1, symbol) then
  assume(phi1, numeric):
fi:
ListOfLists := [[unapply(alpha1 / ((arctan(alpha1 * phi1) + Pi / 2) *
    (1 + alpha1 ^ 2 * (x - phi1) ^ 2)), x)],
    [0, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Beta distribution
#
BetaRV := proc(alpha :: {positive, symbol}, beta :: {positive, symbol})
local ListOfLists, x:
global alpha1, beta1:
alpha1 := alpha:
beta1 := beta:
if (nargs <> 2) then
  print(`ERROR(BetaRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (type(alpha1, infinity) or type(beta1, infinity)) then
  print(`ERROR(BetaRV): Both parameters must be finite`):
  RETURN():
fi:
if type(alpha1, symbol) then
  assume(alpha1, positive):
  about(alpha1):
fi:
if type(beta1, symbol) then
  assume(beta1, positive):
  about(beta1):
fi:
ListOfLists := [[unapply(GAMMA(alpha1 + beta1) * x ^ (alpha1 - 1) *
    (1 - x) ^ (beta1 - 1)/ (GAMMA(alpha1) * GAMMA(beta1)), x)],
    [0, 1], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Cauchy distribution
#
CauchyRV := proc(a :: {numeric, symbol}, alpha :: {positive, symbol})
local ListOfLists, x:
global a1, alpha1:
a1 := a:
alpha1 := alpha:
if (nargs <> 2) then
  print(`ERROR(CauchyRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (type(alpha1, infinity) or type(a1, infinity)) then
  print(`ERROR(CauchyRV): Both parameters must be finite`):
  RETURN():
fi:
if type(a1, symbol) then
  assume(a1, numeric):
fi:
if type(alpha1, symbol) then
  assume(alpha1, positive):
  about(alpha1):
fi:
ListOfLists := [[unapply(1 / (alpha1 * Pi * (1 + ((x - a1) / alpha1) ^
     2)), x)], [-infinity , infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Chi distribution
#
ChiRV := proc(n :: {posint, symbol})
local ListOfLists, x:
global n1:
n1 := n:
if (nargs <> 1) then
  print(`ERROR(ChiRV): This procedure requires 1 argument`):
  RETURN():
fi:
if type(n1, infinity) then
  print(`ERROR(ChiRV): The shape parameter must be finite`):
  RETURN():
fi:
if type(n1, symbol) then
  assume(n1, posint):
  about(n1):
fi:
ListOfLists := [[unapply(x ^ (n1 - 1) * exp(-x ^ 2 / 2) /
    (2 ^ (n1 / 2 - 1) * GAMMA(n1 / 2)), x)],
    [0, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  ChiSquare distribution (special case of gamma)
#
ChiSquareRV := proc(n :: {posint, symbol})
local ListOfLists, x:
global n1:
n1 := n:
if (nargs <> 1) then
  print(`ERROR(ChiSquareRV): This procedure requires 1 argument`):
  RETURN():
fi:
if type(n1, infinity) then
  print(`ERROR(ChiSquareRV): The shape parameter must be finite`):
  RETURN():
fi:
if type(n1, symbol) then
  assume(n1, posint):
  about(n1):
fi:
ListOfLists := [[unapply(x ^ (n1 / 2 - 1) * exp(-x / 2) /
    (2 ^ (n1 / 2) * GAMMA(n1 / 2)), x)],
    [0, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  DoublyNoncentralF
#
# NOTE: reference in Johnson, Kotz, Vol. 2, pg. 499:
#
# DoublyNoncentralFRV := proc()
# local ListOfLists, x:
# ListOfLists := [[unapply( , x)],
#                       [0, 1], ["Continuous", "PDF"]]:
#

#
#  DoublyNoncentralT
#
# NOTE: reference in Johnson, Kotz, Vol. 2, pg. 533
#
# DoublyNoncentralTRV := proc()
# local ListOfLists, x:
# ListOfLists := [[unapply( , x)],
#                       [0, 1], ["Continuous", "PDF"]]:
#

#
#  Erlang distribution
#
ErlangRV := proc(lambda :: {positive, symbol}, n :: {posint, symbol})
local ListOfLists, x:
global lambda1, n1:
lambda1 := lambda:
n1 := n:
if (nargs <> 2) then
  print(`ERROR(ErlangRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (type(lambda1, infinity) or type(n1, infinity)) then
  print(`ERROR(ErlangRV): Both parameters must be finite`):
  RETURN():
fi:
if type(lambda1, symbol) then
  assume(lambda1, positive):
  about(lambda1):
fi:
if type(n1, symbol) then
  assume(n1, posint):
  about(n1):
fi:
ListOfLists := [[unapply(lambda1 * (lambda1 * x) ^ (n1 - 1) * 
    exp(-lambda1 * x) / (n1 - 1)!, x)], [0, infinity], ["Continuous",
    "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Error distribution (exponential power, general error)
#
ErrorRV := proc(mu :: {positive, symbol}, alpha, d :: {numeric, symbol})
local ListOfLists, x:
global mu1, alpha1, d1:
mu1 := mu:
alpha1 := alpha:
d1 := d:
if (nargs <> 3) then
  print(`ERROR(ErrorRV): This procedure requires 3 arguments`):
  RETURN():
fi:
if is(alpha1 < 1) then
  print(`ERROR(ErrorRV): The parameter alpha must be >= 1`):
  RETURN():
fi:
if (type(mu1, infinity) or type(alpha1, infinity) or type(d1, infinity))
    then
  print(`ERROR(ErrorRV): Each parameter must be finite`):
  RETURN():
fi:
if type(mu1, symbol) then
  assume(mu1, positive):
  about(mu1):
fi:
if type(alpha1, symbol) then
  assume(alpha1, RealRange(1, infinity)):
  about(alpha1):
fi:
if type(d1, symbol) then
  assume(d1, numeric):
  about(d1):
fi:
ListOfLists := [[unapply(mu1 * exp(-abs(mu1 * (x - d1)) ^ alpha1) /
    (2 * GAMMA(1 + 1 / alpha1)), x)],
    [-infinity, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  ErrorII distribution (exponential power, general error)
#
ErrorIIRV := proc(a, b :: {nonneg, symbol}, c :: {nonneg, symbol})
local ListOfLists, x:
global a1, b1, c1:
a1 := a:
b1 := b:
c1 := c:
if (nargs <> 3) then
  print(`ERROR(ErrorIIRV): This procedure requires 3 arguments`):
  RETURN():
fi:
if (type(a1, infinity) or type(b1, infinity) or type(c1, infinity)) then
  print(`ERROR(ErorIIRV): Each parameter must be finite`):
  RETURN():
fi:
if type(b1, symbol) then
  assume(b1, nonneg):
  about(b1):
fi:
if type(c1, symbol) then
  assume(c1, nonneg):
  about(c1):
fi:
ListOfLists := [[unapply(exp(-((abs(x - a1)) ^ (2 / c1))/(2 * b1)) /
    ((b1 ^ (c1 / 2))* 2 ^ (c1 / 2 + 1) * GAMMA(c1 / 2 + 1)), x)],
    [-infinity, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Exponential distribution
#
ExponentialRV := proc(lambda)
local ListOfLists, x:
global lambda1:
lambda1 := lambda:
if (nargs <> 1) then
  print(`ERROR(ExponentialRV): This procedure requires 1 argument`):
  RETURN():
fi:
if (is(lambda <= 0)) then
  print(`ERROR(ExponentialRV): Lambda must be positive`):
  RETURN():
fi:
if type(lambda1, infinity) then
  print(`ERROR(ExponentialRV): The scale parameter must be finite`):
  RETURN():
fi:
if type(lambda1, symbol) then
  assume(lambda1, positive):
  about(lambda1):
fi:
ListOfLists := [[unapply(lambda1 * exp(-lambda1 * x), x)], [0, infinity],
    ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Exponential power distribution
#
ExponentialPowerRV := proc(lambda :: {positive, symbol}, kappa ::
    {positive, symbol})
local x,  ListOfLists:
global lambda1, kappa1:
lambda1 := lambda:
kappa1 := kappa:
if (nargs <> 2) then
  print(`ERROR(ExponentialPowerRV): This procedure requires 2`): 
  print(`arguments`):
  RETURN():
fi:
if (type(lambda1, infinity) or type(kappa1, infinity)) then
  print(`ERROR(ExponentialPowerRV): Both parameters must be finite`):
  RETURN():
fi:
if type(lambda1, symbol) then
  assume(lambda1, positive):
  about(lambda1):
fi:
if type(kappa, symbol) then
  assume(kappa1, positive):
  about(kappa1):
fi:
ListOfLists := [[unapply(exp(1 - exp(lambda1 * x ^ kappa1)) * exp(lambda1 
    * x ^ kappa1) * lambda1 * kappa1 * x ^ (kappa1 - 1) , x)],
    [0, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  ExtremeValue distribution (Gumbel)
#
ExtremeValueRV := proc(alpha :: {positive, symbol}, beta :: {positive, symbol})
local ListOfLists, x:
global alpha1, beta1:
alpha1:=alpha:
beta1:=beta:
if (nargs <> 2) then
  print(`ERROR(ExtremeValueRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (type(alpha1, infinity) or type(beta1, infinity)) then 
  print(`ERROR(ExtremeValueRV): Both parameters must be finite`):
  RETURN():
fi:
if type(alpha1, symbol) then
  assume(alpha1, positive):
fi:
if type(beta1, symbol) then
  assume(beta1, positive):
fi:
ListOfLists := [[unapply(beta1 * exp(x * beta1 - exp(x * beta1) / alpha1) /alpha1, x)],
    [-infinity, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  F (variance ratio, Fisher-Snedecor):
#
FRV := proc(n1 :: {posint, symbol}, n2 :: {posint, symbol})
local ListOfLists, x:
global n, m:
n := n1:
m := n2:
if (nargs <> 2) then
  print(`ERROR(FRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (type(n, infinity) or type(m, infinity)) then
  print(`ERROR(FRV): The shape parameters must be finite`):
  RETURN():
fi:
if type(n, symbol) then
  assume(n, posint):
  about(n):
fi:
if type(m, symbol) then
  assume(m, posint):
  about(m):
fi:
ListOfLists := [[unapply((GAMMA((n + m) / 2) * (n / m) ^ (n / 2) *
    x ^ ( n / 2 - 1))/ (GAMMA(n / 2 ) * GAMMA(m / 2) * ((n / m) * x  + 1)
    ^ ((n + m) / 2) ), x)], [0, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Gamma distribution
#
GammaRV := proc(lambda :: {positive, symbol}, kappa :: {positive,
    symbol})
local x, ListOfLists:
global lambda1, kappa1:
lambda1 := lambda:
kappa1 := kappa:
if (nargs <> 2) then
  print(`ERROR(GammaRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (type(lambda1, infinity) or type(kappa1, infinity)) then
  print(`ERROR(GammaRV): Both parameters must be finite`):
  RETURN():
fi:
if type(lambda1, symbol) then
  assume(lambda1, positive):
  about(lambda1):
fi:
if type(kappa1, symbol) then
  assume(kappa1, positive):
  about(kappa1):
fi:
ListOfLists := [[unapply(lambda1 * (lambda1 * x) ^ (kappa1 - 1) * 
    exp(-lambda1 * x) /GAMMA(kappa1), x)], [0, infinity], ["Continuous",
    "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Generalized Pareto distribution
#
GeneralizedParetoRV := proc(gamma :: {positive, symbol}, delta ::  
    {positive, symbol}, kappa)
local x, ListOfLists:
global gamma1, delta1, kappa1:
gamma1 := gamma:
delta1 := delta:
kappa1 := kappa:
if (nargs <> 3) then
  print(`ERROR(GeneralizedParetoRV): This procedure requires 3`):
  print(`arguments`):
  RETURN():
fi:
if is(kappa1 < -delta1 * gamma1) then
  print(`ERROR(GeneralizedParetoRV): Parameter space violation`):
  print(`Need kappa >= -delta * gamma`):
  RETURN():
fi:
if (type(gamma1, infinity) or type(delta1, infinity) or type(kappa1,  
    infinity)) then
  print(`ERROR(GeneralizedParetoRV): Each parameter must be finite`):
  RETURN():
fi:
if type(delta1, symbol) then
  assume(delta1, positive):
  about(delta1):
fi:
if type(gamma1, symbol) then
  assume(gamma1, positive):
  about(gamma1):
fi:
ListOfLists := [[unapply((gamma1 + kappa1 / (x + delta1)) * (1 + x /
    delta1) ^ (-kappa1) * exp(-gamma1 * x), x)], [0, infinity],
    ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Gompertz distribution
#
GompertzRV := proc(delta :: {positive, symbol}, kappa)
local x, ListOfLists:
global delta1, kappa1:
delta1 := delta:
kappa1 := kappa:
if (nargs <> 2) then
  print(`ERROR(GompertzRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if is(kappa1 <= 1) then
  print(`ERROR(GompertzRV): The parameter kappa must be > 1`):
  RETURN():
fi:
if (type(delta1, infinity) or type(kappa1, infinity)) then
  print(`ERROR(GompertzRV): Each paramter must be finite`):
  RETURN():
fi:
if type(delta1, symbol) then
  assume(delta1, positive):
  about(delta1):
fi:
if type(kappa1, symbol) then
  assume(kappa1, RealRange(Open(1), infinity)):
fi:
ListOfLists := [[unapply(delta1 * kappa1 ^ x * exp(-delta1 * (kappa1 ^ 
    x - 1) / log(kappa1)), x)], [0, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  HyperbolicSecant
#
HyperbolicSecantRV := proc()
local ListOfLists, x:
if (nargs <> 0) then
  print(`ERROR(HyperbolicSecantRV): This procedure requires no`):
  print(`arguments`):
  RETURN():
fi:
ListOfLists := [[unapply(sech(Pi * x) , x)], [-infinity, infinity],
    ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  HyperExponential (n parameter distribution related to the
#  exponential: it is a mixture of n Exponential RV's)
#
#  The parameter p is a finite list of probablities (or mixture
#  "weights")
#  p := [p1, p2, ... , pn]:
#  The parameter l is a finite list of values for lambda1, lambda2, ... 
#  l := [lambda1, lambda2, ... , lambdan]:
#
HyperExponentialRV := proc(p :: {list}, l :: {list})
local ListOfLists, x, lengthp, lengthl, count, SumOfListp, 
    RationalSumOfListp, PDF:
lengthp := nops(p):
lengthl := nops(l):
if (nargs <> 2) then
  print(`ERROR(HyperExponentialRV): This procedure requires 2 list`):
  print(`arguments`):
  RETURN():
fi:
if (lengthp <> lengthl) then
  print(`ERROR(HyperExponentialRV): Size of lists p and l must be the`):
  print(`same`):
  RETURN():
fi:
if (evalf(lengthp) = infinity or evalf(lengthl) = infinity) then
  print(`ERROR(HyperExponentialRV): There must be a finite number of`):
  print(`elements in lists p and l`):
  RETURN():
fi:
for count from 1 to lengthp do
  if (is(p[count] <= 0)) then
    print(`ERROR(HyperExponentialRV): Each parameter in the list p`):
    print(`must be positive`):
    RETURN():
  fi:
od:
for count from 1 to lengthp do
  if (is(p[count] >= 1)) then
    print(`ERROR(HyperExponentialRV): Each parameter in list p must be`):
    print(`less than or equal to 1`):
    RETURN():
  fi:
od:
SumOfListp := sum(p[j], j = 1 .. lengthp):
RationalSumOfListp := convert(SumOfListp, rational):
if (RationalSumOfListp <> 1) then
  print(`ERROR(HyperExponentialRV): The parameters in list p must`):
  print(`sum to 1`):
  RETURN():
fi:
for count from 1 to lengthl do 
  if (is(l[count] <= 0)) then
    print(`ERROR(HyperExponentialRV): Each parameter in the list l`):
    print(`must be positive`):
    RETURN():
  fi:
od:
for count from 1 to lengthl do 
  if (evalf(l[count]) = infinity or evalf(l[count]) = -infinity or
      evalf(p[count]) = infinity or evalf(p[count]) = -infinity) then
    print(`ERROR(HyperExponentialRV): Each parameter in lists l and p`):
    print(`must be finite`):
    RETURN():
  fi:
od:
for count from 1 to lengthp do
  if type(p[count], symbol) then
    assume(p[count] >= 0):
    assume(p[count] <= 1):
  fi:
od:
for count from 1 to lengthl do
  if type(l[count], symbol) then
    assume(l[count] > 0):
  fi:
od:
PDF := sum(p[j] * l[j] * exp(-l[j] * x), j = 1 .. lengthp):
ListOfLists := [[unapply(PDF, x)],[0, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  HypoExponential  (n parameter distribution related to the exponential)
#
#  The parameter l is a finite list of values:
#  l := [lambda1, lambda2, ... , lambdan]:
#  NOTE TO LARRY: I'm using Convolution and ExponentialRV for now
#
HypoExponentialRV := proc(l)
local ListOfLists, x, lengthl, j, i, fsum:
lengthl := nops(l):
if (nargs <> 1) then
  print(`ERROR(HypoExponentialRV): This procedure requires 1 list`):
  print(`argument`):
  RETURN():
fi:
if (evalf(lengthl) = infinity) then
  print(`ERROR(HypoExponentialRV): There must be a finite number of`):
  print(`elements in list l`):
  RETURN():
fi:
for j from 1 to lengthl do
  if (is(l[j] <= 0)) then
    print(`ERROR(HypoExponentialRV): Each parameter in the list l must`):
    print(`be positive`):
    RETURN():
  fi:
od:
for j from 1 to lengthl do
  if (evalf(l[j]) = infinity or evalf(l[j]) = -infinity) then
    print(`ERROR(HypoExponentialRV): Each parameter in list l must be`):
    print(`finite`):
    RETURN():
  fi:
od:
for j from 1 to lengthl do
  if type(l[j], symbol) then
    assume(l[j] > 0):
  fi:
od:
if (is(lengthl = 1)) then
  ListOfLists := [[unapply(l[1] * exp(-l[1] * x) , x)],
    [0, infinity], ["Continuous", "PDF"]]:
  RETURN(ListOfLists):
fi:
if (is(lengthl >= 2)) then
  fsum := Convolution(ExponentialRV(l[1]),ExponentialRV(l[2])):
  if (is(lengthl > 2)) then
    for i from 3 to lengthl do
      fsum := Convolution(ExponentialRV(l[i]), fsum):
    od:
  fi:
  RETURN(fsum):
fi:
end:

#
#  IDB distribution
#
IDBRV := proc(gamma :: {nonneg, symbol}, delta :: {nonneg, symbol}, 
    kappa :: {nonneg, symbol})
local x, ListOfLists:
global gamma1, delta1, kappa1:
gamma1 := gamma:
delta1 := delta:
kappa1 := kappa:
if (nargs <> 3) then
  print(`ERROR(IDBRV): This procedure requires 3 arguments`):
  RETURN():
fi:
if (type(gamma1, infinity) or type(delta1, infinity) or type(kappa1,
    infinity)) then
  print(`ERROR(IDBRV): Each parameter must be finite`):
  RETURN():
fi:
if type(gamma1, symbol) then
  assume(gamma1, nonneg):
  about(gamma1):
fi:
if type(delta1, symbol) then
  assume(delta1, nonneg):
  about(delta1):
fi:
if type(kappa1, symbol) then
  assume(kappa1, nonneg):
  about(kappa1):
fi:
ListOfLists := [[unapply(1 - (1 + kappa1 * x) ^ (-gamma1 / kappa1) *
    exp(-delta1 * x ^ 2 / 2), x)], [0, infinity], ["Continuous", "CDF"]]:
#
#  The following code was deleted because there was difficulty
#  integrating the PDF (7/25/00 -- might be worth trying again with Maple
#  6)
#
#  ListOfLists := [[unapply(((1 + kappa * x) * delta * x + gamma) /
#     ((1 + kappa * x) ^ (gamma / kappa + 1)) * exp(- delta * x ^ 2 /
#      2), x)],
#     [0, infinity], ["Continuous", "PDF"]]:
#
RETURN(ListOfLists):
end:

#
#  Inverse Gaussian distribution
#
InverseGaussianRV := proc(lambda :: {positive, symbol}, mu :: {positive,
    symbol})
local x, ListOfLists:
global lambda1, mu1:
lambda1 := lambda:
mu1 := mu:
if (nargs <> 2) then
  print(`ERROR(InverseGaussianRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (is(lambda1 <= 0) or is(mu1 <= 0)) then
  print(`ERROR(InverseGaussianRV): Both parameters must be positive`):
  RETURN():
fi:
if (type(lambda1, infinity) or type(mu1, infinity)) then
  print(`ERROR(InverseGaussianRV): Both parameters must be finite`):
  RETURN():
fi:
if type(lambda1, symbol) then
  assume(lambda1, positive):
  about(lambda1):
fi:
if type(mu1, symbol) then
  assume(mu1, positive):
  about(mu1):
fi:
ListOfLists := [[unapply(sqrt(lambda1 / (2 * Pi * x ^ 3)) * 
    exp(-lambda1 *(x - mu1) ^ 2 / (2 * mu1 ^ 2 * x)), x)], 
    [0, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  InvertedGamma distribution
#
InvertedGammaRV := proc(alpha :: {positive, symbol}, beta :: {positive,
    symbol})
local ListOfLists, x:
global alpha1, beta1:
alpha1 := alpha:
beta1 := beta:
if (nargs <> 2) then
  print(`ERROR(InvertedGammaRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (is(alpha1 <= 0) or is(beta1 <= 0)) then
  print(`ERROR(InvertedGammaRV): Both parameters must be positive`):
  RETURN():
fi:
if (type(alpha1, infinity) or type(beta1, infinity)) then
  print(`ERROR(InvertedGammaRV): Both parameters must be finite`):
  RETURN():
fi:
if type(alpha1, symbol) then
  assume(alpha1 , positive):
  about(alpha1):
fi:
if type(beta1, symbol) then
  assume(beta1 , positive):
  about(beta1):
fi:
ListOfLists := [[unapply(x ^ (-alpha1 - 1) * exp(-1 / (beta1 * x)) /
    (GAMMA(alpha1) * beta1 ^ alpha1) , x)], [0, infinity], 
    ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  KS
#
# NOTE TO DIANE:  this distribution is already a routine ... perhaps this
# doesn't need to be here at all ... just placed in the commented list of 
# distributions
#                      
# KSRV := proc();
# local ListOfLists, x;
# ListOfLists := [[unapply( , x)],[0, 1], ["Continuous", "PDF"]];
#

#
#  LaPlace (double exponential)
#
LaPlaceRV := proc(omega :: {positive, symbol}, theta :: {numeric,
    symbol})
local ListOfLists, x:
global omega1, theta1:
omega1 := omega:
theta1 := theta:
if (nargs <> 2) then
  print(`ERROR(LaPlaceRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (is(omega1 <= 0)) then
  print(`ERROR(LaPlaceRV): The parameter omega must be positive`):
  RETURN():
fi:
if (type(omega1, infinity) or type(theta1, infinity)) then
  print(`ERROR(LaPlaceRV): Both parameters must be finite`):
  RETURN():
fi:
if type(omega1, symbol) then
  assume(omega1, positive):
  about(omega1):
fi:
if type(theta1, symbol) then
  assume(theta1, numeric):
fi:

ListOfLists := [[unapply(exp(-abs(x - theta1) / omega1) / (2 * omega1),
    x)], [-infinity, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  LogGamma distribution
#
LogGammaRV := proc(alpha :: {positive, symbol}, beta :: {positive,
    symbol})
local ListOfLists, x:
global alpha1, beta1:
alpha1 := alpha:
beta1 := beta:
if (nargs <> 2) then
  print(`ERROR(LogGammaRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (is(alpha1 <= 0)) then
  print(`ERROR(LogGammaRV): The parameter alpha must be positive`):
  RETURN():
fi:
if (is(beta1 <= 0)) then
  print(`ERROR(LogGammaRV): The parameter beta must be a positive`):
  RETURN():
fi:
if (type(alpha1, infinity) or type(beta1, infinity)) then
  print(`ERROR(LogGammaRV): Both parameters must be finite`):
  RETURN():
fi:
if type(alpha1, symbol) then
  assume(alpha1, positive):
  about(alpha1):
fi:
if type(beta1, symbol) then
  assume(beta1, positive):
  about(beta1):
fi:

ListOfLists := [[unapply(exp(beta1 * x) * exp(-exp(x) / alpha1) /
    (alpha1 ^ beta1 * GAMMA(beta1)), x)], [-infinity, infinity],
    ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Logistic distribution
#
LogisticRV := proc(kappa :: {positive, symbol}, lambda :: {positive,
    symbol})
local ListOfLists, x:
global kappa1, lambda1:
kappa1 := kappa:
lambda1 := lambda:
if (nargs <> 2) then
  print(`ERROR(LogisticRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (is(kappa1 <= 0) or is(lambda1 <= 0)) then
  print(`ERROR(LogisticRV): Both parameters must be positive`):
  RETURN():
fi:
if (type(kappa1, infinity) or type(lambda1, infinity)) then
  print(`ERROR(LogisticRV): Both parameters must be finite`):
  RETURN():
fi:
if type(kappa1, symbol) then
  assume(kappa1, positive):
  about(kappa1):
fi:
if type(lambda1, symbol) then
  assume(lambda1, positive):
  about(lambda1):
fi:

ListOfLists := [[unapply((lambda1 ^ kappa1 * kappa1 * exp(kappa1 * x)) /
    ((1 + (lambda1 * exp(x)) ^ kappa1) ^ 2), x)],
    [-infinity, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Log logistic distribution
#
LogLogisticRV := proc(lambda :: {positive, symbol}, kappa :: {positive,
    symbol})
local x, ListOfLists:
global lambda1, kappa1:
lambda1 := lambda:
kappa1 := kappa:
if (nargs <> 2) then
  print(`ERROR(LogLogisticRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (is(lambda1 <= 0) or is(kappa1 <= 0)) then
  print(`ERROR(LogLogisticRV): Both parameters must be positive`):
  RETURN():
fi:
if (type(lambda1, infinity) or type(kappa1, infinity)) then
  print(`ERROR(LogLogisticRV): Both parameters must be finite`):
  RETURN():
fi:
if type(lambda1, symbol) then
  assume(lambda1, positive):
  about(lambda1):
fi:
if type(kappa1, symbol) then
  assume(kappa1, positive):
  about(kappa1):
fi:

ListOfLists := [[unapply(lambda1 * kappa1 * (lambda1 * x) ^ (kappa1 - 1)
    / ((1 + (lambda1 * x) ^ kappa1) ^ 2), x)], [0, infinity],
    ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Log normal distribution
#
LogNormalRV := proc(mu :: {numeric, symbol}, sigma :: {positive, symbol})
local x,  ListOfLists:
global mu1, sigma1:
mu1 := mu:
sigma1 := sigma:
if (nargs <> 2) then
  print(`ERROR(LogNormalRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (is(sigma1 <= 0)) then
  print(`ERROR(LogNormalRV): Sigma must be positive`):
  RETURN():
fi:
if (type(mu1, infinity) or type(sigma1, infinity)) then
  print(`ERROR(LogNormalRV): Both parameters must be finite`):
  RETURN():
fi:
if type(sigma1, symbol) then
  assume(sigma1, positive):
  about(sigma1):
fi:
if type(mu1, symbol) then
  assume(mu1, numeric):
fi:

ListOfLists := [[unapply(1 / (sqrt(2 * Pi) * x * sigma1) * exp(-(log(x) -
    mu1) ^ 2 / (2 * sigma1 ^ 2)), x)], [0, infinity], ["Continuous",
    "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Lomax (Pareto Type II)
#
LomaxRV := proc(kappa :: {positive, symbol}, lambda :: {positive,
    symbol})
local ListOfLists, x:
global kappa1, lambda1:
kappa1:=kappa:
lambda1:=lambda:
if (nargs <> 2) then
  print(`ERROR(LomaxRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (is(kappa1 <= 0)) then
  print(`ERROR(LomaxRV): Kappa must be positive`):
  RETURN():
fi:
if (is(lambda1 <= 0)) then
  print(`ERROR(LomaxRV): Lambda must be positive`):
  RETURN():
fi:
if (type(kappa1, infinity) or type(lambda1, infinity)) then
  print(`ERROR(LomaxRV): Both parameters must be finite`):
  RETURN():
fi:
if type(kappa1, symbol) then
  assume(kappa1, positive):
  about(kappa1):
fi:
if type(lambda1, symbol) then
  assume(lambda1, positive):
  about(lambda1):
fi:

ListOfLists := [[unapply(lambda1 * kappa1 * (1 + lambda1 * x) ^ (-kappa1
    - 1) , x)], [0, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Makeham distribution
#
MakehamRV := proc(gamma :: {positive, symbol}, delta :: {positive,
    symbol}, kappa :: {numeric, symbol})
local x,  ListOfLists:
global gamma1, delta1, kappa1:
gamma1:=gamma:
delta1:=delta:
kappa1:=kappa:
if (nargs <> 3) then
  print(`ERROR(MakehamRV): This procedure requires 3 arguments`):
  RETURN():
fi:
if (is(gamma1 <= 0) or is(delta1 <= 0) or is(kappa1 <= 1)) then
  print(`ERROR(MakehamRV): Parameter space violation`):
  RETURN():
fi:
if (type(gamma1, infinity) or type(delta1, infinity) or type(kappa1,
    infinity)) then
  print(`ERROR(MakehamRV): Each parameter must be finite`):
  RETURN():
fi:
if type(delta1, symbol) then
  assume(delta1, positive):
  about(delta1):
fi:
if type(kappa1, symbol) then
  assume(kappa1 > 1):
  about(kappa1):
fi:
if type(gamma1, symbol) then
  assume(gamma1, positive):
  about(gamma1):
fi:

ListOfLists := [[unapply((gamma1 + delta1 * kappa1 ^ x) * exp(-gamma1 * x
    - delta1 * (kappa1 ^ x - 1) / log(kappa1)), x)], [0, infinity],
    ["Continuous","PDF"]]:
RETURN(ListOfLists):
end:

#
#  Muth distribution
#
MuthRV := proc(kappa :: {positive, symbol})
local x,  ListOfLists:
global kappa1:
kappa1 := kappa:
if (nargs <> 1) then
  print(`ERROR(MuthRV): This procedure requires 1 argument`):
  RETURN():
fi:
if (is(kappa1 <= 0) or is(kappa1 > 1)) then
  print(`ERROR(MuthRV): Parameter space violation`):
  RETURN():
fi:
if type(kappa1, infinity) then
  print(`ERROR(MuthRV): The shape parameter must be finite`):
  RETURN():
fi:
if type(kappa1, symbol) then
  assume(kappa1, positive):
  additionally(kappa1 <= 1):
  about(kappa1):
fi:

ListOfLists := [[unapply((exp(kappa1 * x) - kappa) * exp(-exp(kappa1 * x)
    / kappa1 + kappa1 * x + 1 / kappa1), x)], [0, infinity],
    ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  NoncentralChiSquare
#
# NOTE TO DIANE:  see comments at top of file
# REFERENCE NOTE:  Hogg and Craig (5ed), pages 458-460
# REFERENCE NOTE:  Larsen and Marx (2ed), page 508
# NoncentralChiSquareRV := proc():
# local ListOfLists, x:
# ListOfLists := [[unapply(, x)],[0, 1], ["Continuous", "PDF"]]:
#

#
#  NoncentralF
#
# NOTE TO DIANE:  see comments at top of file
# REFERENCE NOTE:  Hogg and Craig (5ed), page 460-461
# REFERENCE NOTE:  Larsen and Marx (2ed), page 509
# NoncentralFRV := proc():
# local ListOfLists, x:
# ListOfLists := [[unapply(, x)], [0, 1], ["Continuous", "PDF"]]:
#

#
#  NoncentralT
#
# NOTE TO DIANE:  see comments at top of file
# REFERENCE NOTE:  Hogg and Craig (5ed), page 420
# REFERENCE NOTE:  Larsen and Marx (2ed), page 353
# NoncentralTRV := proc():
# local ListOfLists, x:
# ListOfLists := [[unapply(, x)], [0, 1], ["Continuous", "PDF"]]:
#

#
#  Normal distribution
#
NormalRV := proc(mu :: {numeric, symbol}, sigma)
local x, ListOfLists:
global mu1, sigma1:
mu1 := mu:
sigma1 := sigma:
if (nargs <> 2) then
  print(`ERROR(NormalRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (is(sigma1 <= 0)) then
  print(`ERROR(NormalRV): Sigma must be positive`):
  RETURN():
fi:
if (type(mu1, infinity) or type(sigma1, infinity)) then
  print(`ERROR(NormalRV): Both parameters must be finite`):
  RETURN():
fi:
if type(sigma1, symbol) then
  assume(sigma1, positive):
  about(sigma1):
fi:
if type(mu1, symbol) then
  assume(mu1, numeric):
fi:

ListOfLists := [[unapply(exp(-((x - mu1) / sigma1) ^ 2 / 2) / sqrt(2 *
    Pi * sigma1 ^ 2), x)], [-infinity, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Pareto distribution
#
ParetoRV := proc(lambda :: {positive, symbol}, kappa :: {positive,
    symbol})
local x,  ListOfLists:
global lambda1, kappa1:
lambda1 := lambda:
kappa1 := kappa:
if (nargs <> 2) then
  print(`ERROR(ParetoRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (is(lambda1 <= 0) or is(kappa1 <= 0)) then
  print(`ERROR(ParetoRV): Both parameters must be positive`):
  RETURN():
fi:
if (type(lambda1, infinity) or type(kappa1, infinity)) then
  print(`ERROR(ParetoRV): Both parameters must be finite`):
  RETURN():
fi:
if type(lambda1, symbol) then
  assume(lambda1, positive):
  about(lambda1):
fi:
if type(kappa1, symbol) then
  assume(kappa1, positive):
  about(kappa1):
fi:

ListOfLists := [[unapply(kappa1 * lambda1 ^ kappa1 / (x ^ (kappa1 + 1)),
    x)], [lambda, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Rayleigh (special case of Weibull with kappa = 2)
#
RayleighRV := proc(lambda :: {positive, symbol})
local ListOfLists, x:
global lambda1:
lambda1 := lambda:
if (nargs <> 1) then
  print(`ERROR(RayleighRV): This procedure requires 1 argument`):
  RETURN():
fi:
if (is(lambda1 <= 0)) then
  print(`ERROR(RayleighRV): The scale parameter must be positive`):
  RETURN():
fi:
if type(lambda1, infinity) then
  print(`ERROR(RayleighRV): The scale parameter must be finite`):
  RETURN():
fi:
if type(lambda1, symbol) then
  assume(lambda1, positive):
  about(lambda1):
fi:

ListOfLists := [[unapply(2 * lambda1 ^ 2 * x * exp(-(lambda1 * x) ^ 2),
    x)], [0, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  StandardCauchy (special case of T with 1 df or of Cauchy)
#
StandardCauchyRV := proc()
local ListOfLists, x:
if (nargs <> 0) then
  print(`ERROR(StandardCauchyRV): This procedure requires no arguments`):
  RETURN():
fi:

ListOfLists := [[unapply(1 / (Pi * (1 + x ^ 2)), x)], [-infinity,
    infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  StandardNormal (special case of Normal)
#
StandardNormalRV := proc()
local ListOfLists, x:
if (nargs <> 0) then
  print(`ERROR(StandardNormalRV): This procedure requires no arguments`):
  RETURN():
fi:

ListOfLists := [[unapply(exp(- x ^ 2 / 2) / sqrt(2 * Pi), x)],
    [-infinity, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  StandardTriangular (special case of Triangular)
#
StandardTriangularRV := proc(m :: {positive, symbol})
local ListOfLists, x:
global m1:
m1 := m:
if (nargs <> 1) then
  print(`ERROR(StandardTriangularRV): This procedure requires 1`):
  print(`argument`):
  RETURN():
fi:
if (is(m1 <= 0) or is(m1 >= 1)) then
  print(`ERROR: The parameter m must be strictly between 0 and 1`):
  RETURN():
fi:
if type(m1, infinity) then
  print(`ERROR(StandardTriangularRV): The parameter m must be finite`):
  RETURN():
fi:
if type(m1, symbol) then
  assume(m1, positive):
  additionally(m1 < 1):
  about(m1):
fi:

ListOfLists := [[unapply(2 * x / m1, x), unapply(2 * (1 - x) / (1 - m1),
    x)], [0, m, 1], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  StandardUniform  (special case of Uniform)
#
StandardUniformRV := proc()
local ListOfLists, x:
if (nargs <> 0) then
  print(`ERROR(StandardUniformRV): This procedure requires no`):
  print(`arguments`):
  RETURN():
fi:

ListOfLists := [[unapply(1, x)], [0, 1], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  T distribution
#
TRV := proc(n :: {posint, symbol})
local ListOfLists, x:
global n1:
n1 := n:
if (nargs <> 1) then
  print(`ERROR(TRV): This procedure requires 1 argument`):
  RETURN():
#fi:
#elif not(type(n1, posint)) then
#  print(`ERROR(TRV): The shape parameter must be a positive integer`):
#  #RETURN():
#fi:
#elif type(n1, infinity) then
#  print(`ERROR: The shape parameter must be finite`):
#  RETURN():
#fi:
elif type(n1, symbol) then
  assume(n1, posint):
  about(n1):
fi:

ListOfLists := [[unapply(GAMMA((n1 + 1) / 2) * (1 + x ^ 2 / n1) ^
    (- (n1 + 1) / 2) / (sqrt(n1 * Pi) * GAMMA(n1 / 2)),x)],
    [-infinity, infinity], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Triangular distribution
#
TriangularRV := proc(a, m, b)
local x,  ListOfLists:
global a1, m1, b1:
a1 := a:
m1 := m:
b1 := b:
if (nargs <> 3) then
  print(`ERROR(TriangularRV): This procedure requires 3 arguments`):
  RETURN():
fi:
if (is(m1 <= a1)) then
  print(`ERROR(TriangularRV): First parameter must be less than the`):
  print(`second parameter`):
  RETURN():
fi:
if (is(b1 <= m1)) then
  print(`ERROR(TriangularRV): Second parameter must be less than the`):
  print(`third parameter`):
  RETURN():
fi:
if (type(a1, infinity) or type(b1, infinity) or type(m1, infinity)) then
  print(`ERROR(TriangularRV): Each parameter must be finite`):
  RETURN():
fi:
if (type(a1, symbol) and type(m1, symbol)) then
  assume(a1 < m1):
  additionally(a1, numeric):
  additionally(m1, numeric):
fi:
if (type(m1, symbol) and type(b1, symbol)) then
  assume(m1 < b1):
  additionally(m1, numeric):
  additionally(b1, numeric):
fi:

ListOfLists := [[unapply(2 * (x - a1) / ((b1 - a1) * (m1 - a1)), x),
    unapply(2 * (b1 - x) / ((b1 - a1) * (b1 - m1)), x)],
    [a, m, b], ["Continuous", "PDF"]]:
RETURN(ListOfLists):
end:

#
#  Uniform distribution
#
UniformRV := proc(a, b)
local x,  ListOfLists:
global a1, b1:
a1 := a:
b1 := b:
if (nargs <> 2) then
  print(`ERROR(UniformRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (is(b <= a)) then
  print(`ERROR(UniformRV): First parameter must be less than second`):
  print(`parameter`):
  RETURN():
fi:
if (type(a1, infinity) or type(b1, infinity)) then
  print(`ERROR(UniformRV): Both parameters must be finite`):
  RETURN():
fi:
if type(a1, symbol) and type(b1, symbol) then
  assume(a1 < b1):
  additionally(a1, numeric):
  additionally(b1, numeric):
  about(a1):
  about(b1):
fi:

ListOfLists := [[unapply(1 /(b1 - a1), x)], [a, b], ["Continuous",
    "PDF"]]:
RETURN(ListOfLists):
end:

#
# Version identifier
#
VersionRV := proc()
print(`APPL version 2, 25 June 2002, (c) Andrew Glen, Larry Leemis, Diane Evans`); 
end:

#
#  Weibull distribution
#
WeibullRV := proc(lambda, kappa)
local x,  ListOfLists:
global lambda1, kappa1:
lambda1 := lambda:
kappa1 := kappa:
if (nargs <> 2) then
  print(`ERROR(WeibullRV): This procedure requires 2 arguments`):
  RETURN():
fi:
if (is(lambda1 <= 0) or is(kappa1 <= 0)) then
  print(`ERROR(WeibullRV): Both parameters must be positive`):
  RETURN():
fi:
if (type(lambda1, infinity) or type(kappa1, infinity)) then
  print(`ERROR(WeibullRV): The parameters must be finite`):
  RETURN():
fi:
if type(lambda1, symbol) then
  assume(lambda1, positive):
  about(lambda1):
fi:
if type(kappa1, symbol) then
  assume(kappa1, positive):
  about(kappa1):
fi:

ListOfLists := [[unapply(kappa1 * lambda1 ^ kappa1 * x ^ (kappa1 - 1)
    * exp(-(lambda1 * x) ^ kappa1), x)], [0, infinity], ["Continuous",
    "PDF"]]:
RETURN(ListOfLists):
end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: convert4.map
#
#  NOTES:  
#  Discrete Cases:
#  (I)  dot cases
#       (a) incremented by 1
#       (b) transformed by g(x)
#           (i)  incremented by k
#           (ii) incremented by 1
#       (c) incremented by k
#  (II) no dot cases
#       (a) arrow case
#       (b) no arrow case
#
#  standard "dot" support format: 
#       [value .. value, incremented by k, transformed by g(x)]
#  
#  standard "no dot" pdf and support format:
#       [frac1, frac2, frac3, ... , fracN], [a1, a2, a3, ... , aN]
#       Example: [0.1, 0.3, 0.2, 0.4], [1, 4, 11, 34/3]
#
#  Procedure name: Convert(X)
# 
#  Other APPL Procedures Called: PDF, Convert, ConvertNoDot
#   
#  Date: February 12, 2000
#
#  Purpose: (1) Converts discrete RVs with a "dot" support type to
#               the standard APPL "dot" support format: 
#               [value .. value, incremented by k, transformed by g(x)]
#
#           (2) Converts discrete RV's with a "no dot" support type
#               to the standard "no dot" pdf and support format:
#            [frac1, frac2, frac3, ... , fracN], [a1, a2, a3, ... , aN]
#
#  Arguments: A discrete random variable X in the list-of-lists format:
#             [[f(x)], [support], ["Discrete", "XXX"]], where XXX is
#             PDF, CDF, IDF, SF, HF, or CHF 
#  REPLACE #5 with something about range
#  Algorithm
#    1.  Check for the appropriate number of arguments
#    2.  Check that the RV X is in the list of 3 lists format
#    3.  Check that the given RV X is discrete
#    4.  Convert X to PDF form if not already in that form 
#    5.  Check to see whether the RV X is in the discrete "dot" case.
#        In startup.map, "dot" is a defined structure type for discrete
#        RVs. The structure `type/dot is defined to be:
#        `type/dot` := {constant .. constant, symbol .. constant,
#             constant .. symbol, symbol .. symbol}:
#    6.  If X is in the "dot" case with support incremented by 1,
#        [value .. value], then convert its support list to:
#        [value .. value, 1, x -> x]
#    7.  If X is in the "dot" case with support incremented by 1 and
#        transformed by g(x): [value .. value, transformed by 
#        g(x)], then convert its support list to: 
#        [value .. value, 1, g(x)]
#    8.  If X is in the "dot" case with support incremented by k,
#        [value .. value, incremented by k], then convert its support
#        list to: 
#        [value .. value, k, x -> x]
#    9.  If the discrete RV X is not in the "dot" case, it is in the
#        "no dot" case, which has a support list that looks like:
#        [1, 2, 5], or [15], or [2, 8, 13, 43, 100]      
#    10. If X is in the "no dot" case, then determine if the PDF 
#        sublist contains a Maple procedure.  If so, then X is in the
#        "arrow" (->) case and needs to be converted to the standard
#        "no dot" form, which is:
#        [[fraction1, fraction2, fraction3, ... , fractionN], 
#         [a1, a2, a3, ... , aN], ["Discrete", "PDF"]]
#    11. Check that symbols or infinity are not support values in the
#        "no dot" cases
#    12. Convert X to the standard "no dot" form
#    13. Return the converted discrete random variable to the user in
#        its new form
#
Convert := proc(X :: list(list))
local NumLists, fX, SubList2, n, NoDotList, SubList1, IllSupp, NewList1, i,
    NewMemb:
#
#  Check for the appropriate number of arguments
#
# print(`in convert`):
if (nargs <> 1) then
  print(`ERROR(Convert): This procedure requires 1 argument:`):
  print(`A discrete random variable`):
  return:
fi:
#
#  Check that the RV X is in the list of 3 lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(Convert):The RV X must be in a list of 3 lists format`):
  return:
fi:
#
#  Check to see that the random variable X is discrete
#
if not(X[3][1] = "Discrete") then
  print(`ERROR(Convert): This procedure requires a discrete RV`):
  return:
fi:
fX := X:
SubList1 := fX[1]:
SubList2 := fX[2]:
# print(SubList1):
# print(SubList2):
#
#  The RV X must be in PDF, CDF, SF, HF, CHF, or IDF form
#
if not(member(X[3][2], {"PDF", "CDF", "SF", "HF", "CHF", "IDF"})) then
  print(`ERROR(Convert): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
#
#  Conversions for random variables having PDF, CDF, SF, HF, or CHF 
#  formats
#
if member(X[3][2], {"PDF", "CDF", "SF", "HF", "CHF"}) then
#
#  Check to see whether the random variable X is in the discrete "dot"
#  case
#
  if type(SubList2[1], range) then
    # print(`dot form`):
#
#  In the "dot" case with support incremented by 1, [value .. value].
#  Convert X's support to: [value .. value, 1, x -> x]
#
    if type(SubList2[-1], range) then
      # print(`example: binomial`):
      SubList2 := [SubList2[1], 1, x -> x]:
#
#  In the "dot" case with support incremented by 1 and transformed by 
#  g(x), [value .. value, transformed by g(x)].
#  Convert X's support to: [value .. value, 1, g(x)]
#
    elif (type(SubList2[-1], procedure) and not(type(SubList2[-2],
        integer))) then
      SubList2 := [SubList2[1], 1, SubList2[-1]]:
#
#  In the "dot" case with support incremented by k, [value .. value,
#  incremented by k].
#  Convert X's support to: [value .. value, k, x -> x]
#
    elif type(SubList2[-1], integer) then   
      SubList2 := [SubList2[1], SubList2[2], x -> x]:
    fi:
#
#  Check to see whether the random variable X is in the discrete "no
#  dot" case
#
  else
    n := nops(SubList2):
    IllSupp := false:
#
#  Check for a procedure (x -> ) in the first SubList
#
    if type(SubList1[1], procedure) then
#
#  Check that symbols or infinity are not support values
#
      for i from 1 to n do
        if (type(SubList2[i], symbol) or type(SubList2[i], infinity))
            then
          IllSupp := true:
          break:
        fi:
      od:
#
#  Convert the Maple procedure in the PDF SubList to a list of the 
#  form: [fraction1, fraction2, fraction3, ..., fractionN]
#
      NewList1 := []:
      if not(IllSupp) then
        for i from 1 to n do
          NewMemb := op(subs(x = SubList2[i], SubList1(x))):
          NewList1 := [op(NewList1), NewMemb]:
        od:
        fX[1] := NewList1:
      else
       print(`ERROR(Convert): This RV requires numeric support values`):
       return(false):
      fi:
#
#  If a Maple procedure is NOT in the PDF sublist, check that symbols
#  or infinity are not support values
#
    else
      for i from 1 to n do
        if (type(SubList2[i], symbol) or type(SubList2[i], infinity))
          then
          IllSupp := true:
          break:
        fi:
      od:
      if (IllSupp) then
        print(`ERROR(Convert): RV requires numeric support values`):
        return(false):
      fi:
    fi:
  fi:
elif X[3][2] = "IDF" then
  # print(`just returning X as is for now`):
fi:
#
#  Return the converted discrete random variable sublists to the user
#  in its new form
#
return([fX[1], SubList2, fX[3]]):

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: converttonodot1.map
#
#  standard "dot" support format: 
#       [value .. value, incremented by k, transformed by g(x)]
#  
#  standard "nodot" pdf and support format:
#       [frac1, frac2, frac3, ... , fracN], [a1, a2, a3, ... , aN]
#       Example: [0.1, 0.3, 0.2, 0.4], [1, 4, 11, 34/3]
#
#  Procedure name: ConvertToNoDot(X)
# 
#  Other APPL Procedures Called: PDF
#   
#  Date: February 13, 2000
#
#  Purpose: Converts discrete RVs with a standard APPL "dot" support
#           format to the standard APPL "no dot" support format: 
#           [frac1, frac2, frac3, ... , fracN], [a1, a2, a3, ... , aN]
#
#  Arguments: A discrete random variable X in the list-of-lists format:
#             [[f(x)], [support], ["Discrete", "XXX"]], where XXX is
#             PDF, CDF, IDF, SF, HF, or CHF 
#
#  Algorithm
#    1.  Check for the appropriate number of arguments
#    2.  Check that the RV X is in the list of 3 lists format
#    3.  Check that the given RV X is discrete
#    4.  Convert X to PDF form if not already in that form 
#    5.  Check to see that the RV X has the standard APPL "dot" format.
#        In startup.map, "dot" is a defined structure type for discrete
#        RVs. The structure `type/dot is defined to be:
#        `type/dot` := {constant .. constant, symbol .. constant,
#             constant .. symbol, symbol .. symbol}:
#        The standard APPL "dot" support format is:
#        [value .. value, incremented by k, transformed by g(x)]
#    6.  Convert to the PDF and support of X to the standard APPL "no
#        dot" formats.
#    7.  Return the converted discrete random variable to the user in
#        its new form
#
ConvertToNoDot := proc(X :: list(list))
local NumLists, List2, fX, gX, List1, Supp, Lo, Hi, Incr, PopSize,
    Finite, NewList1, NewList2, i:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 1) then
  print(`ERROR(ConvertToNoDot): This procedure requires 1 argument:`):
  print(`A discrete random variable`):
  return:
fi:
#
#  Check that the RV X is in the list of 3 lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(ConvertToNoDot): X must be a list of 3 lists`):
  return:
fi:
#
#  Check to see that the random variable X is discrete
#
if not(X[3][1] = "Discrete") then
  print(`ERROR(ConvertToNoDot): Procedure requires a discrete RV`):
  return:
fi:
#
#  Convert X to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
  fX := X:
elif member(X[3][2], {"CDF", "SF", "HF", "CHF", "IDF"}) then
  fX := PDF(X):
else
  print(`ERROR(ConvertToNoDot): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
#
# Convert fX to its standard APPL discrete list-of-sublists format
#
fX := Convert(fX):
if (fX = false) then
  print(`ERROR(Transform): Discrete RV X is NOT in legal APPL form`):
  return:
fi:
List2 := fX[2]:
#
#  Check to see that the random variable X is in the standard discrete
#  "dot" case. If it is not, return an error message to the user.
#
if type(List2, range) then
  if not(type(List2[-1], procedure) and type(List2[-2], numeric)) then
    print(`ERROR(ConvertToNoDot): Procedure requires a discrete RV`):
    print(`in standard "dot" support format`):
    print(`error type 1`):
    return:
  fi:
fi:
#  else
#    print(`ERROR(ConvertToNoDot): Procedure requires a discrete RV`):
#    print(`in standard "dot" support format`):
#    return:
#  fi:
#
#  If the random variable X has a "dot" support format with g(x) as an
#  expression other than x -> x, transform the PDF f(x) by g(x). See
# (*) in the introductory comments for the meaning of g(x).
#
# print(`fX is now`):
# print(fX):
gX := unapply(fX[2][-1](x))(x): 
# print(`gX is`, gX):
if not((ispoly(gX, linear, x, 'a0', 'a1')) and
       (a0 = 0) and (a1 = 1)) then
  fX[1] := subs(x = gX, unapply(fX[1](x))(x)):
fi:
# print(`fX is now`):
# print(fX):
List1 := fX[1]:
Supp := List2[1]:
Lo := lhs(Supp):
Hi := rhs(Supp): 
Incr := List2[-2]:
#
#  Check to see if the discrete RV has finite or infinite support. If
#  it has finite support, then assign the size of the RV's support to
#  PopSize. If the RV's support is infinite, then just return a message
#  about infinite support for now ...
#
if not(type(Hi, symbol)) then
  PopSize := (Hi - Lo)/Incr + 1:
  Finite := true:
elif type(Hi, symbol) then
  print(`ERROR(ConvertToNoDot): Conversion cannot take place, since`):
  print(`the random variable X has infinite support`):
  return(false):
fi:
#
#  Rewrite the discrete PDF in List1 as numerical values separated by 
#  commas, instead of a procedure. Also, rewrite List2.
#  EXAMPLE:  List1 := [x -> x / 15], List2 := [1 .. 5, 1, x -> x]
#  becomes   List1 := [1/15, 2/15, 3/15, 4/15, 5/15]
#            List2 := [1, 2, 3, 4, 5]
#
NewList1 := []:
NewList2 := []:
for i from Lo by Incr to Hi do
  NewList1 := [op(NewList1), simplify(subs(x = i, op(unapply
      (List1(x))(x))))]:
  NewList2 := [op(NewList2), simplify(subs(x = i, gX))]:
od:
List1 := NewList1:
List2 := NewList2:
#
#  Return the ConvertToNoDot discrete random variable sublists to the
#  user in its new form
#
return([List1, List2, fX[3]]):

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: convolution7.map
#  corresponds to my paper
#
#  Procedure Name: Convolution(X, Y)
#
#  Other APPL Procedures Called: PDF, Transform, Product, Convert, 
#
#  Date: September 4, 2000
#
#  Purpose: 
#
#  Arguments: X, Y
#
#  Algorithm:
Convolution := proc(X :: list(list), Y :: list(list), Z :: list(list)) 
global fX, fY:
local fXc, fYc, Sum1, Sum2, NumLists, i, x1, x2, gln, ge, temp1, temp2, temp3, fV,
    Lo, Hi, DotX, DotY, n, m, NewXY, XYSum, XYSumProbs, NewXYSumProbs,
    j, NewXYSum, k, FinalPDF, NextProbValue, FinalSupport, count, mgfx,
    mgfy, mgfprod, Temp, s, Probs, NumZeros, FirstTerm, SecondTerm,
    fZ:
#
#  6/22/2007: ADDED these next three lines for an example in the APPL
#  Monongraph in which we wanted to add 3 different random variables
#  with the Convolution procedure
# 
if (nargs = 3) then
  Sum1 := Convolution(X, Y):
  Sum2 := Convolution(Sum1, Z):
  return(Sum2):
fi:
#
#  Check for the number of arguments
#
if (nargs <> 2) then
  print(`ERROR(Convolution): This procedure requires 2 arguments:`):
  print(`A random variable X, and a random variable Y`):
  return:
fi:
#
#  Check that the first RV is a list of 3 sublists
#
for i from 1 to nargs do
  NumLists := nops(args[i]):
  if (NumLists <> 3) then
    print(`ERROR(Convolution): The RV must be a list of 3 lists`):
    return:
  fi:
od:
#
#  Convert the RV to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
  fXc := X:
elif member(X[3][2], {"CDF", "SF", "HF", "CHF", "IDF"}) then
  fXc := PDF(X):
else
  print(`ERROR(Convolution): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
# print(`fXc is`, fXc):
#
#  Convert Y to PDF form if not already in that form
#
if (Y[3][2] = "PDF") then
  fYc := Y:
elif member(Y[3][2], {"CDF", "SF", "HF", "CHF", "IDF"}) then
  fYc := PDF(Y):
else
  print(`ERROR(Convolution): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
# print(`fYc is`, fYc):

if (X[3][1] = "Continuous") then
  #assume(x1 > 0):
  #assume(x2, real):
  gln := [[x1 -> ln(x1)], [0, infinity]]:
  ge := [[x2 -> exp(x2),x2 -> exp(x2)], [-infinity,0, infinity]]:
  temp1 := Transform(fXc, ge):
    # print(`temp1 is`, temp1):
  temp2 := Transform(fYc, ge):
    # print(`temp2 is`, temp2):
  temp3 := Product(temp1, temp2):
    # print(`temp3 is`, temp3):

  fZ := Transform(temp3, gln):
    # print(`fZ is`, fZ):
elif (X[3][1] = "Discrete") then
  fX := PDF(X):
  fX := Convert(fX):
  if (fX = false) then
    print(`ERROR(Convolution): Discrete random variable X is NOT`):
    print(`in legal APPL form`):
    return:
  fi:
  fY := PDF(Y):
  fY := Convert(fY):
  if (fY = false) then
    print(`ERROR(Convolution): Discrete random variable Y is NOT`):
    print(`in legal APPL form`):
    return:
  fi:
#
#  Determine if the random variable X has a "dot" support format or a
#  "nodot" support format. Return an error message for a symbolic PDF 
#  in the "dot" format with symbolic support, such as:
#  X := [[x -> x / 6], [1 .. n], ["Discrete", "PDF"]];
#
  if type(fX[2][1], range) then
    Lo := lhs(fX[2][1]):
    Hi := rhs(fX[2][1]):
    if type(Hi, symbol) and not(evalb(Hi = infinity)) then 
      print(`ERROR(Convolution): RV's support must be numeric`):
      return:
    elif type(Lo, symbol) or evalb(Lo = -infinity) then 
      print(`ERROR(Convolution): RV's lower support must be`):
      print(`a finite numerical value`):
      return:
#
#  Convert finite "dot" formats to "nodot" formats. For example, if
#  X := [[x -> x / 6], [1 .. 3], ["Discrete", "PDF"]], convert X to
#  X := [[1 / 6, 2 / 6, 3 / 6], [1, 2, 3], ["Discrete", "PDF]];
#
    elif type(Lo, numeric) and type(Hi, numeric) then
      fX := ConvertToNoDot(fX):
      n := nops(fX[2]):
      DotX := false:
    else
      DotX := true:
    fi:
#
#  The RV X has a "nodot" support format
#
  else
    n := nops(fX[2]):
    DotX := false:
  fi:
#
#  Determine if the random variable Y has a "dot" support format or a
#  "nodot" support format. Return an error message for a symbolic PDF 
#  in the "dot" format with symbolic support
#
  if type(fY[2][1], range) then
    Lo := lhs(fY[2][1]):
    Hi := rhs(fY[2][1]):
    if type(Hi, symbol) and not(evalb(Hi = infinity)) then 
      print(`ERROR(Convolution): RV's support must be numeric`):
      return:
    elif type(Lo, symbol) or evalb(Lo = -infinity) then 
      print(`ERROR(Convolution): RV's lower support must be`):
      print(`a finite numerical value`):
      return:
#
#  Convert finite "dot" formats to "nodot" formats. 
#
    elif type(Lo, numeric) and type(Hi, numeric) then
      fY := ConvertToNoDot(fY):
      m := nops(fY[2]):
      DotY := false:
    else
      DotY := true:
    fi:
  else
    m := nops(fY[2]):
    DotY := false:
  fi:
#
#  RV has a "nodot" support format
#  Example:  X := [[1/6, 1/3, 1/2], [1, 2, 3], ["Discrete", "PDF"]];
#  DISCRETE, NODOT (FINITE)
#
  if not(DotX) and not(DotY) then
    if (n * m <= 100) then
      Temp := BruteForceConvolutionMethod():
    else
      Temp := MovingHeapConvolutionMethod():
    fi:
    s := Temp[1]:
    Probs := Temp[2]:
    if Probs[1] = 1 then
      return([Probs, s, ["Discrete", "PDF"]]):
    fi:
#
#  Remove redundancies from probability list
#
    FinalSupport := array(sparse, 1 .. n * m, []):
#
#  Since first element will be unique, place the first 2 sum elements
#  in the final support
#
    FinalSupport[1] := s[1]:
    FinalSupport[2] := s[2]:
    FinalPDF := array(sparse, 1 .. n * m, []):
    FinalPDF[1] := Probs[1]:
    k := 2:
    j := 2:
    while (k < n * m) do
     FinalPDF[j] := FinalPDF[j] + Probs[k]:
     if evalf(s[k]) <> evalf(s[k + 1]) then
        j := j + 1:
        FinalSupport[j] := s[k + 1]:
      fi:
      k := k + 1:
    od:
    FinalPDF[j] := FinalPDF[j] + Probs[k]:
#
#  Remove extraneous zeros from FinalPDF and FinalSupport. We know the
#  zeros (if any) at the end of the FinalPDF array are not probability
#  values.  They exist because of the redundant values in s.  Use
#  FinalPDF to determine how many extraneous zeros exist, and 
#  reconstruct FinalPDF and FinalSupport so the extra zeros are not
#  included as part of the arrays.
#
    NumZeros := 0:
    for i from (n * m) by -1 to 1 while FinalPDF[i] = 0 do
      NumZeros := NumZeros + 1:
    od:
    FinalSupport := array(1 .. n * m - NumZeros, [seq(FinalSupport[i],
        i = 1 .. n * m - NumZeros)]):
    FinalPDF := array(1 .. n * m - NumZeros, [seq(FinalPDF[i],
        i = 1 .. n * m - NumZeros)]):
    FinalSupport := convert(FinalSupport, list):
    FinalPDF := convert(FinalPDF, list):
    fZ := [FinalPDF, eval(FinalSupport), ["Discrete", "PDF"]]:

#    FinalPDF := convert(FinalPDF, list):
#    SizeBefore := nops(FinalPDF):
#    FinalPDF := remove(`=`, FinalPDF, 0):
#    SizeAfter := nops(FinalPDF):
#    ExtraZeros := SizeBefore - SizeAfter:
#    FinalSupport := array(1 .. n * m - ExtraZeros, [seq(FinalSupport[i],
#        i = 1 .. n * m - ExtraZeros)]):
    
#
#  Either X or Y has a "dot" (infinite) support format. For example, 
#  X := [[x -> (1 / 2) ^ x], [1 .. infinity], ["Discrete", "PDF"]];
#  DISCRETE, DOT (INFINITE)
#

#
#  One RV has infinite support, while the other has finite support. Best
#  we can do is return the product of the MGFs.
#
  else
    if not(DotX and DotY) then
      mgfx := MGF(fX):
      mgfy := MGF(fY):
      mgfprod := combine(expand(mgfx * mgfy), exp):
      print(`The moment generating function of X is`, mgfx):
      print(`The moment generating function of Y is`, mgfy):
      print(`The moment generating function of their product is`):
      print(mgfprod):
      return:
#
#  Both X and Y have infinite support.  Determine the convolution
#  of the two PDFs by the discrete convolution formula if they are
#  both defined on the same support, their supports are incremented by 1,
#  and their transformations are x -> x.
#
    else
      # print(lhs(fX[2][1]), lhs(fY[2][1]), fX[2][-2], fY[2][-2]): 
      if (lhs(fX[2][1]) <> lhs(fY[2][1])) or (fX[2][-2] <> fY[2][-2]) or
         (fX[2][2] <> 1) or (evalb(unapply(fX[2][-1](x))(x) <> x)) or       
         (evalb(unapply(fX[2][-1](x))(x) <> unapply(fX[2][-1](x))(x)))
          then 
        mgfx := MGF(fX):
        mgfy := MGF(fY):
        mgfprod := combine(expand(mgfx * mgfy), exp):
        print(`The moment generating function of X is`, mgfx):
        print(`The moment generating function of Y is`, mgfy):
        print(`The moment generating function of their product is`):
        print(mgfprod):
        return:
      else
        # print(op(unapply(fX[1](x))(x))):
        # print(op(unapply(fY[1](x))(x))):
        FirstTerm := subs(x = k, op(unapply(fX[1](x))(x))):
        SecondTerm := subs(x = x - k, op(unapply(fY[1](x))(x))):  
        # print(Sum(FirstTerm * SecondTerm, k = 0 .. x )):  
        FinalPDF := simplify(sum(FirstTerm * SecondTerm, k = 0 .. x )):
        # print(denom(FinalPDF)):

# MIGHT WANT TO ADD LINES FOR WHEN MAPLE IS UNABLE
# TO DETERMINE THE DISCRETE CONV FORMULA SUM

        if has(denom(FinalPDF), GAMMA(x + 1)) then
          FinalPDF := convert(FinalPDF, factorial):
        fi:
        FinalSupport := [lhs(fX[2][1]) + lhs(fY[2][1]) .. infinity]:
        fZ := [[FinalPDF], FinalSupport, ["Discrete", "PDF"]]:
      fi:
    fi:
  fi:
else
  print(`ERROR(Convolution): This procedure requires a`):
  print(`Continuous or Discrete random variable`):
  return:
fi:
return(fZ):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: convolutioniid1.map
#  
#  Procedure Name: ConvolutionIID(X, n)
#
#  Other APPL Procedures Called: PDF, Convolution
#
#  Date: September 10, 1999
#
#  Purpose: 
#
#  Arguments: X: Continuous random variable
#
#  Algorithm:
#
ConvolutionIID := proc(X, n) 
local fX, fsum, i:

if (n < 2) then
  print(`ERROR(ConvolutionIID): n must be > 1`):
  RETURN():
fi:

print(`Please be patient, this may take several minutes`):

# fX := PDF(X):
# print(`fX is`, fX):
fsum := Convolution(X, X):
# print(`fsum is`, fsum):
for i from 3 to n do
  fsum := Convolution(X, fsum):
od:
RETURN(fsum):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: createheap4.map
#
#  Procedure Name: CreateHeap(A, B)
#
#  Other APPL Procedures Called: 
#
#  Date: September 8, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
CreateHeap := proc(A :: list, B :: list) 
global H, Probs:
local n, i:

#
#  Create a left complete tree H containing the sums to be sorted and
#  create a left complete tree Probs that corresponds to each sum in H
#
n := nops(A) + 1:
H := array(1 .. n, [-1 * 10 ^ 6, op(A)]):
Probs := array(1 .. n, [0, op(B)]):
#
#  In the following for loop, do until i = 2, since i = 2 is the root
#  of the tree
#
for i from ceil(n / 2) by -1 to 2 do
  PercolateDown(H, Probs, i, n):
od:
return(H, Probs):

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: createminheap2.map
#
#  Procedure Name: CreateMinHeap(A)
#
#  Other APPL Procedures Called: 
#
#  Date: September 16, 2000
#
#  Purpose: Create minimum heap for just 2 elements
#
#  Arguments: 
#
#  Algorithm:
CreateMinHeap := proc(A :: array) 
global H, Mimic:

#
#  Create a left complete tree H for two elements
#
H := array(1 .. 3, [-1 * 10 ^ 6, A[1, 2], A[2, 1]]):
Mimic := array(1 .. 3, [-1 * 10 ^ 6, [1, 2], [2, 1]]):
# print(`H is`, eval(H)):
# print(`Mimic is`, eval(Mimic)):
PercolateDownHeap(2, 3):
return(eval(H), eval(Mimic)):

end:
#11111111112222222222333333333344444444445555555555666666666677777777778888888888#
#  Filename: crit1.map
#
#  Procedure name: CriticalPoint(X, st) 
#
#  Other APPL Procedures Called: CDF
#   
#  Date: May 30, 1999
#
#  Purpose: CriticalPoint is a procedure that returns the critical point of a List
#           of Lists specificed pdf
#
#  Arguments: 
#
#  Algorithm:
#
CriticalPoint := proc(fX, lower)
local i, nsegments, newlower, critpt, j, pt, X, x;
if (whatttype(evalf(lower)) = string) then
  assume(lower < 1);
  assume(lower > 0);
fi;
# print(`In procedure CriticalPoint`):
X := CDF(fX);
# print(X):
nsegments := nops(X[1]);
# print(nsegments):
if (nsegments = 1) then
  # 6/28/2007, threw in an evalf() around lower and set to newlower
  newlower := evalf(lower):
  # print(newlower):
  critpt := fsolve(X[1][1](pt) = newlower, pt = X[2][1] .. X[2][2]);
  # critpt2 := solve(X[1][1](pt) = lower, pt);
  # print(critpt2);
  # 6/23/2007: Trying to prevent CriticalPoint from passing
  # back just the expression fsolve() because it can't solve
  # redirect fsolve() to try again and give it a region to
  # look in
  # SEARCH 
  if whattype(critpt) = function then
    # print(`try something else`);
    j := 0:
    while (whattype(critpt) = function and j < 100) do
      critpt := fsolve(X[1][1](pt) = lower, pt = 5 * j .. X[2][2]);
      j := j + 1:
    od:
  fi:
else
  for i from 1 to nsegments do
    # print(i);
    if (lower >= evalf(limit(X[1][i](x), x= X[2][i])) and lower <=             evalf(limit(X[1][i](x), x = X[2][i + 1])) ) then 
      critpt := fsolve(X[1][i](pt) = lower, pt = X[2][i] .. X[2][i + 1]);
      # critpt := solve(X[1][i](pt) = lower, pt);
      break;
    fi;
  od;
fi;
RETURN(critpt);

end:

#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: datasets1.map
#
DataSets := proc()
global BallBearing, HorseKickFatalities, Hurricane, MP6, MP6Censor, RatControl, RatTreatment, USSHalfBeak:
local i:

# Leemis, Reliability text
BallBearing :=[17.88, 28.92, 33.00, 41.52, 42.12, 45.60, 48.48, 51.84, 51.96, 54.12, 55.56, 67.80, 68.64, 68.64, 68.88, 84.12, 93.12, 98.64, 105.12, 105.84, 127.92, 128.04, 173.40]:

# Larsen & Marx, 2nd Edition, page 201
HorseKickFatalities := [seq(0, i = 1 .. 109), seq(1, i = 1 .. 65), seq(2, i = 1 .. 22), seq(3, i = 1 .. 3), 4]:

# Larsen & Marx
Hurricane :=[31.00, 2.82, 3.98, 4.02, 9.50, 4.50, 11.40, 10.71, 6.31, 4.95, 5.64, 5.51, 13.40, 9.72, 6.47, 10.16, 4.21, 11.60, 4.75, 6.85, 6.25, 3.42, 11.80, 0.80, 3.69, 3.10, 22.22, 7.43, 5.00, 4.58, 4.46, 8.00, 3.73, 3.50, 6.20, 0.67]:

# Leemis, Reliability text
MP6 := [6, 6, 6, 6, 7, 9, 10, 10, 11, 13, 16, 17, 19, 20, 22, 23, 25, 32, 32, 34, 35]:
MP6Censor := [1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0]:

# A reliability book Larry loaned me -- it's on my bookshelf
USSHalfBeak := [1382, 2990, 4124, 6827, 7472, 7567, 8845, 9450, 9453, 9794, 10848, 11528, 11993, 11993, 12300, 15058, 15413, 16497, 17315, 17352, 17632, 18122, 19067, 19172, 19299, 19360, 19686, 19940, 19944, 20121, 20132, 20431, 20525, 21057, 21061, 21309, 21310, 21378, 21391, 21456, 21461, 21603, 21658, 21688, 21750, 21815, 21820, 21822, 21888, 21930, 21943, 21946, 22181, 22311, 22634, 22635, 22669, 22691, 22846, 22947, 23149, 23305, 23491, 23526, 23774, 23791, 23822, 24006, 24006, 24286, 25000, 25000, 25010, 25048, 25268, 25400, 25500, 25518]:

# Efron & Tibshirani, page 11
RatControl := [10, 27, 30, 40, 46, 51, 52, 104, 146]:
RatTreatment := [16, 23, 38, 94, 99, 141, 197]:

return:
end:


#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: deletemaxheap1.map
#  
#  Procedure Name: DeleteMaxHeap(H, i, n)
#
#  Other APPL Procedures Called: 
#
#  Date: September 8, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
DeleteMaxHeap := proc(H :: array, Probs :: array, n) 
local Temp:

Temp := H[2]:
# print(`Temp is`, Temp):
H[2] := H[n]:
# print(`New elt 2 is`, NewH[2]):
H[n] := Temp:
# print(`New last elt is`, NewH[n]):
# print(`n is`, n):
Temp := Probs[2]:
Probs[2] := Probs[n]:
Probs[n] := Temp:
# print(`NewH is`, NewH):
PercolateDown(H, Probs, 2, n - 1):
return(H, Probs):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: determinant1.map  
#  
#  Procedure Name: Determinant(Matrix) 
#
#  Other APPL Procedures Called:  Product, Convolution  
#
#  Date: April 13, 2000 
#
#  Purpose: Returns the distribution of the determinant of a 2x2 matrix #  with random variables as elements
#  
#  Arguments: Matrix: A 2x2 array of random variables
#
#  Algorithm:
#    1.  Check to see if the matrix is a 2x2 square matrix 
#    2.  Compute the distribution of the determinant 
#        to contain all 1's to indicate the data values are uncensored
#
Determinant := proc(Matrix) 
local i, j, NumSubLists, Term1, Term2, Deter, g:
#
#  Check for the appropriate number of arguments: 1 
#
if (nargs <> 1) then
  print(`ERROR(Determinant): This procedure requires one argument:`):
  print(`a matrix of random variables`):
  RETURN():
fi:
#
#  Check that the matrix is a 2x2 matrix 
#

#
#  Check that the RV X is given in a list of 3 lists format
#
for i from 1 to 2 do
  for j from 1 to 2 do
    NumSubLists := nops(Matrix[i, j]):
    if (NumSubLists <> 3) then
      print(`ERROR(Determinant):`):
      print(`The RV X must be in a list of 3 lists format`):
      RETURN():
    fi:
  od:
od:

Term1 := Product(Matrix[1, 1], Matrix[1, 2]):
# print(`******************************************`):
# print(`Term1 is:`):
# print(Term1):
# print(`******************************************`):
Term2 := Product(Matrix[2, 1], Matrix[1, 2]):
g := [[x -> -x], [-infinity, infinity]]:
Term2 := Transform(Term2, g):
# print(`******************************************`):
# print(`Term2 is:`):
# print(Term2):
# print(`******************************************`):
Deter := Convolution(Term1, Term2):

RETURN(Deter):
end:#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: difference1.map
#
#  Procedure Name: Difference(X, Y)
#
#  Other APPL Procedures Called: PDF
#
#  Date: February 7, 2001
#
#  Purpose: 
#
#  Arguments: X: Random variable
#             Y: Random variable
# 
#  Algorithm:
#    1. Check for the appropriate number of arguments
#    2. Check that the RV X is in the list of 3 lists format
#    3. Convert X to PDF form if not already in that form
#    4. Check whether the RV X is Continuous or Discrete
#    5. If the RV X is continuous, then compute its expected value
#    6. If the RV X is discrete, then determine if the support of X is
#       in the "dot" or "no dot" form
#    7. If the random variable X is in the discrete "dot" case, first
#       call procedure Convert(X) to convert its support to the
#       *standard dot* support format: 
#       [anything .. anything, incremented by k, transformed by h(x)]
#    8. Transform the discrete dot pdf f(x) by h(x)
#    9. Find the expected value of the transformed pdf
#   10. Similarly, if the random variable X is in the discrete "no dot"
#       case, first call procedure Convert(X) to convert its support to
#       the *standard no dot* pdf/support format:        
#       [frac1, frac2, frac3, ... , fracN], [a1, a2, a3, ... , aN]
#
Difference := proc(X :: list(list), Y :: list(list))
local NumListsX, NumListsY, fX, fY, NegY, DiffRV:

#
#  Check for the appropriate number of arguments
#
if (nargs <> 2) then
  print(`ERROR(Difference): This procedure requires 2 arguments`):
  print(`A random variable X and a random variable Y`):
  RETURN():
fi:
#
#  Check that the RV X is in the list of 3 lists format
#
NumListsX := nops(X):
NumListsY := nops(Y):
if (NumListsX <> 3) or (NumListsY <> 3) then
  print(`ERROR(Difference): X  and Y must be in a list of 3`):
  print(`sublists format`):
  RETURN():
fi:
#
#  Convert X to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
    fX := X:
else
  if ((X[3][2] = "CDF") or
      (X[3][2] = "CHF") or
      (X[3][2] = "HF") or
      (X[3][2] = "IDF") or
      (X[3][2] = "SF")) then
    fX := PDF(X):
  else
    print(`ERROR(Difference): The RV X must be given as`):
    print(`PDF, CDF, SF, HF, CHF, or IDF`):
    RETURN():
  fi:
fi:
if (Y[3][2] = "PDF") then
    fY := Y:
else
  if ((Y[3][2] = "CDF") or
      (Y[3][2] = "CHF") or
      (Y[3][2] = "HF") or
      (Y[3][2] = "IDF") or
      (Y[3][2] = "SF")) then
    fY := PDF(Y):
  else
    print(`ERROR(Difference): The RV Y must be given as`):
    print(`PDF, CDF, SF, HF, CHF, or IDF`):
    RETURN():
  fi:
fi:

NegY := Transform(Y, [[x -> -x], [-infinity, infinity]]):
# print(NegY):
DiffRV := Convolution(X, NegY):

RETURN(DiffRV):
end:#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: discdist1.map
#
#  Procedure names:  BenfordRV
#                    BernoulliRV
#                    BingoCoverRV
#                    BinomialRV
#                    BirthdayRV
#                    GeometricRV
#                    NegativeBinomialRV
#                    PoissonRV
#                    UniformDiscreteRV
#
#  Other APPL Procedures Called: None
#
#  Date:  September 12, 2000
#
#  Purpose:  Define the common parametric discrete univariate
#            probability distributions shown below:
#
#  NOTE: For each distribution, x is an integer.
#
#  Distribution    Support        Parameters    Parameter Space
#  ------------    -------        ----------    ---------------
#  Benford         x=1,2,...,9    none          none
#  Bernoulli       
#  BingoCover	 x=24,25,...,75 none		none
#  Binomial        0<=x<=n        n, p          n: pos int; 0 < p < 1
#  Birthday		 x=1,2,...,365  none          none
#  Geometric       x >= 1         p             0 < p < 1
#  Hypergeometric
#  NegativeBinomial
#  Poisson         x >= 0         lambda        lambda > 0
#  UniformDiscrete
#  
#  Arguments:  The parameters of the distribution of the random
#              variable
#
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Check parameter space when parameters are numeric
#    3.  Check to see that the parameters are finite
#    4.  Make assumptions about any symbolic parameters
#    5.  Assign a list of lists in the following format:
#        [[f(x)], [support], ["Discrete", "XXX"]]
#        where XXX is one of the following:  PDF, CDF, IDF, SF, HF, CHF
#    6.  Return the list of lists
# 
#  Note:  Could define a type in startup about p being between 0 and 1
#

#
#  Benford distribution
#
BenfordRV := proc()
local ListOfLists, x:
if (nargs <> 0) then
  print(`ERROR(BenfordRV): This procedure requires no arguments`):
  return:
fi:
readlib(log10):
ListOfLists := [[unapply(log[10](1 + 1 / x), x)], [1 .. 9], 
    ["Discrete", "PDF"]]:
return(ListOfLists):
end:

#
#  Bernoulli distribution
#
BernoulliRV := proc(p)
local ListOfLists, x:
if (nargs <> 1) then
  print(`ERROR(BernoulliRV): This procedure requires 1 argument`):
  return:
fi:
if (is(p <= 0) or is(p >= 1)) then
  print(`ERROR(BernoulliRV): The parameter p must be between 0 and 1`):
  return:
fi:
if type(p, infinity) then
  print(`ERROR(BernoulliRV): p must be finite`):
  return:
fi:
if type(p, symbol) then
  assume(p, RealRange(Open(0), Open(1))):
fi:
ListOfLists := [[1 - p, p], [0, 1], ["Discrete", "PDF"]]:
return(ListOfLists):
end:


#
#  BingoCover distribution
#
BingoCoverRV := proc(numrows, numballs)
local ListOfLists, j, k, x:
#
# Set j = numrows and k = numballs. If no parameters are given, then
# set j = 5 and k = 75 as in a standard bingo card
#
if (nargs = 0) then
  j := 5:
  k := 75: 
#
# If two arguments are given, make sure j is an odd integer >= 3, k is a
# positive integer, and 0 = k mod j
#
elif (nargs = 2) then
  j := numrows:
  k := numballs:
  if type(j, symbol) then
    assume(j, posint):
    additionally(j >= 3):
    additionally(j, odd):
  fi:
  if not(is(j, posint)) then
    print(`ERROR(BingoCoverRV): j must be a positive integer`):
    return:
  fi:
  if not(is(j, odd) and is(j >= 3)) then
    print(`ERROR(BingoCoverRV): j must be an odd integer >= 3`):
    return:
  fi:
  if type(k, symbol) then
    assume(k, posint):
    additionally(k >= j ^ 2):
    additionally(k mod j = 0):
  fi:
  if not(is(k, posint)) then
    print(`ERROR(BingoCoverRV): k must be a positive integer`):
    return:
  fi:
  if not(is(k >= j ^ 2)) then
    print(`ERROR(BingoCoverRV): This procedure requires k >= j^2`):
    return:
  fi:
  if not(is(k mod j = 0)) then
    print(`ERROR(BingoCoverRV): k mod j must be 0`):
    return:
  fi:
else    
  print(`ERROR(BingoCoverRV): This procedure requires no arguments or`):
  print(`or 2 arguments`):
  return:
fi:
with(combinat, binomial):
ListOfLists := [[unapply((binomial(j ^ 2 - 1, j ^ 2 - 2) * 
    binomial(k - (j ^ 2 - 1), x - (j ^ 2 - 1)) / binomial(k, x - 1)) * 
    1 / (k - (x - 1)), x)], [j ^ 2 - 1 .. k], ["Discrete", "PDF"]]:
return(ListOfLists):
end:

#
#  Binomial distribution
#
BinomialRV := proc(n, p :: {constant, symbol})
local ListOfLists, x:
# NOTE: binomial(*, *) is only guaranteed to work if both *'s are
# NUMERIC
if (nargs <> 2) then
  print(`ERROR(BinomialRV): This procedure requires 2 arguments`):
  return:
fi:
# try something with RealRange here
if (is(p <= 0) or is(p >= 1)) then
  print(`ERROR(BinomialRV): The parameter p must be between 0 and 1`):
  return:
fi:
if (type(p, infinity) or type(n, infinity)) then
  print(`ERROR(BinomialRV): Both parameters must be finite`):
  return:
fi:
if type(p, symbol) then
  assume(p, RealRange(Open(0), Open(1))):
fi:
if type(n, symbol) then
  assume(n, posint):
fi:
ListOfLists := [[unapply(n! / ((n - x)! * x!) * p^x * (1 - p) ^ (n - x),
     x)], [0 .. n], ["Discrete", "PDF"]]:
return(ListOfLists):
end:

#
#  Birthday distribution:  Let Y := BirthdayRV(); Then Y = the number of
#  the first student whose birthday matches one of the previous students
#
BirthdayRV := proc()
local ListOfLists, x:
if (nargs <> 0) then
  print(`ERROR(BirthdayRV): This procedure requires no arguments`):
  return:
fi:
ListOfLists := [[unapply(x * 364! / ((365 ^ x) * (365 - x)!), x)],  
    [1 .. 365], ["Discrete", "PDF"]]:
return(ListOfLists):
end:


#
#  Geometric distribution
#
GeometricRV := proc(p)
local ListOfLists, x:
if (nargs <> 1) then
  print(`ERROR(GeometricRV): This procedure requires 1 argument`):
  return:
fi:
if (is(p <= 0) or is(p >= 1)) then
  print(`ERROR(GeometricRV): The parameter p must be between 0 and 1`):
  return:
fi:
if type(p, infinity) then
  print(`ERROR(GeometricRV): The parameter p must be finite`):
  return:
fi:
if type(p, symbol) then
  assume(p, RealRange(Open(0), Open(1))):
fi:
ListOfLists := [[unapply(p * (1 - p)^(x - 1), x)], [1 .. infinity],
    ["Discrete", "PDF"]]:
return(ListOfLists):
end:

#
#  Hypergeometric distribution
#
HypergeometricRV := proc(M, r, n)
local ListOfLists, x, lo, hi:
#  NOTE: binomial(*, *) only "works" if both *'s are numeric
#
#  M used as parameter instead of N since N is an assigned name and 
#  can't make assumptions about it later
#
if (nargs <> 3) then
  print(`ERROR(HypergeometricRV): This procedure requires 3`):
  print(`arguments`):
  return:
fi:
if type(M, symbol) then
  assume(M, posint):
fi:
if type(r, symbol) then
  assume(r, posint):
fi:
if type(n, symbol) then
  assume(n, posint):
fi:
lo := max(0, n - M + r):
# print(`lo is`, lo):
hi := min(r, n):
# print(`hi is`, hi):
ListOfLists := [[unapply(((r! / ((r - x)! * x!)) * ((M - r)! / 
    ((M - r - n + x)! * (n - x)!))) / (M! / ((M - n)! * n!)), x)], 
    [lo .. hi], ["Discrete", "PDF"]]:
return(ListOfLists):
end:

#
#  Negative Binomial distribution
#
NegativeBinomialRV := proc(r, p)
local ListOfLists, x:
if (nargs <> 2) then
  print(`ERROR(NegativeBinomialRV): This procedure requires 1`):
  print(`argument`):
  return:
fi:
if (is(p <= 0) or is(p >= 1)) then
  print(`ERROR(NegativeBinomialRV): The parameter p must be between`):
  print(`0 and 1`):
  return:
fi:
if type(p, infinity) then
  print(`ERROR(NegativeBinomialRV): The parameter p must be finite`):
  return:
fi:
if type(p, symbol) then
  assume(p, RealRange(Open(0), Open(1))):
fi:
ListOfLists := [[unapply(((x - 1)! / ((r - 1)! * (x - r)!)) * p ^ r * 
    (1 - p) ^ (x - r), x)], [r .. infinity], ["Discrete", "PDF"]]:
return(ListOfLists):
end:

#
#  Poisson distribution
#
PoissonRV := proc(lambda)
local ListOfLists, x:
if (nargs <> 1) then
  print(`ERROR(PoissonRV): This procedure requires 1 argument`):
  return:
fi:
if type(lambda, infinity) then
  print(`ERROR(PoissonRV): The parameter lambda must be finite`):
  return:
fi:
if type(lambda, symbol) then
  assume(lambda, positive):
fi:
ListOfLists := [[unapply(lambda ^ x * exp(-lambda) / x!, x)], 
    [0 .. infinity], ["Discrete", "PDF"]]:
return(ListOfLists):
end:

#
#  Uniform Discrete distribution
#
UniformDiscreteRV := proc(a, b, k)
local ListOfLists, incr, n, i:
if (nargs <> 2 and nargs <> 3) then
  print(`ERROR(UniformDiscreteRV): This procedure requires either`):
  print(`2 or 3 arguments`):
  return:
fi:
if is(b - a <= 0) then
  print(`ERROR(UniformDiscreteRV): "b" must be greater than "a"`):
  return:
fi:
if not(type(a, numeric)) or not(type(b, numeric)) then
  print(`ERROR(UniformDiscreteRV): "a" and "b" must be numeric`):
  return:
fi:
if (nargs = 3) then
  incr := k:
else
  incr := 1:
fi:
if not(type(incr, numeric)) then
  print(`ERROR(UniformDiscreteRV): "k" must be numeric`):
  return:
fi:
n := (b - a) / incr:
if not(type(n, posint)) then
  print(`ERROR(UniformDiscreteRV): "(b - a)" must be divisible by "k"`):
  return:
fi:
ListOfLists := [[seq( 1 / (n + 1), i = 1 .. n + 1)], [seq(a + i * incr, 
    i = 0 .. n)], ["Discrete", "PDF"]]:
return(ListOfLists):
end:

#
#  Zipf distribution
#
ZipfRV := proc(alpha)
local ListOfLists, denom, k, c:
if (nargs <> 1) then
  print(`ERROR(ZipfRV): This procedure requires 1 argument`):
  return:
fi:
if not(type(alpha, numeric)) then
  print(`ERROR(ZipfRV): "alpha" must be numeric`):
  return:
fi:
if is(alpha <= 0) then
  print(`ERROR(ZipfRV): "alpha" must be positive`):
  return:
fi:
denom := sum(((1 / k) ^ (alpha + 1)), k = 1 .. infinity):
c := 1 / denom:
ListOfLists := [[unapply(c / x ^ (alpha + 1), x)], [1 .. infinity],
    ["Discrete", "PDF"]]:
return(ListOfLists):
end:

#11111111112222222222333333333344444444445555555555666666666677777777778888888888#
#  Filename: display1.map
#  
#  Procedure Name: Display(X)
#
#  Other APPL Procedures Called:  None  
#
#  Date:  June 1, 1999
#
#  Purpose:  Prints the List of List random variable X in a more readable format
#            given a List of Lists specificed PDF
#
#  Arguments: X: A continuous random variable
#
#  Algorithm:
#
Display := proc(X)
local i, bb, nsegments, fnseq;

nsegments := nops(X[1]);
print(`This random variable is currently represented as follows:`);
if(X[3][2] = "PDF") then
  bb:= ` PDF`; 
  print(X[3][1], bb);
  if(X[2][1] <> -infinity) then
    fnseq := x < X[2][1], 0;
  else
    fnseq := NULL;
  fi;
  for i from 1 to nsegments do
    fnseq := fnseq, x < X[2][i + 1], X[1][i](x)
  od;
  # print(`the fn seq`, fnseq);
  convert(If(fnseq), piecewise);

elif(X[3][2] = "CDF") then
  bb := ` CDF`;
  print(X[3][1], bb);
  if(X[2][1] <> -infinity) then
    fnseq := x < X[2][1], 0;
  else
    fnseq := NULL;
  fi;
  for i from 1 to nsegments do
    fnseq := fnseq, x < X[2][i + 1], X[1][i](x)
  od;
  if(X[2][nsegments + 1] <> infinity) then
    fnseq := fnseq, x > X[2][nsegments + 1], 1;
  fi;
  # print(`the fn seq`, fnseq);
  convert(If(fnseq), piecewise);
 
elif(X[3][2] = "SF") then
  bb:= ` SF`; 
  print(X[3][1], bb);
  if(X[2][1] <> -infinity) then
    fnseq := x < X[2][1], 1;
  else
    fnseq := NULL;
  fi;
  for i from 1 to nsegments do
    fnseq := fnseq, x < X[2][i + 1], X[1][i](x)
  od;
  if(X[2][nsegments + 1] <> infinity) then
    fnseq := fnseq, x > X[2][nsegments + 1], 0;
  fi;
  # print(`the fn seq`, fnseq);
  convert(If(fnseq), piecewise);

elif(X[3][2] = "HF") then
  bb:= ` HF`; 
  print(X[3][1], bb);
  if(X[2][1] <> -infinity) then
    fnseq := x < X[2][1], 0;
  else
    fnseq := NULL;
  fi;
  for i from 1 to nsegments do
    fnseq := fnseq, x < X[2][i + 1], X[1][i](x)
  od;
  # print(`the fn seq`, fnseq);
  convert(If(fnseq), piecewise);

elif(X[3][2] = "CHF") then
  bb:= ` CHF`; 
  print(X[3][1], bb);
  if(X[2][1] <> -infinity) then
    fnseq := x < X[2][1], 0;
  else
    fnseq := NULL;
  fi;
  for i from 1 to nsegments do
    fnseq := fnseq, x < X[2][i + 1], X[1][i](x)
  od;
  if(X[2][nsegments + 1] <> infinity) then
    fnseq := fnseq, x > X[2][nsegments + 1], 1;
  fi;
  # print(`the fn seq`, fnseq);
  convert(If(fnseq), piecewise);

elif( X[3][2] = "IDF") then
  bb:= ` IDF`; 
  print(X[3][1], bb);
  if(X[2][1] <> -infinity) then
    fnseq := x < X[2][1], 0;
  else
    fnseq := NULL;
  fi;
  for i from 1 to nsegments do
    fnseq := fnseq, x < X[2][i + 1], X[1][i](x)
  od;
  if(X[2][nsegments + 1] <> infinity) then
    fnseq :=  fnseq, x > X[2][nsegments + 1], 1;
  fi;
  # print(`the fn seq`, fnseq);
  convert(If(fnseq), piecewise);

else
  print(`error, a non-list of list specified`);
fi;

end:

#11111111112222222222333333333344444444445555555555666666666677777777778888888888#
#  Filename: dn1.map
# 
#  Procedure Names:  D1, D2, D3, ... , D10
#
#  Other APPL Procedures Called: None
#  
#  Date:  June 7, 1999
#
#  Purpose: 
#
#  Arguments: None
#
#  Algorithm:
#
D1 := [[proc (x) options operator, arrow; 2*x-1 end], [1/2, 1], ["Continuous", "CDF"]]:

D2 := [[proc (x) options operator, arrow; 1/2*(4*x-1)^2 end, proc (x) options operator, arrow; -1+4*x-2*x^2 end], [1/4, 1/2, 1], ["Continuous", "CDF"]]:

D3 := [[proc (x) options operator, arrow; 2/9*(6*x-1)^3 end, proc (x) options operator, arrow; -8/3*x+14*x^2-12*x^3 end, proc (x) options operator, arrow; -1+10/3*x-4*x^3+2*x^2 end, proc (x) options operator, arrow; -1+6*x-6*x^2+2*x^3 end], [1/6, 1/3, 1/2, 2/3, 1], ["Continuous", "CDF"]]:

D4 := [[proc (x) options operator, arrow; 3/32*(8*x-1)^4 end, proc (x) options operator, arrow; 3/8-9/2*x+21/2*x^2-48*x^4+24*x^3 end, proc (x) options operator, arrow; 3/8-63/8*x+75/2*x^2-48*x^3+16*x^4 end, proc (x) options operator, arrow; -1+37/8*x+3/2*x^2-10*x^3+6*x^4 end, proc (x) options operator, arrow; -12*x^2+8*x-1+8*x^3-2*x^4 end], [1/8, 1/4, 3/8, 1/2, 3/4, 1], ["Continuous", "CDF"]]:

D5 := [[proc (x) options operator, arrow; 24/625*(10*x-1)^5 end, proc (x) options operator, arrow; -96/625+672/125*x-1464/25*x^2+240*x^3-288*x^4 end, proc (x) options operator, arrow; 424/5*x^3+12*x^2-168/25*x+336/625-240*x^4+160*x^5 end, proc (x) options operator, arrow; -728/125*x+224/5*x^2-456/5*x^3+74*x^4-20*x^5 end, proc (x) options operator, arrow; -1+522/125*x+24/5*x^2-56/5*x^3+12*x^5-6*x^4 end, proc (x) options operator, arrow; -92/5*x^3+12/25*x^2+738/125*x-1+22*x^4-8*x^5 end, proc (x) options operator, arrow; 20*x^3-20*x^2+10*x-1-10*x^4+2*x^5 end], [1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 4/5, 1], ["Continuous", "CDF"]]:

D6 := [[proc (x) options operator, arrow; 5/324*(12*x-1)^6 end, proc (x) options operator, arrow; 10/27*x+235/9*x^2-1280/3*x^3+2360*x^4-4800*x^5+2880*x^6-5/81 end, proc (x) options operator, arrow; 145/27*x-35/1296-785/9*x^2+4240/9*x^3-2600/3*x^4+320*x^5+320*x^6 end, proc (x) options operator, arrow; 5/16-565/81*x+1525/54*x^2+515/9*x^3-1115/3*x^4+560*x^5-280*x^6 end, proc (x) options operator, arrow; 5/16-7645/648*x+775/9*x^2-1985/9*x^3+295*x^4-240*x^5+104*x^6 end, proc (x) options operator, arrow; -1+3371/648*x+175/36*x^2-185/9*x^3+32*x^5-20*x^6 end, proc (x) options operator, arrow; -1+4651/648*x-115/108*x^2-265/9*x^3+160/3*x^4-38*x^5+10*x^6 end, proc (x) options operator, arrow; -1+12*x-30*x^2+40*x^3-30*x^4+12*x^5-2*x^6 end], [1/12, 1/6, 1/4, 1/3, 5/12, 1/2, 2/3, 5/6, 1], ["Continuous", "CDF"]]:

D7 := [[proc (x) options operator, arrow; 720/117649*(14*x-1)^7 end, proc (x) options operator, arrow; -2880/7*x^4-128160/343*x^3-8640/2401*x+40320*x^7-43200*x^6+92160/7*x^5+8640/117649+20880/343*x^2 end, proc (x) options operator, arrow; 99840/49*x^4+15600/343*x^3+140400/16807*x-4480*x^7+11200*x^6-57600/7*x^5-31860/117649-176760/2401*x^2 end, proc (x) options operator, arrow; -15950/49*x^4+45040/343*x^3-120240/16807*x-1680*x^7+2120*x^6-3540/7*x^5+54540/117649+36240/2401*x^2 end, proc (x) options operator, arrow; -51950/49*x^4+60040/343*x^3-157740/16807*x+1008*x^7-2296*x^6+15660/7*x^5+54540/117649+73740/2401*x^2 end, proc (x) options operator, arrow; 3770/7*x^4-103000/343*x^3-153852/16807*x-168*x^7+468*x^6-4380/7*x^5+31512/343*x^2 end, proc (x) options operator, arrow; -150/7*x^4-6960/343*x^3+81446/16807*x-40*x^7+20*x^6-1+324/7*x^5+2700/343*x^2 end, proc (x) options operator, arrow; 710/49*x^4-11120/343*x^3+104486/16807*x+30*x^7-80*x^6-1+414/7*x^5+11220/2401*x^2 end, 
proc (x ) options operator, arrow; 5210/49*x^4-14870/343*x^3+141986/16807*x-12*x^7+58*x^6-1-786/7*x^5-7530/2401*x^2 end, proc (x) options operator, arrow; -70*x^4+70*x^3+14*x+2*x^7-14*x^6-1+42*x^5-42*x^2 end], [1/14, 1/7, 3/14, 2/7, 5/14, 3/7, 1/2, 4/7, 5/7, 6/7, 1], ["Continuous", "CDF"]]:

D8 := [[proc (x) options operator, arrow; 315/131072*(16*x-1)^8 end, proc (x) options operator, arrow; 6615/4096*x-138915/2048*x^2+49140*x^5-184275/16*x^4+80325/64*x^3+322560*x^8-161280*x^7-55440*x^6-315/32768 end, proc (x) options operator, arrow; -38745/16384*x+919485/8192*x^2-19215/524288-22785*x^5+300195/32*x^4-402465/256*x^3-35840*x^8+35840*x^7+10360*x^6 end, proc (x) options operator, arrow; 25795/4096*x-559265/4096*x^2-3115/524288+6020*x^5-105595/32*x^4+523005/512*x^3-11200*x^8+14560*x^7-9485*x^6 end, proc (x) options operator, arrow; -571655/65536*x+217315/16384*x^2+584395/1048576-5901/4*x^5-75705/128*x^4+475895/2048*x^3+6720*x^8-12096*x^7+7931*x^6 end, proc (x) options operator, arrow; -1240267/131072*x+35/128+430241/8192*x^2+60235/16*x^5-39795/32*x^4+102277/1024*x^3-1792*x^8+4928*x^7-11725/2*x^6 end, proc (x) options operator, arrow; -1031905/65536*x+35/128+156723/1024*x^2-35805/16*x^5+2765/2*x^4-603617/1024*x^3+256*x^8-1344*x^7+4739/2*x^6 end, proc (x) options 
operator, arrow; 375071/65536*x-1+8435/1024*x^2+1547/16*x^5-35/2*x^4-32865/1024*x^3+70*x^8-110*x^7-35/2*x^6 end, proc (x) options operator, arrow; 947017/131072*x-1+69335/16384*x^2+2919/32*x^5+10395/256*x^4-96355/2048*x^3-42*x^8+156*x^7-833/4*x^6 end, proc (x) options operator, arrow; 1273609/131072*x-1-93961/16384*x^2-8421/32*x^5+48195/256*x^4-123571/2048*x^3+14*x^8-82*x^7+805/4*x^6 end, proc (x) options operator, arrow; 16*x-1-56*x^2+112*x^5-140*x^4+112*x^3-2*x^8+16*x^7-56*x^6 end], [1/16, 1/8, 3/16, 1/4, 5/16, 3/8, 7/16, 1/2, 5/8, 3/4, 7/8, 1], ["Continuous", "CDF"]]:

D9 := [[proc (x) options operator, arrow; 4480/4782969*(18*x-1)^9 end, proc (x) options operator, arrow; 555520/531441*x-703360/59049*x^2+3207680/243*x^4-89600/4782969-2535680/6561*x^3+9067520/9*x^6-4444160/27*x^5-2938880*x^7+3225600*x^8 end, proc (x) options operator, arrow; -3365600/531441*x+7269920/59049*x^2-9699200/2187*x^4-4827200/6561*x^3-30365440/81*x^6+18914560/243*x^5+806400*x^7-752640*x^8+215040*x^9+500080/4782969 end, proc (x) options operator, arrow; 46340000/4782969*x-9682960/43046721-62515040/531441*x^2+27233360/6561*x^4+4669280/19683*x^3+804160/9*x^6-7171360/243*x^5-1420160/9*x^7+179200*x^8-107520*x^9 end, proc (x) options operator, arrow; 1120000/177147*x+3267040/43046721-92895040/531441*x^2-37843540/6561*x^4+29533280/19683*x^3-2242912/81*x^6+3270904/243*x^5+56000*x^7-76608*x^8+45696*x^9 end, proc (x) options operator, arrow; -1643264/177147*x+17812480/43046721+16411472/531441*x^2-7209524/6561*x^4+13801760/59049*x^3+849296/81*x^6-174776/729*x^5-244384/9*x^7+
30464*x^8-13440*x^9 end, proc (x) options operator, arrow; -57544816/4782969*x+17812480/43046721+9862720/177147*x^2-19041652/6561*x^4+17566528/59049*x^3-565712/27*x^6+2502808/243*x^5+232288/9*x^7-17664*x^8+4992*x^9 end, proc (x) options operator, arrow; -60169328/4782969*x+9157696/59049*x^2+1434944/729*x^4-41500928/59049*x^3+16408/3*x^6-2859920/729*x^5-43232/9*x^7+2234*x^8-372*x^9 end, proc (x) options operator, arrow; 25924114/4782969*x-1+654640/59049*x^2-34720/729*x^4-1820000/59049*x^3+280/3*x^6+79408/729*x^5-1760/9*x^7-70*x^8+140*x^9 end, proc (x) options operator, arrow; 10508038/1594323*x-1+4491760/531441*x^2-42980/6561*x^4-910000/19683*x^3-9632/81*x^6+13412/81*x^5-568/3*x^7+294*x^8-112*x^9 end, proc (x) options operator, arrow; 13120774/1594323*x-1+1879024/531441*x^2+537628/6561*x^4-1272880/19683*x^3-35840/81*x^6+10052/81*x^5+1504/3*x^7-266*x^8+56*x^9 end, proc (x) options operator, arrow; 52539010/4782969*x-1-4709320/531441*x^2+2016644/6561*x^4-4759832/59049*x^3+43736/
81*x^6-389732/729*x^5-2936/9*x^7+110*x^8-16*x^9 end, proc (x) options operator, arrow; 18*x-1-72*x^2-252*x^4+168*x^3-168*x^6+252*x^5+72*x^7-18*x^8+2*x^9 end], [1/18, 1/9, 1/6, 2/9, 5/18, 1/3, 7/18, 4/9, 1/2, 5/9, 2/3, 7/9, 8/9, 1], ["Continuous", "CDF"]]:

D10:= [[proc (x) options operator, arrow; 3715891200*(x-1/20)^10 end, proc (x) options operator, arrow; -17577/100000000+14742/125*(x-1/20)^4+1701/500000*x-2658096/125*(x-1/20)^5-20979/50000*(x-1/20)^2+63866880*(x-1/20)^9+10206/625*(x-1/20)^3+9815904/25*(x-1/20)^6-14079744*(x-1/20)^8-3773952/5*(x-1/20)^7-58060800*(x-1/20)^10 end, proc (x) options operator, arrow; -347634/625*(x-1/20)^4-87003/500000*x+176043/20000000+6988464/125*(x-1/20)^5+3094497/250000*(x-1/20)^2-7526400*(x-1/20)^9-766962/3125*(x-1/20)^3-9963072/25*(x-1/20)^6+1983744*(x-1/20)^8+3354624/5*(x-1/20)^7+6451200*(x-1/20)^10 end, proc (x) options operator, arrow; 576009/125*(x-1/20)^4+11425113/10000000*x-25022487/400000000-4827816/125*(x-1/20)^5-13149297/400000*(x-1/20)^2+698880*(x-1/20)^9+279909/3125*(x-1/20)^3-806400*(x-1/20)^10+2954448/25*(x-1/20)^6-189504*(x-1/20)^8-576576/5*(x-1/20)^7 end, proc (x) options operator, arrow; -895671/625*(x-1/20)^4-7321923/50000000*x+586360257/10000000000-37343376/3125*(x-1/20)^
5-97325109/2000000*(x-1/20)^2-591360*(x-1/20)^9+10861641/15625*(x-1/20)^3+419328*(x-1/20)^10+9939636/125*(x-1/20)^6+2205504/5*(x-1/20)^8-1157184/5*(x-1/20)^7 end, proc (x) options operator, arrow; -53315913/50000*(x-1/20)^4-2264889459/400000000*x+32391039681/80000000000+1011969/3125*(x-1/20)^5+76585131/1600000*(x-1/20)^2+95424*(x-1/20)^9+26202267/250000*(x-1/20)^3-77952*(x-1/20)^10+1224657/125*(x-1/20)^6-114408/5*(x-1/20)^8-446208/25*(x-1/20)^7 end, proc (x) options operator, arrow; -14030709/10000*(x-1/20)^4-2408216691/400000000*x+29524495041/80000000000+10083969/3125*(x-1/20)^5+2434189491/40000000*(x-1/20)^2-107328*(x-1/20)^9+13387419/250000*(x-1/20)^3+44928*(x-1/20)^10+724689/125*(x-1/20)^6+503064/5*(x-1/20)^8-223488/5*(x-1/20)^7 end, proc (x) options operator, arrow; -545825343/800000*(x-1/20)^4-4693484517/1280000000*x+54707994171/1280000000000+578833353/100000*(x-1/20)^5+47753233407/640000000*(x-1/20)^2+30876*(x-1/20)^9-148612383/800000*(x-1/20)^3-8712*(x-1/20)^10-
38285793/2000*(x-1/20)^6-457983/10*(x-1/20)^8+945621/25*(x-1/20)^7 end, proc (x) options operator, arrow; 1744264641/800000*(x-1/20)^4-21319938937/6400000000*x-138565534149/1280000000000-577221687/100000*(x-1/20)^5+67080586239/640000000*(x-1/20)^2-5476*(x-1/20)^9-2454337947/4000000*(x-1/20)^3+1528*(x-1/20)^10+22269471/2000*(x-1/20)^6+113409/10*(x-1/20)^8-356907/25*(x-1/20)^7 end, proc (x) options operator, arrow; 3868053/1600000*(x-1/20)^4+17949962129/2560000000*x-2604380589873/2560000000000+37915731/200000*(x-1/20)^5+1152305973/256000000*(x-1/20)^2+266*(x-1/20)^9-392222733/8000000*(x-1/20)^3-252*(x-1/20)^10-372939/4000*(x-1/20)^6+5481/20*(x-1/20)^8-717/2*(x-1/20)^7 end, proc (x) options operator, arrow; 51596601/800000*(x-1/20)^4+50216886467/6400000000*x-1287808038009/1280000000000+15172353/100000*(x-1/20)^5-277935651/640000000*(x-1/20)^2-532*(x-1/20)^9-218737701/4000000*(x-1/20)^3+168*(x-1/20)^10-706839/2000*(x-1/20)^6+5229/10*(x-1/20)^8+687/25*(x-1/20)^7 end, proc (x) options 
operator, arrow; 123478047/800000*(x-1/20)^4+57109569719/6400000000*x-1264494550539/1280000000000-3779307/100000*(x-1/20)^5-5109942753/640000000*(x-1/20)^2+380*(x-1/20)^9-220108629/4000000*(x-1/20)^3-72*(x-1/20)^10-902853/2000*(x-1/20)^6-8253/10*(x-1/20)^8+4539/5*(x-1/20)^7 end, proc (x) options operator, arrow; 860690313/3200000*(x-1/20)^4+266881638251/25600000000*x-4865761405281/5120000000000-264951603/400000*(x-1/20)^5-56832817887/2560000000*(x-1/20)^2-133*(x-1/20)^9-504543891/16000000*(x-1/20)^3+18*(x-1/20)^10+7374213/8000*(x-1/20)^6+17253/40*(x-1/20)^8-15999/20*(x-1/20)^7 end, proc (x) options operator, arrow; -987963501/3200000*(x-1/20)^4-4237943235591/5120000000000+322687697779/25600000000*x+155994237/400000*(x-1/20)^5-152852067369/2560000000*(x-1/20)^2+19*(x-1/20)^9+2681615217/16000000*(x-1/20)^3-2*(x-1/20)^10-2736741/8000*(x-1/20)^6-3249/40*(x-1/20)^8+20577/100*(x-1/20)^7 end], [1/20, 1/10, 3/20, 1/5, 1/4, 3/10, 7/20, 2/5, 9/20, 1/2, 3/5, 7/10, 4/5, 9/10, 1], 
["Continuous", "CDF"]]:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: expect4.map
#
#  Procedure Name: ExpectedValue(X, [g])
#
#  Other APPL Procedures Called: PDF
#
#  Date: August 27, 2000
#
#  Purpose: Returns the expected value of g(X)
#           Ex: Suppose X ~ ExponentialRV(lambda); then E(X^2) would be
#           entered as ExpectedValue(X, g), where g is the procedure 
#           g := x -> x^2
#
#  Arguments: X: Random variable
#             g: A procedure
# 
#  Algorithm:
#    1. Check for the appropriate number of arguments
#    2. Check that the RV X is in the list of 3 lists format
#    3. Convert X to PDF form if not already in that form
#    4. Check whether the RV X is Continuous or Discrete
#    5. If the RV X is continuous, then compute its expected value
#    6. If the RV X is discrete, then determine if the support of X is
#       in the "dot" or "no dot" form
#    7. If the random variable X is in the discrete "dot" case, first
#       call procedure Convert(X) to convert its support to the
#       *standard dot* support format: 
#       [anything .. anything, incremented by k, transformed by h(x)]
#    8. Transform the discrete dot pdf f(x) by h(x)
#    9. Find the expected value of the transformed pdf
#   10. Similarly, if the random variable X is in the discrete "no dot"
#       case, first call procedure Convert(X) to convert its support to
#       the *standard no dot* pdf/support format:        
#       [frac1, frac2, frac3, ... , fracN], [a1, a2, a3, ... , aN]
#   11. Find the expected value of the pdf
#   12. Return the expected value of g(X)
#
ExpectedValue := proc(X :: list(list), g :: procedure)
local NumLists, fX, nsegments, Expect, gnew, i, SubList1, SubList2,
    Support, Lo, Hi, IncrBy, Transformation, TransfPDF, NextValue, n:
#
#  Check for the appropriate number of arguments
#
if ((nargs <> 1) and (nargs <> 2)) then
  print(`ERROR(ExpectedValue): This procedure requires`):
  print(`1 or 2 arguments:`):
  print(`A random variable X and an optional function g, such as`):
  print(`g := x -> x^2. If g is not provided, it is assumed to be`):
  print(`g := x -> x`):
  return:
fi:
#
#  Check that the RV X is in the list of 3 lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(ExpectedValue): X must be in a list of 3 lists format`):
  return:
fi:
#
#  Convert X to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
    fX := X:
elif member(X[3][2], {"CDF", "SF", "HF", "CHF", "IDF"}) then
  fX := PDF(X):
else
  print(`ERROR(ExpectedValue): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:

if (nargs = 1) then
  gnew := x -> x:
else
  gnew := g:
fi:
nsegments := nops(fX[1]):
Expect := 0:
#
#  If the RV X is continuous, compute its expected value
#
if (fX[3][1] = "Continuous") then
  for i from 1 to nsegments do
    Expect := Expect + int(gnew(x) * fX[1][i](x), x =                            fX[2][i] .. fX[2][i + 1]):
    # print(Expect):
    Expect := simplify(combine(Expect)):
    # print(Expect):
    # Expect := simplify(combine(Expect)):
    # print(Expect):
  od:
#
#  If the RV X is discrete, then determine if the support of X is in
#  the "dot" or "no dot" form
#
elif (fX[3][1] = "Discrete") then
  fX := Convert(fX):
  if (fX = false) then
    print(`ERROR(ExpectedValue): Discrete random variable X is`):
    print(`NOT in legal APPL form`):
    return(false):
  fi:
  SubList1 := fX[1]:
  SubList2 := fX[2]:
#
#  If the random variable X is in the discrete "dot" case, first call
#  procedure Convert(X) to convert its support to the *standard dot* 
#  support format: 
#  [anything .. anything, incremented by k, transformed by h(x)]
#
  if type(SubList2[1], range) then
    Support := SubList2[1]:
    Lo := lhs(Support):
    Hi := rhs(Support): 
    IncrBy := SubList2[-2]:
#
#  Transform the pdf f(x) by h(x)
#
    Transformation := unapply(SubList2[-1](x))(x):
    TransfPDF := subs(x = Transformation, unapply(SubList1(x))(x)):
    # print(`transfpdf is`, TransfPDF):
#
#  Find the expected value of the transformed pdf
#  Deal w/ support [a .. b, 1, x -> x] as a special case
#        
    if ((IncrBy = 1) and (ispoly(Transformation, linear, x, 'a0',
        'a1')) and (a0 = 0) and (a1 = 1)) then
      Expect := simplify(eval(sum(op(SubList1(x)) * gnew(x), 
          x = Lo .. Hi))):
    elif ((IncrBy = 1) and (ispoly(Transformation, linear, x, 'a0',
         'a1'))) then
      # print(`Lo is`, Lo):  print(`hi is`, Hi): 
      Expect := simplify(eval(sum(op(TransfPDF)* gnew(x), 
          x = Lo .. Hi))):
    else
      for i from Lo by IncrBy to Hi do
        NextValue := subs(x = i, op(TransfPDF)) * subs(x = subs(x = i,
            Transformation), unapply(gnew(x))(x)):
        Expect := simplify(Expect + NextValue):
      od:
    fi:
#
#  If the random variable X is in the discrete "no dot" case, call 
#  procedure Convert(X) to convert its support to the *standard no dot* 
#  pdf/support format:        
#  [frac1, frac2, frac3, ... , fracN], [a1, a2, a3, ... , aN]
#
  else
    n := nops(SubList1):
# added this for convolution mgf
    SubList1 := convert(SubList1, rational):
#
#  Find the expected value of the pdf f(x)
#      
    for i from 1 to n do
      NextValue := subs(x = SubList2[i], unapply(gnew(x))(x)) *
          SubList1[i]:
      Expect := simplify(Expect + NextValue):
    od:
  fi:
else
  print(`ERROR(ExpectedValue): The RV X must be either`):
  print(`Continuous or Discrete`):
  return:
fi:

return(simplify(Expect)):
end:

#
#  ExponentialKS distribution
#
ExponentialKSRV := proc(n :: posint)
local x,  ListOfLists:

if (nargs <> 1) then
  print(`ERROR(ExponentialKSRV): This procedure requires 1 argument`):
  RETURN():
fi:
if (is(n > 2)) then
  print(`ERROR(ExponentialKSRV): Cannot determine this distribution`):
  print(`for n larger than 2`):
  RETURN():
fi:

if n = 1 then
  print(`PDF for D_1 is degenerate`):
  return([[1], [1 - 1 / exp(1)], ["Discrete", "PDF"]]): 
elif n = 2 then
  ListOfLists := [[unapply(-(4 * x - 3) / ((2 * x - 1) * (x - 1)), x),
      unapply(-3 / ((2 * x + 1) * (x - 1)), x), 
      unapply(-1 / (x - 1), x)],
      [abs(-1 + exp(2 * (2 + ln(-1 / 4 + 1 / 4 * sqrt(1 + 16 * 
      exp(-2)))) / (ln(-1 / 4 + 1 / 4 * sqrt(1 + 16 * exp(-2))) * (-(2 + 
      ln(-1 / 4 + 1 / 4 * sqrt(1 + 16 * exp(-2)))) / ln(-1 / 4 + 1 / 4 * 
      sqrt(1 + 16 * exp(-2))) + 1)))), 
      abs(exp(2 * (2 + ln(1 / 2 - 1 / 2 * sqrt(1 - 4 * exp(-2)))) / 
      (ln(1 / 2 - 1 / 2 * sqrt(1 - 4 * exp(-2))) * (-(2 + ln(1 / 2 - 1 /
      2 * sqrt(1 - 4 * exp(-2)))) / ln(1 / 2 - 1 / 2 * sqrt(1 - 4 * 
      exp(-2))) + 1))) - 1 / 2), 
      1 / 2, 1 - 1 / exp(1)],
      ["Continuous", "PDF"]]:
  return(ListOfLists):
fi:
end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: exponentialvariate1.map
#  
#  Procedure Name: ExponentialVariate(lambda)
#
#  Other APPL Procedures Called: None
#
#  Date: June 1, 1999
#
#  Purpose: 
#
#  Arguments:
#
#  Algorithm:
#
ExponentialVariate := proc(lambda)
local variate:

variate := -1 / lambda * ln(rand() / 1000000000000):
return(evalf(variate)):

end:

#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: geometricosmean1.map  
#  
#  Procedure Name: GeometricOSMean(p) 
#
#  Other APPL Procedures Called: OrderStat, Mean
#
#  Date: April 16, 2000 
#
#  Purpose: Reproduce appendix from Margolin, Winokur, "Exact Moments
#  of the Order Statistics of the Geometric Distribution and their
#  Relation to Inverse Sampling and Reliability of Redundant Systems"
#  in the American Statistical Association Journal, 1967
#  
#  Arguments: p: A probability, 0 < p < 1
#
#  Algorithm:
#    1.  
#
GeometricOSMean := proc(p) 
local Index1, Index2, X, Rows, i, n, r:
global MeanMatrix:
#
#  Check for the appropriate number of arguments: 1 
#
if (nargs <> 1) then
  print(`ERROR(GeometricOSMean): This procedure requires 1 argument:`):
  print(`a probability value p`):
  RETURN():
fi:

Index1 := 1:
Index2 := 1:
X := GeometricRV(p):
Rows := [seq(0, i = 1 .. 8)]:
MeanMatrix := array(1 .. 5, 1 .. 8, [Rows, Rows, Rows, Rows, Rows]):
MeanMatrix[Index1, Index2] := Mean(OrderStat(X, 1, 1)):
for n from 5 by 5 to 20 do
  Index1 := Index1 + 1:  
  for r from 1 to 5 do
    MeanMatrix[Index1, Index2] := Mean(OrderStat(X, n, r)):
    Index2 := Index2 + 1:
  od:
  for r from 10 by 5 to 20 while (r <= n) do
    MeanMatrix[Index1, Index2] := Mean(OrderStat(X, n, r)):
    Index2 := Index2 + 1:
  od:
  Index2 := 1:
od:
RETURN(print(MeanMatrix)):
end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: geometricosvariance1.map  
#  
#  Procedure Name: GeometricOSVariance(p) 
#
#  Other APPL Procedures Called: OrderStat, Variance
#
#  Date: April 16, 2000 
#
#  Purpose: Reproduce appendix from Margolin, Winokur, "Exact Moments
#  of the Order Statistics of the Geometric Distribution and their
#  Relation to Inverse Sampling and Reliability of Redundant Systems"
#  in the American Statistical Association Journal, 1967
#  
#  Arguments: p: A probability, 0 < p < 1
#
#  Algorithm:
#    1.  
#
GeometricOSVariance := proc(p) 
local Index1, Index2, X, Rows, i, n, r:
global VarMatrix:
#
#  Check for the appropriate number of arguments: 1 
#
if (nargs <> 1) then
  print(`ERROR(GeometricOSVariance): This procedure requires one`):
  print(`argument: a probability value p`):
  RETURN():
fi:

Index1 := 1:
Index2 := 1:
X := GeometricRV(p):
Rows := [seq(0, i = 1 .. 8)]:
VarMatrix := array(1 .. 5, 1 .. 8, [Rows, Rows, Rows, Rows, Rows]):
VarMatrix[Index1, Index2] := Variance(OrderStat(X, 1, 1)):
for n from 5 by 5 to 20 do
  Index1 := Index1 + 1:  
  for r from 1 to 5 do
    VarMatrix[Index1, Index2] := Variance(OrderStat(X, n, r)):
    Index2 := Index2 + 1:
  od:
  for r from 10 by 5 to 20 while (r <= n) do
    VarMatrix[Index1, Index2] := Variance(OrderStat(X, n, r)):
    Index2 := Index2 + 1:
  od:
  Index2 := 1:
od:
RETURN(print(VarMatrix)):
end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: heapsort3.map
#
#  Procedure Name: HeapSort(A, B)
#
#  Other APPL Procedures Called: 
#
#  Date: September 8, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
HeapSort := proc(A :: list, B :: list) 
global H, Probs:
local n, i, SortedArray, SortedProbs:

CreateHeap(A, B):
# print(`H is`, eval(H)):
# print(`Probs is`, eval(Probs)):
n := nops(convert(H, list)):
# print(`n is`, n):
for i from n by -1 to 2 do
  DeleteMaxHeap(H, Probs, i):
  # print(eval(H)):
  # print(evalf(Probs)):
od:
SortedArray := array([seq(H[i], i = 2 .. n)]):
SortedArray := convert(evalf(SortedArray), list):
# print(`whattype(SortedArray)`, whattype(SortedArray)):
SortedProbs := array([seq(Probs[i], i = 2 .. n)]):
SortedProbs := convert(evalf(SortedProbs), list):
# print(`whattype(SortedProbs)`, whattype(SortedProbs)):
# return(eval(SortedArray), evalf(SortedProbs)):
return(SortedArray, SortedProbs):

end:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: hf6.map
#  
#  Procedure Name: HF(X, [x])
#
#  Other APPL Procedures Called: SF, PDF, Convert
#
#  Date: March 20, 2001
#
#  Purpose: HF is a procedure that:
#          (1) Returns the hazard function of a random variable X in the
#              APPL list of 3 sublists form if given only the one
#              argument X, or
#          (2) Returns the value Pr(X = x) / Pr(X >= x) if it is given
#              the optional argument x in addition to the RV X
#
#  Arguments: X: A continuous or discrete random variable; 
#             x (optional argument): A numeric value entered when
#                trying to determine Pr(X = x) / Pr(X >= x) 
#
#  Algorithm: 1. Perform error checking on user entered arguments
#             2. The HF of X is determined by sending it to its 
#                appropriate category, which is based on whether:
#                A. X is continuous or discrete
#                B. X is entered in its PDF, CDF, SF, HF, CHF, or IDF
#                   format 
#             3. If only 1 argument (the random variable X) is entered
#                by the user, return the hazard function of X in the
#                APPL list of 3 lists format 
#             4. If 2 arguments are provided, return the value 
#                Pr(X = x) / Pr(X >= x)
#
HF := proc(X :: list(list), st)
local numlists, nsegments, supp, fX, SX, hX, i, HHX, prob, Y, Range, lo, 
    hi, incr, transf, pdf, sf, hf, idf, pieces, numops, noceil,
    ceilpiece, solns, nsolns, cdf, val, invfound, j, idfval, losupp,
    hisupp, sublist1, n, hcum, notfound, count, k:
#
#  Check for the appropriate number of arguments
#
if ((nargs <> 1) and (nargs <> 2)) then
  print(`ERROR(HF): This procedure requires 1 or 2 arguments:`):
  print(`A random variable X and an optional argument x for`):
  print(`computing Pr(X = x) / Pr(X >= x)`):
  return:
fi:
#
#  Check that the RV X is in the list of 3 lists format
#
numlists := nops(X):
if (numlists <> 3) then
  print(`ERROR(HF): The RV X must be a list of 3 lists`):
  return:
fi:
#
#  Make sure X is given as a PDF, CDF, SF, HF, CHF, or IDF
#
if not(member(X[3][2], {"PDF", "CDF", "SF", "HF", "CHF", "IDF"})) then
  print(`ERROR(HF): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
#
#  If the RV X is continuous, find and return the HF of X
#
if (X[3][1] = "Continuous") then
  nsegments := nops(X[1]):
  supp := X[2]:
  if (X[3][2] = "PDF") then
    fX := X:
    SX := SF(X):
  elif (X[3][2] = "SF") then
    fX := PDF(X):
    SX := X:    
  elif (X[3][2] = "HF") then
    hX := X[1]:
  elif (X[3][2] = "CHF") then
    hX:=[]:
    for i from 1 to nsegments do
      HHX := unapply(simplify(diff(X[1][i](x), x)), x):
      hX := [op(hX), op([unapply(simplify(HHX(x)), x)])]: 
    od:
  else
    fX := PDF(X):
    # print(`fX is`, fX):
    SX := SF(X):
    # print(`SX is`, SX):
    # IDF's support will change from X[2] to fX[2]
    supp := fX[2]:
  fi:
  if not((X[3][2] = "HF") or (X[3][2] = "CHF")) then
    hX := []:
    for i from 1 to nsegments do
      HHX := unapply(simplify(fX[1][i](x) / SX[1][i](x)), x):
      hX := [op(hX), op([unapply(simplify(HHX(x)), x)])]: 
    od:
  fi:
  if (nargs = 1) then
    return([hX, supp, ["Continuous", "HF"]]):
  elif (nargs = 2) then
    if not(type(evalf(st), {numeric, infinity})) then
      if nsegments = 1 then
        prob := hX[1](st):
        return(prob):
      else
        print(`ERROR(HF): Symbolic second arguments with a piecewise`):
        print(`HF is not allowable in APPL at this time`):
        return:
      fi:
    fi:
    for i from 1 to nsegments do 
      if ((evalf(st) >= evalf(supp[i])) and (evalf(st) < 
           evalf(supp[i + 1]))) then
        break:
      fi:
    od:
    prob := hX[i](st):
    return(prob):
  fi:
#
#  The RV X is a discrete random variable
#
elif (X[3][1] = "Discrete") then
#
#  If the RV X is discrete, then call the procedure Convert(X) to
#  convert the discrete random variable's support to a standard APPL
#  discrete RV support format. Assign the converted random variable
#  to the Maple variable Y.
#
  Y := Convert(X):
  hX[1] := Y[1]:
  hX[2] := Y[2]:
#
#  X has dot support
#
  if type(Y[2][1], range) then
    Range := Y[2][1]:
    lo := lhs(Range):
    hi := rhs(Range):
    if member(Y[3][2], {"PDF", "CDF", "SF", "HF", "CHF"}) then
      incr := Y[2][2]:
      transf := Y[2][3]:
#
#  Report the support of X back to the user in its simplest form
#
      if (incr = 1 and unapply(transf(x))(x) = x) then
        hX[2] := [Range]:
#
#  APPL is not programmed to convert to a PDF format when the increment
#  is not 1 and/or the transformation is not x -> x
#
      elif not(incr = 1 or unapply(transf(x))(x) = x) then
        print(`ERROR(HF): APPL is currently unable to evaluate`):
        print(`this RV`):
        return:
      fi:
    fi:
#
#  X is given in its PDF form
#
    if (Y[3][2] = "PDF") then
      pdf := unapply(op(Y[1])(x))(x):
      SX := SF(Y):
      sf := unapply(op(SX[1])(x))(x):
      hf := simplify(pdf / sf):
      hX[1] := [unapply(hf, x)]:
#
#  X is given in its CDF or CHF form
#
    elif member(Y[3][2], {"CDF", "CHF"}) then 
      fX := PDF(Y):
      pdf := unapply(op(fX[1])(x))(x):
      SX := SF(Y):
      sf := unapply(op(SX[1])(x))(x):
      hf := simplify(pdf / sf):
      hX[1] := [unapply(hf, x)]:
#
#  X is given in its SF form
#
    elif (Y[3][2] = "SF") then 
      fX := PDF(Y):
      pdf := unapply(op(fX[1])(x))(x):
      sf := unapply(op(Y[1])(x))(x):
      hf := simplify(pdf / sf):
      hX[1] := [unapply(hf, x)]:
#
#  If X is given in its HF form, then nothing needs to be done to X.
#
    elif (Y[3][2] = "HF") then
#
#  X is given in its IDF form
#
    elif (Y[3][2] = "IDF") then
      # need to look for a ceil function here!
      idf := unapply(op(Y[1])(y))(y):
      # print(`idf is`, idf):
      # print(`[op(idf)] is`, [op(idf)]):
      pieces := [op(idf)]:
      numops := nops(pieces):
      # print(numops):
      noceil := true:
      for i from 1 to numops while noceil do
        if has(pieces, ceil) then
          # print(`has ceil`):
          noceil := false:
          ceilpiece := i:
        fi:
      od:
      if not(noceil) then
        # print(pieces[ceilpiece]):
        pieces[ceilpiece] := op(pieces[ceilpiece]):
        idf := sum(pieces[k], k = 1 .. numops):
      fi:
      solns := [solve(idf = x, y)]:
      # print(solns):
      nsolns := nops(solns):
      # Find the correct inverse
      if (nsolns = 1) then 
        # If there is only one inverse, assign it to cdf.
        cdf := solns[1]:
      else
        if lo = -infinity then
          if hi = infinity then
            val := 0:
          else 
            val := hi:
          fi: 
        else
          val := lo:  
        fi:   
        # print(`val is`, val):
        invfound := false:
        for j from 1 to nsolns do 
          # Evaluate each inverse of the IDF at the value "val" assigned
          # above. If CDF(IDF(val)) = val, then assign idf equal to that
          # inverse. 
          idfval := subs(x = val, idf):
          if evalf(subs(x = idfval, solns[j])) = evalf(val) then
            cdf := solns[j]:
            invfound := true:
            break:
          fi: 
        od:
        if not(invfound) then       
          print(`ERROR(HF): Could not find the appropriate inverse`):
        fi:  
      fi:
      pdf := simplify(subs(x = w, cdf) - subs(x = w - 1, cdf)):
      sf := 1 - sum(pdf, w = lo .. x - 1):
      pdf := subs(w = x, pdf):
      hX[1] := [unapply(simplify(pdf / sf), x)]:
#  CAUTION: losupp is incorrect in some cases -- currently don't know
#  how to fix this, need to be able to retrieve the first cdf value and
#  sub it into idf as lo
      losupp := evalf(subs(y = lo, idf)):
      hisupp := evalf(subs(y = hi, idf)): 
      hX[2] := [losupp .. hisupp]:
    fi:
#
#  X has no dot support
#
  else
    sublist1 := hX[1]:
    n := nops(sublist1):
#
#  X is given in its PDF, CDF, or SF form
#
    if member(Y[3][2], {"PDF", "CDF", "SF"}) then
      fX := PDF(Y): 
      SX := SF(Y):
      for i from 1 to n do
        hX[1][i] := fX[1][i] / SX[1][i]:
      od: 
#
#  If X is given in its HF form, then nothing needs to be done to X.
#
    elif (Y[3][2] = "HF") then
#
#  X is given in its CHF form
#
    elif (Y[3][2] = "CHF") then
      hX[1][n] := 1:
      hX[1][1] := 1 - exp(-sublist1[2]):
      hcum := hX[1][1]:
      for i from 2 to n - 1 do
        hX[1][i] := 1 - exp(-sublist1[i + 1]) / hcum:
        hcum := hcum + hX[1][i]:
      od:
#
#  X is given in its IDF form
#
    elif (Y[3][2] = "IDF") then
      fX := PDF(Y): 
      SX := SF(Y):
      for i from 1 to n do
        hX[1][i] := fX[1][i] / SX[1][i]:
      od: 
      hX[2] := SX[2]:
    fi:
  fi:
#
#  Only 1 argument, X, given for the procedure
#
  if (nargs = 1) then
    return([hX[1], hX[2], ["Discrete", "HF"]]):
#
#  Two arguments, X and x, provided for the procedure
#
  elif (nargs = 2) then
    if type(Y[2][1], range) then
#
#  Determine (if possible) if 'st' is in the support of fX; if not,
#  Pr(X = st) = 0.
#
      if not(type(lo, infinity) or type(hi, infinity)) then
#
#  CAUTION: Maple does not consider 1.0 a member of the set {1, 2, 3};
#  Problem if user chooses 'st' to be a float and the set contains
#  integers or vice versa
#
        if not(member(st, {$lo .. hi})) then
          prob := 0:
          return(prob):
        fi:
      fi:
      prob := op(hX[1](st)): 
    else
      prob := 0:
      notfound := true:
      count := 1:
      for k from 1 to n while notfound do
        if evalf(hX[2][k]) = evalf(st) then
          notfound := false:
          prob := hX[1][count]: 
        fi:
        count := count + 1:
      od:
    fi:
    return(prob):
  fi:
#
#  X is neither continuous nor discrete
else
  print(`ERROR(HF): The random variable X must be continuous or`):
  print(`discrete`):
fi:
end: #1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: idf8.map
#  
#  Procedure Name: IDF(X, [x])
#
#  Other APPL Procedures Called: CDF, IDFDiscrete
#  
#  Date: March 20, 2001
#
#  Purpose: IDF is a procedure that:
#          (1) returns the inverse distribution function of a 
#              random variable X in the APPL list of sublists format if
#              the only argument given is X, or
#          (2) Given the optional value x, returns the value alpha, 
#              where that F(x) = alpha.
#
#  Arguments: X: A continuous or discrete random variable; 
#             x (optional argument): A numeric value entered when
#                alpha, where alpha = Pr(X <= x)
#
#  Algorithm: 1. Perform error checking on user entered arguments
#             2. The IDF of X is determined by sending it to its 
#                appropriate category, which is based on whether:
#                A. X is continuous or discrete
#                B. X is entered in its PDF, CDF, SF, HF, CHF, or IDF
#                   format 
#             3. If only 1 argument (the random variable X) is entered
#                by the user, return the inverse distribution function
#                of X in the APPL list of 3 lists format 
#             4. If 2 arguments are provided, return the value alpha, 
#                where alpha = Pr(X <= x)
#
IDF := proc(X :: list(list), st)
local numlists, nsegments, i, prob, cp, FX, IDX, solnlist, nsolns, 
    c, begin, END, itp, supp, j, s, a, t, ii:
#
#  Check for the appropriate number of arguments
#
# print(`in IDF`):
if ((nargs <> 1) and (nargs <> 2)) then
  print(`ERROR(IDF): This procedure requires 1 or 2 arguments:`):
  print(`A random variable X and an optional argument x for`):
  print(`computing alpha, where alpha = Pr(X <= x)`):
  return:
fi:
#
#  Check that the RV X is in the list of 3 lists format
#
numlists := nops(X):
if (numlists <> 3) then
  print(`ERROR(IDF): The RV X must be a list of 3 lists`):
  return:
fi:
#
#  Make sure X is given as a PDF, CDF, SF, HF, CHF, or IDF
#
if not(member(X[3][2], {"PDF", "CDF", "SF", "HF", "CHF", "IDF"})) then
  print(`ERROR(IDF): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
#
#  If the RV X is continuous, find and return the IDF of X
#
if (X[3][1] = "Continuous") then
  nsegments := nops(X[1]):
  if (X[3][2]= "IDF") then
    if (nargs = 1) then
      return(X):
    elif (nargs = 2) then
      for i from 1 to nsegments do 
        if ((evalf(st) >= evalf(X[2][i])) and (evalf(st) <= 
             evalf(X[2][i + 1]))) then
          break:
        fi:
      od:
      prob := limit(X[1][i](a), a = st):
      return(prob):
    fi:
  else
    if (nargs = 2) then
      # 6/22/2007: FIX -- looks like CriticalPoint is doing
      # what we'd like IDF to do when given 2 args ... so
      # why not just have IDF call CriticalPoint to do what
      # it is not able to do
      # SEARCH IDF
      # print(`going to CriticalPoint`);
      # print(X); print(st);
      cp := CriticalPoint(X, st):
      return(cp):
    fi:
    FX := CDF(X): 
    IDX := []:
    for i from 1 to nsegments do 
      solnlist := [solve(FX[1][i](x) = s, x)]:
      nsolns := nops(solnlist): 
      solnlist := [seq(unapply(simplify(solnlist[j]), s), j = 1 ..
          nsolns)]:
      # Find right inverse
      if (nsolns = 1) then 
        # If there is only one inverse, assign it to ginv.
        IDX := [op(IDX), solnlist[1]]:
      else 
        # If there is more than one inverse, find the appropriate one.
        # Find midpoints of each segment
        c := array(1 .. nsegments):
        if (FX[2][1] = -infinity and FX[2][2] = infinity) then
          c[1] := 0:
        else
          begin := 1:
          END := nsegments:
          if (FX[2][1] = -infinity) then
            c[1] := FX[2][2] - 1:
            begin := 2:
          fi:
          if (FX[2][nsegments + 1] = infinity) then
            c[nsegments] := FX[2][nsegments] + 1:
            END := nsegments - 1:
          fi:
          for ii from begin to END do
            c[ii] := (FX[2][ii] + FX[2][ii + 1]) / 2:
          od:
        fi: 
        # print(cis, c):
        for t from 1 to nsolns do 
          # Evaluate each inverse of the CDF at the midpoint of the
          # subinterval.  Set IDX[1][i] to that inverse for which gtemp
          #(g(x)) = x.
          itp := solnlist[t](FX[1][i](c[i])): 
          # print(itpis, itp):
          # whattype(itp): 
          # print(herrrrrr):
          if(whattype(evalf(FX[1][i](c[i]))) <> float) then 
            # print(notafloat, simplify(itp), c[i]):
          else 
            # print(isafloat, itp, c[i]): 
          fi:
          if (((whattype(evalf(FX[1][i](c[i]))) <> float) and
              (itp = c[i]) ) or 
             ((whattype(evalf(FX[1][i](c[i]))) = float) and 
              (evalf(itp) >= evalf(FX[2][i]) and 
              (evalf(itp) <= evalf(FX[2][i + 1]))))) then
            IDX := [op(IDX), solnlist[t]]: 
            # print(hereiam):
            break:
          else
            print(`ERROR(IDF): Could not find the appropriate inverse`):
          fi:  
          # print(evermakeithere):
        od:
      fi:
    od:
    supp := [0]:
    for i from 1 to nsegments - 1 do 
      supp := [op(supp), CDF(FX, FX[2][i + 1])]:
      # print(`supp is`, supp):
    od:   
    supp := [op(supp), 1]:
  fi:
#
#  Only 1 argument, X, given for the procedure
#
  if (nargs = 1) then
    return([IDX, supp, ["Continuous", "IDF"]]):
#
#  Two arguments, X and x, provided for the procedure
#
  elif (nargs = 2) then
    if not(type(evalf(st), {numeric, infinity})) then
      if nsegments = 1 then
        prob := IDX[1](st):
        return(prob):
      else
        print(`ERROR(IDF): Symbolic second arguments with a piecewise`):
        print(`IDF are not allowable in APPL at this time`):
        return:
      fi:
    fi:
    # print(`nsegments is`, nsegments):
    for i from 1 to nsegments do 
      if ((evalf(st) >= evalf(supp[i])) and (evalf(st) < 
           evalf(supp[i + 1]))) then
        break:
      fi:
    od:
    # print(IDX[i]):
    prob := IDX[i](st):
    # print(`prob is`, prob):
    return(prob):
  fi:
elif (X[3][1] = "Discrete") then
  if nargs = 1 then
    IDFDiscrete(X):
  else 
#
#  6/23/2007, trying to fix IDF for discrete RV's
#  IDF should return something
#
    cp := IDFDiscrete(X, st):
    return(cp):
  fi:
else
  print(`ERROR(IDF): The random variable X must be continuous or`):
  print(`discrete`):
fi:
end: 



#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: idfdiscrete5.map 
#  
#  Procedure Name: IDFDiscrete(X, [x])
#
#  Other APPL Procedures Called: Convert, CDF
#
#  Date: March 20, 2001
#
#  Defn: For a distribution F, mapping a quantile x into a probability
#        alpha, the inverse distribution function G performs the 
#        corresponding inverse mapping from alpha into x. Thus, if
#        Pr(X <= x) = F(x) = alpha, then G(alpha) = x.
#
#  Purpose: IDF is a procedure that:
#          (1) returns the inverse distribution function of a 
#              random variable X in the APPL list of sublists format if
#              the only argument given is X, or
#          (2) Given the optional value x, returns the value alpha, 
#              where that F(x) = alpha.
#
#  Arguments: X: A discrete random variable; 
#             x (optional argument):  A numeric value entered when
#                trying to determine alpha, where alpha = Pr(X <= x) 
#
#  Algorithm: 1. Perform error checking on user entered arguments
#             2. The IDF of X is determined by sending it to its 
#                appropriate category, which is based on whether:
#                A. X is entered in its PDF, CDF, SF, HF, CHF, or IDF
#                   format 
#             3. If only 1 argument (the random variable X) is entered
#                by the user, return the inverse distribution function
#                of X in the APPL list of 3 lists format 
#             4. If 2 arguments are provided, return the value alpha,
#                where alpha = Pr(X <= x)
# 
#  CAUTION: Made x local to find the inverse of the CDF
# 
IDFDiscrete := proc(X :: list(list), st)
local Y, IDX, Range, lo, hi, incr, transf, FX, cdf, x, inveq, solns,
    nsolns, idf, val, invfound, j, losupp, cdfval, n, i, Lo, prob:
#
#  Call the procedure Convert(X) to convert the discrete random
#  variable's support to a standard APPL discrete RV support format. 
#
Y := Convert(X):
IDX[1] := Y[1]:
IDX[2] := Y[2]:
#
# 6/23/2007, IDF can't work with Binomial because it can't convert
# it to a nice closed form CDF; but IDF should still be able
# to report a critical value, so changing Binomial-type supports
# to NoDot format
#
if type(Y[2][1], range) then
  Range := Y[2][1]:
  lo := lhs(Range):
  hi := rhs(Range):
  if not(type(hi, symbol)) then
    Y := ConvertToNoDot(X):
  fi:
fi:
#
#  X has dot support
#
# print(Y):
if type(Y[2][1], range) then
  Range := Y[2][1]:
  lo := lhs(Range):
  hi := rhs(Range):
  if member(Y[3][2], {"PDF", "CDF", "SF", "HF", "CHF"}) then
    incr := Y[2][2]:
    transf := Y[2][3]:
#
#  Report the support of new random variable back to the user in its
#  simplest form
#
    if (incr = 1 and unapply(transf(x))(x) = x) then
      IDX[2] := [Range]:
#
#  APPL is not programmed to convert to a PDF format when the increment
#  is not 1 and/or the transformation is not x -> x
#
    elif not(incr = 1 or unapply(transf(x))(x) = x) then
      print(`ERROR(IDF): APPL is currently unable to evaluate`):
      print(`this RV`):
      return:
    fi:
  fi:
#
#  X is given in its PDF, CDF, SF, HF, or CHF form
#
  if member(Y[3][2], {"PDF", "CDF", "SF", "HF", "CHF"}) then
    FX := CDF(X):
    # print(FX):
    cdf := op(unapply(FX[1](x))(x)):
    inveq := subs(x = y, cdf):
    # print(`inveq is`, inveq):
    # print(`number of ops in inveq`, nops(inveq)):
    # if finding an inverse symbolically is probably not possible -- 
    # making this determination if 4 or more terms make up inveq
    # find the IDF value by "brute force" ... better than nothing
    if nops(inveq) >= 4 and nargs = 2 then
      Lo := lhs(FX[2][1]):
      # print(`Lo is`, Lo):
      if ((evalf(st, Digits + 2) > 0) and 
          (evalf(st, Digits + 2) <= 
           evalf(subs(x = Lo, op(unapply(FX[1](x))(x))), Digits + 2)))
           then 
        # print(`in here`):
        return(Lo):
      fi:
      # Setting the upper limit to Lo + 100
      # print(FX[1]):
      for i from Lo to (Lo + 100) do
        # print(i):
        if ((evalf(st, Digits + 2) > 
           evalf(subs(x = i, op(unapply(FX[1](x))(x))), Digits + 2))
           and (evalf(st, Digits + 2) <= evalf(subs(x = i + 1, 
           op(unapply(FX[1](x))(x))), Digits + 2))) then 
        return(i + 1):
        fi:
      od: 
      print(`ERROR(IDF): Unable to determine requested value`):
      return:
    fi:
    solns := [solve(inveq = x, y)]:
    # print(`solns are`, solns):
    nsolns := nops(solns):
    # print(nsolns):
    # Find the correct inverse
    if (nsolns = 1) then 
      # If there is only one inverse, assign it to idf
      idf := solns[1]:
    else
      if lo = -infinity then
        if hi = infinity then
          val := 0:
        else 
          val := hi:
        fi: 
      else
        val := lo:  
      fi:   
      # print(`val is`, val):
      invfound := false:
      for j from 1 to nsolns do 
        # Evaluate each inverse of the CDF at the value "val" assigned
        # above. If IDF(CDF(val)) = val, then assign idf equal to that
        # inverse. 
        cdfval := subs(x = val, cdf):
        # print(cdfval):
        if evalf(subs(x = cdfval, solns[j])) = evalf(val) then
          idf := solns[j]:
          invfound := true:
          break:
        fi: 
      od:
      if invfound = false then       
        print(`ERROR(IDF): Could not find the appropriate inverse`):
      fi:  
    fi:
    # print(`idf is`, idf):
    # "floor" causes problems with a GeometricRV; see IDFDiscreteDotCase
    IDX[1] := [unapply(ceil(idf), x)]:
    # Should really have the range as [0, 1] (as in continuous)?  Either
    # way, doesn't fully make sense, but we still want to treat the RV
    # as if it is in the dot case.  [0 .. 1] means from 0 to 1 here.
    # NEW (5/20/01): IDF range: CDF at x = lo to 1
    losupp := subs(x = lo, cdf):
    IDX[2] := [losupp .. 1]:
#
#  If X is given in its IDF form, then nothing needs to be done to X.
#
  elif (X[3][2] = "IDF") then
  fi:
#
#  X has no dot support
#
else
#
#  X is given in its PDF, CDF, SF, HF, or CHF form
#
  if member(Y[3][2], {"PDF", "CDF", "SF", "HF", "CHF"}) then
    FX := CDF(Y):
    # print(`FX is`, FX):
    IDX[2] := FX[1]:
    IDX[1] := FX[2]:
#
#  If X is given in its IDF form, then nothing needs to be done to X.
#
  elif (Y[3][2] = "IDF") then
  fi:
fi:
#
#  Only 1 argument given
#
if (nargs = 1) then
  return([IDX[1], IDX[2], ["Discrete", "IDF"]]):
else
  if (evalf(st, Digits + 2) <= 0) then
    print(`ERROR(IDF): x must be greater than 0`):
    return:
  fi:
  if (evalf(st, Digits + 2) > 1) then
    print(`ERROR(IDF): x must be less than or equal to 1`):
    return:
  fi:
#
#  No dot support format (Example: [1, 3, 7].)
#
  if not(type(IDX[1][1], range)) and not(type(IDX[2][1], range)) then
    n := nops(IDX[2]):
    # print(n):
    # print(IDX[2][1]):
    if ((evalf(st, Digits + 2) > 0) and 
        (evalf(st, Digits + 2) <= evalf(IDX[2][1], Digits + 2))) then 
      return(IDX[1][1]):
    fi:
    for i from 1 to (n - 1) do
      if ((evalf(st, Digits + 2) > evalf(IDX[2][i], Digits + 2)) and 
          (evalf(st, Digits + 2) <= evalf(IDX[2][i + 1], Digits + 2)))
          then 
        return(IDX[1][i + 1]):
      fi:
    od:
    return(IDX[1][n]):
#
#  Dot support format (Example: [1 .. infinity].)
#
  elif type(IDX[2][1], range) then
    prob := subs(x = st, idf):
    return(prob):
  fi:
fi:
end: #11111111112222222222333333333344444444445555555555666666666677777777778888888888#
#  Filename: incompletebeta1.map
#
#  Procedure Name: IncompleteBeta(p, a, b)
#
#  Other APPL Procedures Called:
#
#  Updated: June 14, 1999
#
#  Purpose: Computes the Incomplete Beta Function
#
#  Arguments: 
# 
#  Algorithm:
#
IncompleteBeta := proc(p, a, b)
local Expression, x:
if (nargs <> 3) then
  print(`ERROR(IncompleteBeta): This procedure requires 3 arguments`):
  RETURN():
fi:
if (type(p, infinity) or type(a, infinity) or type(b, infinity)) then
  print(`ERROR(IncompleteBeta): Each parameter must be finite`):
  RETURN():
fi:
if type(a, symbol) then
  assume(a, positive):
fi:
if type(b, symbol) then
  assume(b, positive):
fi:
Expression := GAMMA(a + b) / (GAMMA(a) * GAMMA(b)) * int(x ^ (a - 1) * (1 - x) ^ (b - 1), 
    x = 0 .. p):
RETURN(Expression):
end:

#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: insertheapconvolution1.map
#  making fX and fY global variables
#
#  Procedure Name: InsertHeapConvolution()
#
#  Other APPL Procedures Called: 
#
#  Date: September 17, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
InsertHeapConvolution := proc(position) 
global H, Mimic, fX, fY:
local size, xval, xprob, yval, yprob, place, Parent, ParentValue,
    ParentValueProb, ParentValuePosition:

size := nops(convert(H, list)):
place := size + 1:
H := array(1 .. place, [seq(H[i], i = 1 .. size), 0]):
# print(`H is`, H):
xval := fX[2][position[1]]:
xprob := fX[1][position[1]]:
# print(`xval is`, xval):
yval := fY[2][position[2]]:
yprob := fY[1][position[2]]:
# print(`yval is`, yval):
#
#  Insert the new item at the bottom of the tree
#
H[place] := [xval + yval, xprob * yprob]:
# print(`H is`, H):
Mimic := array(1 .. place, 
    [seq(Mimic[i], i = 1 .. size), position]):
# print(`Mimic is`, Mimic):
#
#  Inserted item will trickle up to its proper place in the tree
#
Parent := ceil(place / 2):
while ((Parent >= 2) and (H[place][1] < H[Parent][1])) do
  ParentValue := H[Parent][1]:
  ParentValueProb := H[Parent][2]:
  ParentValuePosition := Mimic[Parent]:
  # print(`H is`, eval(H)):
  # print(`Parent is`, Parent):
  # print(`place is`, place):
  H[Parent] := H[place]:
  Mimic[Parent] := Mimic[place]:
  H[place][1] := ParentValue:
  H[place][2] := ParentValueProb:
  Mimic[place] := ParentValuePosition:
  place := Parent:
  Parent := ceil(place / 2):
od:
return:

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: insertheapproduct1.map
#  making fX and fY global variables
#
#  Procedure Name: InsertHeapProduct()
#
#  Other APPL Procedures Called: 
#
#  Date: September 17, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
InsertHeapProduct := proc(position) 
global H, Mimic, fX, fY:
local size, xval, xprob, yval, yprob, place, Parent, ParentValue,
    ParentValueProb, ParentValuePosition:

size := nops(convert(H, list)):
place := size + 1:
H := array(1 .. place, [seq(H[i], i = 1 .. size), 0]):
# print(`H is`, H):
xval := fX[2][position[1]]:
xprob := fX[1][position[1]]:
# print(`xval is`, xval):
yval := fY[2][position[2]]:
yprob := fY[1][position[2]]:
# print(`yval is`, yval):
#
#  Insert the new item at the bottom of the tree
#
H[place] := [xval * yval, xprob * yprob]:
# print(`H is`, H):
Mimic := array(1 .. place, 
    [seq(Mimic[i], i = 1 .. size), position]):
# print(`Mimic is`, Mimic):
#
#  Inserted item will trickle up to its proper place in the tree
#
Parent := ceil(place / 2):
while ((Parent >= 2) and (H[place][1] < H[Parent][1])) do
  ParentValue := H[Parent][1]:
  ParentValueProb := H[Parent][2]:
  ParentValuePosition := Mimic[Parent]:
  # print(`H is`, eval(H)):
  # print(`Parent is`, Parent):
  # print(`place is`, place):
  H[Parent] := H[place]:
  Mimic[Parent] := Mimic[place]:
  H[place][1] := ParentValue:
  H[place][2] := ParentValueProb:
  Mimic[place] := ParentValuePosition:
  place := Parent:
  Parent := ceil(place / 2):
od:
return:

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: insertheapproductq11.map
#
#  Procedure Name: InsertHeapProductQ1()
#
#  Other APPL Procedures Called: 
#
#  Date: January 11, 2001
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
InsertHeapProductQ1 := proc(position) 
global Q1H, Q1Mimic, fXPos, fYPos:
local size, xval, xprob, yval, yprob, place, Parent, ParentValue,
    ParentValueProb, ParentValuePosition:

size := nops(convert(Q1H, list)):
place := size + 1:
Q1H := array(1 .. place, [seq(Q1H[i], i = 1 .. size), 0]):
# print(`Q1H is`, Q1H):
xval := fXPos[2][position[1]]:
xprob := fXPos[1][position[1]]:
# print(`xval is`, xval):
yval := fYPos[2][position[2]]:
yprob := fYPos[1][position[2]]:
# print(`yval is`, yval):
#
#  Insert the new item at the bottom of the tree
#
Q1H[place] := [xval * yval, xprob * yprob]:
# print(`Q1H is`, Q1H):
Q1Mimic := array(1 .. place, 
    [seq(Q1Mimic[i], i = 1 .. size), position]):
# print(`Q1Mimic is`, Q1Mimic):
#
#  Inserted item will trickle up to its proper place in the tree
#
Parent := ceil(place / 2):
while ((Parent >= 2) and (Q1H[place][1] < Q1H[Parent][1])) do
  ParentValue := Q1H[Parent][1]:
  ParentValueProb := Q1H[Parent][2]:
  ParentValuePosition := Q1Mimic[Parent]:
  # print(`Q1H is`, eval(Q1H)):
  # print(`Parent is`, Parent):
  # print(`place is`, place):
  Q1H[Parent] := Q1H[place]:
  Q1Mimic[Parent] := Q1Mimic[place]:
  Q1H[place][1] := ParentValue:
  Q1H[place][2] := ParentValueProb:
  Q1Mimic[place] := ParentValuePosition:
  place := Parent:
  Parent := ceil(place / 2):
od:
return:

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: insertheapproductq21.map
#  making fX and fY global variables
#
#  Procedure Name: InsertHeapProductQ2()
#
#  Other APPL Procedures Called: 
#
#  Date: September 17, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
InsertHeapProductQ2 := proc(position) 
global Q2H, Q2Mimic, fXNeg, fYPos:
local size, xval, xprob, yval, yprob, place, Parent, ParentValue,
    ParentValueProb, ParentValuePosition:

size := nops(convert(Q2H, list)):
place := size + 1:
Q2H := array(1 .. place, [seq(Q2H[i], i = 1 .. size), 0]):
# print(`Q2H is`, Q2H):
xval := fXNeg[2][position[1]]:
xprob := fXNeg[1][position[1]]:
# print(`xval is`, xval):
yval := fYPos[2][position[2]]:
yprob := fYPos[1][position[2]]:
# print(`yval is`, yval):
#
#  Insert the new item at the bottom of the tree
#
Q2H[place] := [xval * yval, xprob * yprob]:
# print(`Q2H is`, Q2H):
Q2Mimic := array(1 .. place, 
    [seq(Q2Mimic[i], i = 1 .. size), position]):
# print(`Q2Mimic is`, Q2Mimic):
#
#  Inserted item will trickle up to its proper place in the tree
#
Parent := ceil(place / 2):
while ((Parent >= 2) and (Q2H[place][1] < Q2H[Parent][1])) do
  ParentValue := Q2H[Parent][1]:
  ParentValueProb := Q2H[Parent][2]:
  ParentValuePosition := Q2Mimic[Parent]:
  # print(`Q2H is`, eval(Q2H)):
  # print(`Parent is`, Parent):
  # print(`place is`, place):
  Q2H[Parent] := Q2H[place]:
  Q2Mimic[Parent] := Q2Mimic[place]:
  Q2H[place][1] := ParentValue:
  Q2H[place][2] := ParentValueProb:
  Q2Mimic[place] := ParentValuePosition:
  place := Parent:
  Parent := ceil(place / 2):
od:
return:

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: insertheapproductq31.map
#
#  Procedure Name: InsertHeapProductQ3()
#
#  Other APPL Procedures Called: 
#
#  Date: January 11, 2001
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
InsertHeapProductQ3 := proc(position) 
global Q3H, Q3Mimic, fXNeg, fYNeg:
local size, xval, xprob, yval, yprob, place, Parent, ParentValue,
    ParentValueProb, ParentValuePosition:

size := nops(convert(Q3H, list)):
place := size + 1:
Q3H := array(1 .. place, [seq(Q3H[i], i = 1 .. size), 0]):
# print(`Q3H is`, Q3H):
xval := fXNeg[2][position[1]]:
xprob := fXNeg[1][position[1]]:
# print(`xval is`, xval):
yval := fYNeg[2][position[2]]:
yprob := fYNeg[1][position[2]]:
# print(`yval is`, yval):
#
#  Insert the new item at the bottom of the tree
#
Q3H[place] := [xval * yval, xprob * yprob]:
# print(`Q3H is`, Q3H):
Q3Mimic := array(1 .. place, 
    [seq(Q3Mimic[i], i = 1 .. size), position]):
# print(`Q3Mimic is`, Q3Mimic):
#
#  Inserted item will trickle up to its proper place in the tree
#
Parent := ceil(place / 2):
while ((Parent >= 2) and (Q3H[place][1] < Q3H[Parent][1])) do
  ParentValue := Q3H[Parent][1]:
  ParentValueProb := Q3H[Parent][2]:
  ParentValuePosition := Q3Mimic[Parent]:
  # print(`Q3H is`, eval(Q3H)):
  # print(`Parent is`, Parent):
  # print(`place is`, place):
  Q3H[Parent] := Q3H[place]:
  Q3Mimic[Parent] := Q3Mimic[place]:
  Q3H[place][1] := ParentValue:
  Q3H[place][2] := ParentValueProb:
  Q3Mimic[place] := ParentValuePosition:
  place := Parent:
  Parent := ceil(place / 2):
od:
return:

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: insertheapproductq41.map
#
#  Procedure Name: InsertHeapProductQ4()
#
#  Other APPL Procedures Called: 
#
#  Date: January 11, 2001
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
InsertHeapProductQ4 := proc(position) 
global Q4H, Q4Mimic, fXPos, fYNeg:
local size, xval, xprob, yval, yprob, place, Parent, ParentValue,
    ParentValueProb, ParentValuePosition:

size := nops(convert(Q4H, list)):
place := size + 1:
Q4H := array(1 .. place, [seq(Q4H[i], i = 1 .. size), 0]):
# print(`Q4H is`, Q4H):
xval := fXPos[2][position[1]]:
xprob := fXPos[1][position[1]]:
# print(`xval is`, xval):
yval := fYNeg[2][position[2]]:
yprob := fYNeg[1][position[2]]:
# print(`yval is`, yval):
#
#  Insert the new item at the bottom of the tree
#
Q4H[place] := [xval * yval, xprob * yprob]:
# print(`Q4H is`, Q4H):
Q4Mimic := array(1 .. place, 
    [seq(Q4Mimic[i], i = 1 .. size), position]):
# print(`Q4Mimic is`, Q4Mimic):
#
#  Inserted item will trickle up to its proper place in the tree
#
Parent := ceil(place / 2):
while ((Parent >= 2) and (Q4H[place][1] < Q4H[Parent][1])) do
  ParentValue := Q4H[Parent][1]:
  ParentValueProb := Q4H[Parent][2]:
  ParentValuePosition := Q4Mimic[Parent]:
  # print(`Q4H is`, eval(Q4H)):
  # print(`Parent is`, Parent):
  # print(`place is`, place):
  Q4H[Parent] := Q4H[place]:
  Q4Mimic[Parent] := Q4Mimic[place]:
  Q4H[place][1] := ParentValue:
  Q4H[place][2] := ParentValueProb:
  Q4Mimic[place] := ParentValuePosition:
  place := Parent:
  Parent := ceil(place / 2):
od:
return:

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: insertionsort1.map
#  for convolution for discrete rvs, rangestat6.map
#
#  Procedure Name: InsertionSort(A, B)
#
#  Other APPL Procedures Called: 
#
#  Date: September 8, 2000
#
#  Purpose: Returns two sorted lists; the procedure sorts list A and 
#           uses list A to sort list B accordingly
#
#  Arguments: 
#
#  Algorithm:
InsertionSort := proc(A :: list, B :: list) 
local n, NewA, NewB, i, TempA, TempB, j, SortedA, SortedB:

NewA := Array([-1 * 10 ^ 6, op(A)]):
# NewA := [-1 * 10 ^ 6, op(A)]:
NewB := Array([0, op(B)]):
n := ArrayNumElems(NewA):
# print(NewA):
# print(NewB):
for i from 3 to n do
  # print(NewA):
  TempA := NewA[i]:
  TempB := NewB[i]:
  for j from i by -1 to 2 while evalf(TempA) < evalf(NewA[j - 1]) do
    NewA[j] := NewA[j - 1]:
    NewB[j] := NewB[j - 1]:
  od:
  NewA[j] := TempA:
  NewB[j] := TempB:
od:
# SortedA := Array([seq(NewA[i], i = 2 .. n)]):
SortedA := [seq(NewA[i], i = 2 .. n)]:
# SortedB := Array([seq(NewB[i], i = 2 .. n)]):
SortedB := [seq(NewB[i], i = 2 .. n)]:
# print(SortedA): print(SortedB):
RETURN(SortedA, SortedB):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: ks2.map: removed unused variables, commented out print
#  statements, removed [op(*)] when * was already a list, no tampering
#  with the logic, ordered variables by when they appear in code
#  
#  Procedure Name: KSRV(n)
#
#  Other APPL Procedures Called: None 
#
#  Date: July 27, 2000
#
#  Purpose: KS returns the PDF of the KS statistic for sample size n 
#
#  Arguments: 
#
#  Algorithm:
#
KSRV := proc(n)
local N, m, v, vv, g, mm, i, j, k, c, x, A, z, l, P, F, V, u, S, KSCDF, KSspt:

# Phase 1
N := n: 
m := floor(3 * N / 2) + (N mod 2) - 1:
# print(`m is`, m):
vv := array(0 .. m):
vv[0] := 0:
g := 1 / (2 * N):
mm := 0:
for i from 1 to (N - 1) do
  mm := mm + 1:
  vv[mm] := i * g:
od:
for j from 2 * floor(N / 2) + 1 to (2 * N - 1) by 2 do
  mm := mm + 1:
  vv[mm] := j * g:
od:
if not(mm = m) then
  print(`ERROR(KSRV): In calculating m`):
fi:
# print(`v is`, seq(vv[i], i = 0 .. m)):

# Phase 2
for k from 1 to m do
  c[k] := (vv[k - 1] + vv[k]) / 2:
od:
for k from 1 to N do
  x[k] := (2 * k - 1) * g:
od:
# print(`c is`, seq(c[i], i = 1 .. m)):
# print(`x is`, seq(x[i], i = 1 .. N)):
A := array(1 .. N, 1 .. N):
for i from 2 to N do
  for j from 1 to i - 1 do 
    A[i, j] := 0:
  od:
od:
for k from 1 to m do 
  for i from 1 to N do
    for j from i to N do
      A[i, j] := 0
    od:
  od:
  z := max(floor(N * c[k] - 1/2), 0):
  l := min(ceil(2 * N * c[k]), N):
  for i from 1 to N do
    for j from  max(i, z + 1) to min(N, i + l - 1) do
      A[i, j] := 1:
    od:
  od:
  # print(`For k =`, k, `the A matrix is`, A):
od:
P := array(1 .. m):
F := array(1 .. N, 1 .. N):
V := array(1 .. N, 1 .. N):
u := array(1 .. N):
# set up the variables u_i
for i from 1 to N do
  u[i] := cat(u, i):
od:

P[1] := N! * (2 * v) ^ N:
for k from 2 to m do
  z := max(floor(N * c[k] - 1/2), 0):
  l := min(ceil(2 * N * c[k]), N ):
  # print(`at k = `, k,` l and z calculated John's way are `, l, z):
  F[N, N] := int(1, u[N] = x[N] - v .. 1):  
  V[N, N] := int(1, u[N] = u[N - 1] .. 1): 


  for i from N - 1 to 2 by -1 do
    # print(`k and i are`, k, i):
    if (i + l > N) then
      S := 0:
    else
      S := F[i + 1, i + l]:
    fi:
    # if (k = 7) then print(`K IS SEVEN: S at first =`, S): fi:
    if (i + l > N + 1) then 
      F[i, N] := int(V[i + 1, N], u[i] = x[N] - v .. floor(x[i] + c[k])
          + (x[i] + v) * (1 - floor(x[i] + c[k]))):
      V[i, N] := int(V[i + 1, N], u[i] = u[i - 1] .. floor(x[i] + c[k])
          + (x[i] + v) * (1 - floor(x[i] + c[k]))):
    fi:
    if (i + l = N + 1) then 
      F[i, N] := int(V[i + 1, N], u[i] = x[N] - v .. x[i] + v):
    fi:
    if (i + l < N + 1) then
      F[i, i + l - 1] := int(V[i + 1, i + l - 1] + S, u[i] = 
          x[i + l - 1] - v .. x[i] + v):  
    fi: 
    # if (k = 7) then print(`K IS SEVEN: F and V at step one are`):
    # print(F, V): fi:
    S := S + F[i + 1, min(i + l - 1, N)]:
    # if (k = 7) then print(`K IS SEVEN: S second =`, S): fi:
    for j from (min(N - 1, i + l - 2)) to (max(i + 1, z + 2)) by -1 do
      F[i, j] := int(V[i + 1, j] + S, u[i] = x[j] - v .. x[j + 1] - v ):
      V[i, j] := int(V[i + 1, j] + S, u[i] = u[i - 1] .. x[j + 1] - v ):
      S := S + F[i + 1, j]:
      # if (k = 7) then print(`K IS SEVEN: In J loop:  j, F, V, are`,):
      # print(j, F, V): fi:
    od: 
    # print(`here i am1, j, k, l, i, z`, j, k, l, i, z):
    # print(F,V):
    if (z + 1 <= i) then
      V[i, i] := int(S, u[i] = u[i - 1] .. x[i + 1] - v):
    fi:
    if (z + 1 > i) then 
      V[i, z + 1] := int(V[i + 1, z + 1] + S , u[i] = u[i - 1] .. 
          x[z + 2] - v):
    fi:
    if (z + 1 < i) then
      F[i, i] := int(S, u[i] = x[i] - v .. x[i + 1] - v):
    fi:
    # if (k=7) then print(`K IS SEVEN: after z + 1 check: F and V`):
     #print(`are`,F, V): fi; 
    # print(`here i am2, j, k, l, i, z`, j, k, l, i, z):
  od: 
  # print(`Now computing case of i = 1, k is currently`, k):
  # print(`l is`, l):
  if (l = N) then
    S := 0:
    F[1, N] := int(V[2, N], u[1] = x[N] - v .. x[1] + v):
  else
    S := F[2, l + 1]:
  fi:
  # if (k=7) then print(`K IS SEVEN: outer loop, F and S are`,F,S): fi:
  # print(`k and S are`, k, S):
  if (l < N) then
    F[1, l] := int( V[2, l] + S, u[1] = x[l] - v .. x[1] + v): 
  fi:
  S := S + F[2, l]:
  for j from min(N - 1, l - 1) to max(2, z + 1) by -1 do
    F[1, j] := int(V[2, j] + S, u[1] = (x[j] - v) * ceil(x[j] - c[k]) ..
        x[j + 1] - v):
    S := S + F[2, j]:
    # if (k=7) then print(`K IS SEVEN: second j loop, j, F, and S`):
    # print(`are`, j, F, S): fi:
  od:
  if (z = 0) then
    F[1, 1] := int(S, u[1] = 0 .. x[2] - v):
    # if (k=7) then print(`K IS SEVEN: z = 0, F is`,F): fi:
  fi:
  # if (k = 3) then  print(`end of loop and F is`, F):
  # print(`end of loop and V is`, V): fi:
  P[k] := 0:
  for j from z + 1 to l do
    P[k] := P[k] + F[1, j]:
    # print(`just added`, expand(F[1, j])):
    # if (k = 7) then print(`K IS SEVEN: final j loop, j and F[1,j]`):
    # print(`are`, j, F[1,j]): fi:
  od:
  P[k] := N! * P[k]:
  # print(`here i am2, j, k, l, i, z`, j, k, l, i, z):
od:
# print(`Before conversion of P, P and m are`, P,m):  
#KSCDF 
KSspt := []:
KSCDF := []:
for i from 0 to m do
  # print(`i and vvi are`, i, vv[i]):
  KSspt := [op(KSspt), vv[i] + 1 / (2 * N)]: 
od:  
for i from 1 to m do
  KSCDF := [op(KSCDF), unapply(simplify(subs(v = (w - 1 / (2 * N)), P[i])) , w)]:
od:
#print(herrrrrr, KS1);
# [op(KSCDF2)], 
RETURN([KSCDF, KSspt, ["Continuous", "CDF"]]):
end:
#111111111122222222223333333333444444444455555555556666666666777777777788888  
#  Filename: kstest1.map
#
#  Procedure name: KSTest(X, Sample, Parameters)
#
#  Other APPL Procedures Called: 
#
#  Date: January 12, 2000
#
#  Purpose: Calculates the Kolmogorov-Smirnoff test statistic for the
#           empirical CDF of the sample data versus the CDF of a fitted
#           distribution with random variable X
#
#  Arguments: X: Random variable, 
#             Sample: List of sample data points,
#             Parameters: List of parameters set equal to their estimated
#               values to be substituted into the CDF of X
#  
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Check that the RV X is in a list-of-lists format
#    3.  Check that X is in its PDF, CDF, SF, HF, CHF, or IDF format
#
KSTest := proc(X :: list(list), Sample :: list, Parameters :: list)
local NumLists, n, SortedSample, EmpCDF, i, NoRepeatSample, EmpCDFValues, m,
    FX, SubList1, newSubList1, FittedCDFValues, KS, Dpos, Dneg:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 3) then
  print(`ERROR(KSTest): This procedure 3 arguments`):
  RETURN():
fi:
#
#  Check that the RV X is in a list-of-lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(KSTest): The RV X must be in a`): 
  print(`list of 3 lists format`):
  RETURN(): 
fi:
#
#  Check that X is in its PDF, CDF, SF, HF, CHF, or IDF format
#
if not((X[3][2] = "PDF") or
       (X[3][2] = "CDF") or
       (X[3][2] = "SF") or
       (X[3][2] = "HF") or
       (X[3][2] = "CHF") or
       (X[3][2] = "IDF")) then
  print(`ERROR(KSTest): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  RETURN():
fi:

n := nops(Sample):
SortedSample := sort(Sample):
EmpCDF := [[], [], ["Discrete", "CDF"]]:
for i from 1 to n - 1 do 
  if SortedSample[i] < SortedSample[i + 1] then
    EmpCDF[1] := [op(EmpCDF[1]), i / n]:
  fi:
od:
EmpCDF[1] := [op(EmpCDF[1]), 1]:
NoRepeatSample := [op({op(SortedSample)})]:
EmpCDF[2] := sort(NoRepeatSample):
EmpCDFValues := [0, op(EmpCDF[1])]:
# print(EmpCDFValues):

m := nops(EmpCDF[2]):
FX := CDF(X):
SubList1 := FX[1]:
newSubList1 := [subs({op(Parameters)}, op(SubList1(x)))]:
FX[1] := newSubList1:
# print(`FX[1] is`, FX[1]):
FittedCDFValues := []:
#
# CDF still contains an integral; can only estimate integral values with
# evalf
#
if hasfun(op(FX[1]), int) then
  for i from 1 to m do
    FittedCDFValues := [op(FittedCDFValues), evalf(subs(x = EmpCDF[2][i], 
        op(FX[1])))]:
    # print(`hard cdf`, FittedCDFValues):
  od:
#
# "Nice" CDF
#
else
  for i from 1 to m do
    FittedCDFValues := [op(FittedCDFValues), subs(x = EmpCDF[2][i], 
        op(FX[1]))]:
    # print(`nice cdf`, FittedCDFValues):
  od:
fi:

KS := 0:
for i from 1 to m - 1 do
  Dpos := evalf(abs(EmpCDFValues[i + 1] - FittedCDFValues[i])):
  Dneg := evalf(abs(FittedCDFValues[i] - EmpCDFValues[i])):
  KS := max(KS, Dpos, Dneg):
  # print(`KS is`, KS):
od:
KS := max(KS, evalf(abs(FittedCDFValues[m] - 1))):

print(`The KS test statistic is`, KS):
RETURN(KS):
end:

#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: kurtosis2.map
#
#  Procedure Name: Kurtosis(X)
#
#  Other APPL Procedures Called: 
#
#  Updated: June 3, 2001
#
#  Purpose: Returns the kurtosis
#
#  Arguments: X: Random Variable
# 
#  Algorithm:
Kurtosis := proc(X :: list(list))
local mu, sigma, Term1, Term2, Term3, Term4, kurt:

mu := ExpectedValue(X):
sigma := sqrt(Variance(X)):
Term1 := ExpectedValue(X, x -> x ^ 4):
Term2 := 4 * mu * ExpectedValue(X, x -> x ^ 3):
Term3 := 6 * mu ^ 2 * ExpectedValue(X, x -> x ^ 2):
Term4 := 3 * mu ^ 4:
# Change on 6/7/2007: Put "simplify" in the kurt expression
kurt := simplify((Term1 - Term2 + Term3 - Term4) / sigma ^ 4):
# previously defined (in kurtosis1.map) as
# kurt := ExpectedValue(X, x -> x ^ 4):
return(kurt):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: max3.map: adding discrete capabilities -> MaximumDiscrete
#  Problem occured in max1.map when receiving an RV with constants 
#  for range limits
#
#  Procedure Name: Maximum(X, Y)
#
#  Other APPL Procedures Called: PDF, Transform, Minimum
#
#  Date:  June 21, 2000
#
#  Purpose:  Maximum is a procedure that returns the PDF of the maximum
#            of two independent RVs 
#
#  Arguments: X, Y: Independent continuous random variables
#
#  Algorithm:
#
Maximum := proc(X, Y)
local lowerX, upperX, fX, nsegsx, lowerY, upperY, fY, nsegsy, fnegX,
    fnegY, fmax:

if (X[3][1] = "Discrete") then
  return(MaximumDiscrete(X, Y)):
fi:
lowerX := -infinity:
upperX := infinity:
fX := PDF(X):
# print(`fX is`, fX):
nsegsx := nops(fX[2]):
if not(fX[2][1] = -infinity) then
  lowerX := fX[2][1]:
  # print(lowerX):
  if hastype(lowerX, symbol) and not(type(lowerX, constant)) then
    assume(lowerX > -infinity):
  fi:
fi:
if not(fX[2][nsegs] = infinity) then
  upperX := fX[2][nsegsx]:
  # print(upperX):
  if hastype(upperX, symbol) and not(type(upperX, constant)) then
    assume(upperX < infinity):
  fi:
fi:

lowerY := -infinity:
upperY := infinity:
fY := PDF(Y):
nsegsy := nops(fY[2]):
if not(fY[2][1] = -infinity) then
  lowerY := fY[2][1]:
  if hastype(lowerY, symbol) and not(type(lowerY, constant)) then
    assume(lowerY > -infinity):
  fi:
fi:
if not(fY[2][nsegs] = infinity) then
  upperY := fY[2][nsegsy]:
  if hastype(upperY, symbol) and not(type(upperY, constant)) then
    assume(upperY < infinity):
  fi:
fi:

fnegX := Transform(fX, [[x -> -x], [lowerX, upperX]]):
# print(`fnegX is`, fnegX):
fnegY := Transform(fY, [[x -> -x], [lowerY, upperY]]):
# print(`fnegY is`, fnegY):
fmax  := Minimum(fnegX, fnegY):
fmax  := Transform(fmax, [[x -> -x], [-infinity, infinity]]):

RETURN(fmax):
end:

#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: maxdiscrete2.map
#  maxdiscrete2.map looking at cases (if possible), X finite, Y
#  infinite, vice versa
#
#  Procedure Name: MaximumDiscrete(X, Y)
#
#  Other APPL Procedures Called: 
#
#  Date:  June 12, 2001
#
#  Purpose:  MaximumDiscrete is a procedure that returns the PDF of the
#            maximum of two independent discrete RVs 
#
#  Arguments: X, Y: Independent discrete random variables
#
#  Algorithm:
#
MaximumDiscrete := proc(X, Y)
local fX, fY, xformulaic, xlo, xhi, xN, XSet, yformulaic, ylo, yhi, yN,
    YSet, MaxSet, i, MaxList, mn, MaxProb, j, MaxPDF, FX, cdfx, FY, 
    cdfy, maxcdf, maxcdf1, pdfx, cdfval, m, lastpdfval, maxpdf1,
    maxpdf2:

# Convert X and Y to their PDF representations (just to get each random
# variable in the same representation form)
fX := PDF(X):
fY := PDF(Y):

# Convert fX to its standard APPL discrete list-of-sublists format.  If
# X has a $Dot$ format and finite support, then convert X to its 
# $NoDot$ format
fX := Convert(fX):
if (fX = false) then
  print(`ERROR(Maximum): Discrete RV X is NOT in legal APPL form`):
  return:
fi:
if type(fX[2][1], range) and not(type(rhs(fX[2][1]), infinity)) then
  fX := ConvertToNoDot(fX):
fi:
# print(`fX is`, fX):

# Convert fY to its standard APPL discrete list-of-sublists format. If
# Y has a $Dot$ format and finite support, then convert Y to its 
# $NoDot$ format
fY := Convert(fY):
if (fY = false) then
  print(`ERROR(Maximum): Discrete RV Y is NOT in legal APPL form`):
  return:
fi:
if type(fY[2][1], range) and not(type(rhs(fY[2][1]), infinity)) then
  fY := ConvertToNoDot(fY):
fi:
# print(`fY is`, fY):

# fX has a standard discrete $Dot$ format with infinite support. Assume
# for now that xincr is 1 and xtransf is x -> x
if type(fX[2][1], range) then
  xformulaic := true:
  xlo := lhs(fX[2][1]):
  xhi := rhs(fX[2][1]):
  # XSet := {xlo, xhi}:
  # xincr := fX[2][2]:
  # xtransf := fX[2][3]:
  # if type(xhi, symbol) then
  if not(type(xhi, infinity)) then
    print(`ERROR(Maximum): X's support must be numeric`):
    return:
  fi:
  if type(xlo, symbol) or evalb(xlo = -infinity) then 
    print(`ERROR(Maximum): X's lower support must be`):
    print(`a finite numerical value.`): 
    return:
  fi:
else
  # print(`NoDot format for X`):
  xN := nops(fX[2]):
  xlo := fX[2][1]:
  xhi := fX[2][xN]:
  XSet := {op(fX[2])}:
  xformulaic := false:
fi:

# fY has a standard discrete Dot format with infinite support. Assume
# for now that yincr is 1 and ytransf is x -> x
if type(fY[2][1], range) then
  yformulaic := true:
  ylo := lhs(fY[2][1]):
  yhi := rhs(fY[2][1]):
  # YSet := {ylo, yhi}:
  # yincr := fY[2][2]:
  # ytransf := fY[2][3]:
  if not(evalb(yhi = infinity)) then
    print(`ERROR(Maximum): Y's support must be numeric`):
    return:
  fi:
  if type(ylo, symbol) or evalb(ylo = -infinity) then 
    print(`ERROR(Maximum): Y's lower support must be`):
    print(`a finite numerical value.`): 
    return:
  fi:
else
  # print(`NoDot format for Y`):
  yN := nops(fY[2]):
  ylo := fY[2][1]:
  yhi := fY[2][yN]:
  YSet := {op(fY[2])}:
  yformulaic := false:
fi:

# Building MaxSet so that it will contain all possible maximum values.
# Don't need to put values from the support of X or Y into the support
# of the maximum if they can never be the maximum
# EX. Omega_X = {1, 3, 7, 9}, Omega_Y = {5, 6, 7}
# The X support values 1 and 3 will never be the maximum
if not(xformulaic) and not(yformulaic) then
  # print(`fX is`, fX):
  # print(`fY is`, fY):
  if xlo = ylo then
    MaxSet := XSet union YSet:
  elif xlo > ylo then
    for i from 2 to yN while (fY[2][i] <= xlo) do
    od:
    if i = yN then
      MaxSet := XSet:
    else
      MaxSet := XSet union YSet[i .. yN]:
    fi:
  else
    for i from 2 to xN while (fX[2][i] <= ylo) do
    od:
    if i = xN then
      MaxSet := YSet:
    else
      MaxSet := YSet union XSet[i .. xN]:
    fi:
  fi:
  # print(`MaxSet is`, MaxSet):
  MaxList := sort([op(MaxSet)], (x, y) -> evalb(evalf(x) < evalf(y))):
  MaxList := ReduceList(MaxList):
  mn := nops(MaxList):
  # print(`MaxList is`, MaxList):
  MaxProb := []:
  for j from 1 to mn do
    MaxProb := [op(MaxProb), CDF(X, MaxList[j]) * CDF(Y, MaxList[j])]:
  od:
  # print(MaxProb, MaxList):
  MaxPDF := PDF([MaxProb, MaxList, ["Discrete", "CDF"]]):
elif xformulaic or yformulaic then
  if xformulaic and yformulaic then
    FX := CDF(X):
    cdfx := op(unapply(FX[1](x))(x)):
    FY := CDF(Y):
    cdfy := op(unapply(FY[1](x))(x)):
    if xlo = ylo then
      maxcdf := simplify(cdfx * cdfy):
      MaxPDF := PDF([[unapply(maxcdf, x)], FX[2], ["Discrete", "CDF"]]):
    elif xlo > ylo then
      maxcdf := simplify(cdfx * cdfy):
      MaxPDF := PDF([[unapply(maxcdf, x)], FX[2], ["Discrete", "CDF"]]):
    else
      maxcdf := simplify(cdfx * cdfy):
      MaxPDF := PDF([[unapply(maxcdf, x)], FY[2], ["Discrete", "CDF"]]):
    fi:
  # X infinite, Y finite
  elif xformulaic and not(yformulaic) then
    FX := CDF(X):
    cdfx := op(unapply(FX[1](x))(x)):
    maxcdf1 := []:
    if xlo = ylo then
      # Explain in chapter why going from ...
      pdfx := op(unapply(fX[1](x))(x)):
      for i from ylo to yhi do
        cdfval := subs(x = i, cdfx) * CDF(Y, i):
        # print(`cdf value is`):
        # print(cdfval):
        maxcdf1 := [op(maxcdf1), cdfval]:
      od:
      # print(`maxcdf1 is`):
      # print(maxcdf1):
      m := nops(maxcdf1):
      lastpdfval := 1 - sum(maxcdf1[k], k = 1 .. m):
      maxpdf1 := PDF([[op(maxcdf1), 1], [$ylo .. yhi, yhi + 1], 
          ["Discrete", "CDF"]]):
      # print(`maxpdf1 is`, maxpdf1): 
      maxpdf2 := pdfx:
      MaxPDF := [[op(maxpdf1[1][1 .. m]), unapply(maxpdf2, x)], 
          [$ylo .. yhi, yhi + 1 .. infinity], ["Discrete", "PDF"]]:
    elif xlo > ylo then
      if xlo >= yhi then
        MaxPDF := X:
      else
        pdfx := op(unapply(fX[1](x))(x)):
        for i from xlo to yhi do
          cdfval := subs(x = i, cdfx) * CDF(Y, i):
          # print(cdfval):
          maxcdf1 := [op(maxcdf1), cdfval]:
        od:
        m := nops(maxcdf1):
        lastpdfval := 1 - sum(maxcdf1[k], k = 1 .. m):
        maxpdf1 := PDF([[op(maxcdf1), 1], [$xlo .. yhi, yhi + 1], 
            ["Discrete", "CDF"]]):
        # print(`maxpdf1 is`, maxpdf1): 
        maxpdf2 := pdfx:
        MaxPDF := [[op(maxpdf1[1][1 .. m]), unapply(maxpdf2, x)], 
            [$xlo .. yhi, yhi + 1 .. infinity], ["Discrete", "PDF"]]:
      fi:
    else
      pdfx := op(unapply(fX[1](x))(x)):
      for i from ylo to yhi do
        cdfval := subs(x = i, cdfx) * CDF(Y, i):
        # print(cdfval):
        maxcdf1 := [op(maxcdf1), cdfval]:
      od:
        m := nops(maxcdf1):
        lastpdfval := 1 - sum(maxcdf1[k], k = 1 .. m):
        maxpdf1 := PDF([[op(maxcdf1), 1], [$ylo .. yhi, yhi + 1], 
            ["Discrete", "CDF"]]):
        # print(`maxpdf1 is`, maxpdf1): 
        maxpdf2 := pdfx:
        MaxPDF := [[op(maxpdf1[1][1 .. m]), unapply(maxpdf2, x)], 
            [$ylo .. yhi, yhi + 1 .. infinity], ["Discrete", "PDF"]]:
    fi:
  # X finite, Y infinite ... just flip-flop the code above for
  # X infinite, Y finite
  elif not(xformulaic) and yformulaic then
    print(`not currently written for X finite, Y infinite`):
    print(`just reverse X and Y variables and redo`):
  fi:
fi:
return(MaxPDF):  
end:#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: maximumiid1.map
#
#  Procedure Name: MaximumIID(X, n)
#
#  Other APPL Procedures Called: 
#
#  Date:  June 12, 2001
#
#  Purpose:  MaximumIID is a procedure that returns the PDF of the
#            maximum of n iid random variables 
#
#  Arguments: X: Discrete random variable, n: positive integer
#
#  Algorithm:
#
MaximumIID := proc(X, n)
local fX:

fX := OrderStat(X, n, n):
return(fX):

end:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: mean9.map
#
#  Procedure Name: Mean(X)
#
#  Other APPL Procedures Called: PDF, Convert
#
#  Updated: August 3, 2000
#
#  Purpose: Returns the mean of a distribution. 
#
#  Arguments: X: Random Variable
# 
#  Algorithm:
#    1. Check for the appropriate number of arguments
#    2. Check that the RV X is in the list of 3 lists format
#    3. Convert X to PDF form if not already in that form
#    4. Call the procedure ExpectedValue with the RV X and g := x -> x 
#    5. Return the mean of the RV X
#
Mean := proc(X :: list(list))
local NumLists, fX, nsegments, mean, i, SubList1, SubList2, Support, Lo,
    Hi, IncrBy, Transformation, TransfPDF, NextValue, n:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 1) then
  print(`ERROR(Mean): This procedure requires 1 argument:`):
  print(`A random variable`):
  RETURN(false):
fi:
#
#  Check that the RV X is in a list of 3 lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(Mean): The RV X must be in a list of 3 lists format`):
  RETURN(false):
fi:
#
#  Make sure X is given as a PDF, CDF, SF, HF, CHF, or IDF
#
if not(member(X[3][2], {"PDF", "CDF", "SF", "HF", "CHF", "IDF"})) then
  print(`ERROR(Mean): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  RETURN():
fi:

mean := ExpectedValue(X, x -> x):
# print(mean):
if type(false, BooleanOpt(mean)) then
  return:
else
  return(simplify(mean)):
fi:
end:
#1111111111222222222233333333334444444444555555555566666666667777777777#  
#  Filename: menu1.map
#
#  Procedure name: Menu(Item), where Item is either All, Continuous, Discrete, or
#                  Procedures
#
#  Other APPL Procedures Called: None
#             
#  Date Revised: June 7, 1999
#
#  Purpose: APPL Menu   
#
#  Arguments: (optional)
#             Menu or Menu(All): Returns the list of continuous and discrete 
#               distributions and the list of APPL procedures
#             Menu(Continuous): Returns the list of continuous distributions only
#             Menu(Discrete): Returns the list of discrete distributions only
#             Menu(Procedures): Returns the list of APPL procedures only
#
Menu := proc(Item)
#
#  Check for the appropriate number of arguments
#
if (nargs <> 1) then
  print(`ERROR(Menu): Procedure requires 1 of the following as an argument:`):
  print(`All, Continuous, Discrete, or Procedures`):
  RETURN():
fi:
if (Item = `All`) then 
  print(`CONTINUOUS DISTRIBUTIONS:`):
  print(`ArcSinRV()`, `ArcTanRV(alpha, phi)`, `BetaRV(beta, gamma)`,
    `CauchyRV(a, alpha)`, `ChiRV(n)`, `ChiSquareRV(n)`, `DoublyNoncentralFRV()`, 
    `DoublyNoncentralTRV()`, `ErlangRV(lambda, n)`, `ErrorRV(mu, alpha, d)`,
    `ExponentialRV(lambda)`, `ExponentialPowerRV(lambda, kappa)`, 
    `ExtremeValueRV(alpha, beta)`, `FRV(n1, n2)`, `GammaRV(lambda, kappa)`,
    `GeneralizedParetoRV(gamma, delta, kappa)`, `GompertzRV(delta, kappa)`, 
    `HyperbolicSecantRV()`, `HyperExponentialRV(p,l)`, `HypoExponentialRV(l)`, 
    `IDBRV(gamma, delta, kappa)`, `InverseGaussianRV(lambda, mu)`, 
    `InvertedGammaRV(alpha, beta)`, `KSRV(n)`, `LaPlaceRV(omega, theta)`, 
    `LogGammaRV(alpha, beta)`, `LogisticRV(kappa, lambda)`, 
    `LogLogisticRV(lambda, kappa)`, 
    `LogNormalRV(mu, sigma)`, `LomaxRV(kappa, lambda)`, 
    `MakehamRV(gamma, delta, kappa)`, `MuthRV(kappa)`, `NoncentralChiSquareRV()`,
    `NoncentralFRV()`, `NoncentralTRV()`, `NormalRV(mu, sigma)`, 
    `ParetoRV(lambda, kappa)`, `RayleighRV(lambda)`, `StandardCauchyRV()`,
    `StandardNormalRV()`, `StandardTriangularRV(m)`, `StandardUniformRV()`,
    `TRV(n)`, `TriangularRV(a, m, b)`, `UniformRV(a, b)`, 
    `WeibullRV(lambda, kappa)`):
  print(``):
  print(`DISCRETE DISTRIBUTIONS:`):
  print(`BenfordRV()`, `BinomialRV(n, p)`, `GeometricRV(p)`, `PoissonRV(lambda)`):
  print(``):
  print(`PROCEDURES:`):
  print(`X and Y are random variables; n and r are positive integers, n >= r`):
  print(`g is a function`):
  print(`Brackets [] denote optional parameters`):
  print(`A capitalized parameter, such as Sample, indicates that it must be`): 
  print(`entered as a list --> ex. Sample := [1, 12.4, 34, 52.45, 63]`):
  print(`Benford(X)`, `CDF:CHF:HF:IDF:PDF:SF(X, [x]))`, `CriticalPoint(X, prob)`, 
    `Display(X)`, `ExpectedValue(X, g)`, `Maximum(X, Y)`, `Mean(X)`, 
    `Minimum(X, Y)`, `Mixture(MixParameters, MixRVs)`, 
    `MLE(X, Sample, Parameters, [Rightcensor])`, `MOM(X, Sample, Parameters)`, 
    `OrderStat(X, n, r)`, `PlotDist(X, low, high)`, `Product(X, Y)`, 
    `ProductIID(X, n)`, `Sum(X, Y)`, `SumIID(X, n)`, `Transform(X, g)`, 
    `Truncate(X, low, high)`, `Variance(X)`, `VerifyPDF(X)`):
print(``):
elif (Item = `Continuous`) then
  print(`CONTINUOUS DISTRIBUTIONS:`):
  print(`ArcSinRV()`, `ArcTanRV(alpha, phi)`, `BetaRV(beta, gamma)`,
    `CauchyRV(a, alpha)`, `ChiRV(n)`, `ChiSquareRV(n)`, `DoublyNoncentralFRV()`, 
    `DoublyNoncentralTRV()`, `ErlangRV(lambda, n)`, `ErrorRV(mu, alpha, d)`,
    `ExponentialRV(lambda)`, `ExponentialPowerRV(lambda, kappa)`, 
    `ExtremeValueRV(alpha, beta)`, `FRV(n1, n2)`, `GammaRV(lambda, kappa)`,
    `GeneralizedParetoRV(gamma, delta, kappa)`, `GompertzRV(delta, kappa)`, 
    `HyperbolicSecantRV()`, `HyperExponentialRV(p,l)`, `HypoExponentialRV(l)`, 
    `IDBRV(gamma, delta, kappa)`, `InverseGaussianRV(lambda, mu)`, 
    `InvertedGammaRV(alpha, beta)`, `KSRV(n)`, `LaPlaceRV(omega, theta)`, 
    `LogGammaRV(alpha, beta)`, `LogisticRV(kappa, lambda)`, 
    `LogLogisticRV(lambda, kappa)`, 
    `LogNormalRV(mu, sigma)`, `LomaxRV(kappa, lambda)`, 
    `MakehamRV(gamma, delta, kappa)`, `MuthRV(kappa)`, `NoncentralChiSquareRV()`,
    `NoncentralFRV()`, `NoncentralTRV()`, `NormalRV(mu, sigma)`, 
    `ParetoRV(lambda, kappa)`, `RayleighRV(lambda)`, `StandardCauchyRV()`,
    `StandardNormalRV()`, `StandardTriangularRV(m)`, `StandardUniformRV()`,
    `TRV(n)`, `TriangularRV(a, m, b)`, `UniformRV(a, b)`, 
    `WeibullRV(lambda, kappa)`):
  print(``):
elif (Item = `Discrete`) then
  print(`DISCRETE DISTRIBUTIONS:`):
  print(`BenfordRV()`, `BinomialRV(n, p)`, `GeometricRV(p)`, `PoissonRV(lambda)`):
  print(``):
elif (Item = `Procedures`) then
  print(`PROCEDURES:`):
  print(`X and Y are random variables; n and r are positive integers, n >= r`):
  print(`g is a function`):
  print(`Brackets [] denote optional parameters`):
  print(`A capitalized parameter, such as Sample, indicates that it must be`): 
  print(`entered as a list --> ex. Sample := [1, 12.4, 34, 52.45, 63]`):
  print(`Benford(X)`, `CDF:CHF:HF:IDF:PDF:SF(X, [x]))`, `CriticalPoint(X, prob)`, 
    `Display(X)`, `ExpectedValue(X, g)`, `Maximum(X, Y)`, `Mean(X)`, 
    `Minimum(X, Y)`, `Mixture(MixParameters, MixRVs)`, 
    `MLE(X, Sample, Parameters, [Rightcensor])`, `MOM(X, Sample, Parameters)`, 
    `OrderStat(X, n, r)`, `PlotDist(X, low, high)`, `Product(X, Y)`, 
    `ProductIID(X, n)`, `Sum(X, Y)`, `SumIID(X, n)`, `Transform(X, g)`, 
    `Truncate(X, low, high)`, `Variance(X)`, `VerifyPDF(X)`):
print(``):
else
  print(`ERROR(Menu): The menu argument must be one of the following:`):
  print(`All, Continuous, Discrete, or Procedures`):
fi:
end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: mgf2.map
#  ADDING DISCRETE CAPABILITIES
#
#  Procedure Name: MGF(X)
#
#  Other APPL Procedures Called: ExpectedValue
#
#  Updated: August 8, 2000
#
#  Purpose: Returns the moment-generating function of a distribution. 
#
#  Arguments: X: Random Variable
# 
#  Algorithm:
#    1. Check for the appropriate number of arguments
#    2. Check that the RV X is in the list of 3 lists format
#    3. Check that X is given as a PDF, CDF, SF, HF, CHF, or IDF
#    4. Call the procedure ExpectedValue with the RV X and
#       g := x -> exp(t * x) 
#    5. Return the MGF of the RV X
#
MGF := proc(X :: list(list))
local NumLists, mgf:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 1) then
  print(`ERROR(MGF): This procedure requires 1 argument:`):
  print(`A random variable`):
  RETURN(false):
fi:
#
#  Check that the RV X is in a list of 3 lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(MGF): The RV X must be in a list of 3 lists format`):
  RETURN(false):
fi:
#
#  Make sure X is given as a PDF, CDF, SF, HF, CHF, or IDF
#
if not(member(X[3][2], {"PDF", "CDF", "SF", "HF", "CHF", "IDF"})) then
  print(`ERROR(MGF): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  RETURN():
fi:

mgf := ExpectedValue(X, x -> exp(t * x)):
RETURN(mgf):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: min3.map
#  
#  Procedure Name: Minimum(X, Y)
#
#  Other APPL Procedures Called: PDF, ReduceList, CDF
#  
#  Date:  June 21, 2000
#
#  Purpose:  Minimum is a procedure that returns the PDF of the minimum
#            of two independent RVs 
#
#  Arguments: X, Y: Independent continuous random variables
#
#  Algorithm:
#
Minimum := proc(X, Y)
local  fX, fY, fmin, i, j, nsegments,FX, FY, Fmin, ffmin, x, currFX,
    currFY, highest, highesti, stoppoint, Xindex, Yindex:

if (X[3][1] = "Discrete") then
  return(MinimumDiscrete(X, Y)):
fi:
fX := PDF(X):
fY := PDF(Y):
# print(max(op(fX[2]))):
# print(max(op(fY[2]))):
# print(min(max(op(fX[2])), max(op(fY[2])))):
fmin[2] := [op(fX[2]), op(fY[2])]:
# print(`fmin[2] is`, fmin[2]):
fmin[2] := sort([op(fmin[2])], (x, y) -> evalb(evalf(x) < evalf(y))):
fmin[2] := ReduceList(fmin[2]):

#
# Now delete any elements that are above the lower support max
#
highest := min(max(op(fX[2])), max(op(fY[2]))):
stoppoint := nops(fmin[2]):

# 
# ID the max support of the new RV
#
for i from 1 to stoppoint do
  if (fmin[2][i] = highest) then
    highesti := i:
    break:
  fi:
od:

#
# Remove from support list all values too high
#
if (highesti <> fmin[2][stoppoint]) then 
  for j from (highesti + 1) to stoppoint do
    fmin[2] := subsop((highesti + 1) = NULL, fmin[2]):
  od:
fi:

FX := CDF(fX):
FY := CDF(fY):
nsegments := nops(fmin[2]) - 1:
Xindex := 1:
Yindex := 1:

fmin[1] := []:
for i from 1 to nsegments do
  # print(FX,FY):
  if (fmin[2][i] < fX[2][1])  then
    currFX := x -> 0:
  elif (fmin[2][i] = fX[2][Xindex]) then
    currFX := FX[1][Xindex]:
    Xindex := Xindex + 1:	 
  fi:
  if (fmin[2][i] < fY[2][1]) then
    currFY := x -> 0:
  elif (fmin[2][i] = fY[2][Yindex]) then
    currFY := FY[1][Yindex]:
    Yindex := Yindex + 1:	 
  fi:
  # print('currently',currFX, currFY):
  Fmin := simplify(1 - (1 - currFX(x)) * (1 - currFY(x))):
  Fmin := unapply(Fmin, x):
  # print('Fminis',Fmin):
  ffmin := diff(Fmin(x), x):
  ffmin := simplify(ffmin):
  # print('ffminis', ffmin):
  fmin[1] := [op(fmin[1]), unapply(ffmin, x)]:
  # print(fmin1is,fmin[1]):
od:
RETURN([fmin[1], fmin[2], ["Continuous", "PDF"]]):

end:

#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: mindiscrete2.map
#
#  Procedure Name: MinimumDiscrete(X, Y)
#
#  Other APPL Procedures Called: 
#
#  Date:  June 12, 2001
#
#  Purpose:  MinimumDiscrete is a procedure that returns the PDF of the
#            minimum of two independent discrete RVs 
#
#  Arguments: X, Y: Independent discrete random variables
#
#  Algorithm:
#
MinimumDiscrete := proc(X, Y)
local fX, fY, xformulaic, xlo, xhi, xN, XSet, yformulaic, ylo, yhi, yN,
    YSet, MinSet, i, MinList, mn, MinProb, j, MinPDF, FX, cdfx, FY,
    cdfy, mincdf, minpdf1, minpdf2, mincdf2, mindpdf2, cdfval, END, 
    cdfsupp, prev, pdfx, pdfy:

# Convert X and Y to their PDF representations (just to get each random
# variable in the same representation form)
fX := PDF(X):
fY := PDF(Y):

# Convert fX to its standard APPL discrete list-of-sublists format.  If
# X has a $Dot$ format and finite support, then convert X to its 
# $NoDot$ format
fX := Convert(fX):
if (fX = false) then
  print(`ERROR(Minimum): Discrete RV X is NOT in legal APPL form`):
  return:
fi:
if type(fX[2][1], range) and not(type(rhs(fX[2][1]), infinity)) then
  fX := ConvertToNoDot(fX):
fi:
# print(`fX is`, fX):

# Convert fY to its standard APPL discrete list-of-sublists format. If
# Y has a $Dot$ format and finite support, then convert Y to its 
# $NoDot$ format
fY := Convert(fY):
if (fY = false) then
  print(`ERROR(Minimum): Discrete RV Y is NOT in legal APPL form`):
  return:
fi:
if type(fY[2][1], range) and not(type(rhs(fY[2][1]), infinity)) then
  fY := ConvertToNoDot(fY):
fi:
# print(`fY is`, fY):

# fX has a standard discrete $Dot$ format with infinite support. Assume
# for now that xincr is 1 and xtransf is x -> x
if type(fX[2][1], range) then
  xformulaic := true:
  xlo := lhs(fX[2][1]):
  xhi := rhs(fX[2][1]):
  # XSet := {xlo, xhi}:
  # xincr := fX[2][2]:
  # xtransf := fX[2][3]:
  # if type(xhi, symbol) then
  if not(type(xhi, infinity)) then
    print(`ERROR(Minimum): X's support must be numeric`):
    return:
  fi:
  if type(xlo, symbol) or evalb(xlo = -infinity) then 
    print(`ERROR(Minimum): X's lower support must be`):
    print(`a finite numerical value.`): 
    return:
  fi:
else
  # print(`NoDot format for X`):
  xN := nops(fX[2]):
  xlo := fX[2][1]:
  xhi := fX[2][xN]:
  XSet := {op(fX[2])}:
  xformulaic := false:
fi:

# fY has a standard discrete Dot format with infinite support. Assume
# for now that yincr is 1 and ytransf is x -> x
if type(fY[2][1], range) then
  yformulaic := true:
  ylo := lhs(fY[2][1]):
  yhi := rhs(fY[2][1]):
  # YSet := {ylo, yhi}:
  # yincr := fY[2][2]:
  # ytransf := fY[2][3]:
  if not(evalb(yhi = infinity)) then
    print(`ERROR(Minimum): Y's support must be numeric`):
    return:
  fi:
  if type(ylo, symbol) or evalb(ylo = -infinity) then 
    print(`ERROR(Minimum): Y's lower support must be`):
    print(`a finite numerical value.`): 
    return:
  fi:
else
  # print(`NoDot format for Y`):
  yN := nops(fY[2]):
  ylo := fY[2][1]:
  yhi := fY[2][yN]:
  YSet := {op(fY[2])}:
  yformulaic := false:
fi:

# Building MinSet so that it will contain all possible minimum values.
# Don't need to put values from the support of X or Y into the support
# of the minimum if they can never be the minimum
# EX. Omega_X = {1, 3, 7, 9}, Omega_Y = {5, 6, 7, 14, 18}
# The Y support values 14 and 18 will never be the minimum
if not(xformulaic) and not(yformulaic) then
  # print(`fX is`, fX):
  # print(`fY is`, fY):
  # print(`xhi is`, xhi):
  # print(`yhi is`, yhi):
  if xhi = yhi then
    MinSet := XSet union YSet:
  elif xhi > yhi then
    for i from xN - 1 by -1 to 1 while (fX[2][i] > yhi) do
    od:
    # print(`i is`, i):
    if i = 1 then
      MinSet := YSet:
    else
      # print(`i is`, i):
      MinSet := YSet union XSet[1 .. i]:
    fi:
  else
    for i from yN - 1 by -1 to 1 while (fY[2][i] > xhi) do
    od:
    if i = 1 then
      MinSet := XSet:
    else
      MinSet := XSet union XSet[1 .. i]:
    fi:
  fi:
  # print(`MinSet is`, MinSet):
  MinList := sort([op(MinSet)], (x, y) -> evalb(evalf(x) < evalf(y))):
  MinList := ReduceList(MinList):
  mn := nops(MinList):
  # print(`MinList is`, MinList):
  MinProb := []:
  for j from 1 to mn do
    MinProb := [op(MinProb), 1 - (1 - CDF(X, MinList[j])) * 
        (1 - CDF(Y, MinList[j]))]:
  od:
  # print(`CDF is:`):
  # print(MinProb, MinList):
  MinPDF := PDF([MinProb, MinList, ["Discrete", "CDF"]]):
elif xformulaic or yformulaic then
  if xformulaic and yformulaic then
    FX := CDF(X):
    cdfx := op(unapply(FX[1](x))(x)):
    FY := CDF(Y):
    cdfy := op(unapply(FY[1](x))(x)):
    if xlo = ylo then
      mincdf := simplify(1 - (1 - cdfx) * (1 - cdfy)):
      MinPDF := PDF([[unapply(mincdf, x)], FX[2], ["Discrete", "CDF"]]):
    elif xlo > ylo then
      minpdf1 := op(unapply(fY[1](x))(x)):
      mincdf2 := simplify(1 - (1 - cdfx) * (1 - cdfy)):
      minpdf2 := simplify(subs(x = x, mincdf2) - 
          subs(x = x - 1, mincdf2)): 
      MinPDF := [[unapply(minpdf1, x), unapply(minpdf2, x)], 
          [ylo .. xlo - 1, xlo .. infinity], ["Discrete", "PDF"]]:
    elif xlo < ylo then
      minpdf1 := op(unapply(fX[1](x))(x)):
      mincdf2 := simplify(1 - (1 - cdfx) * (1 - cdfy)):
      minpdf2 := simplify(subs(x = x, mincdf2) - 
          subs(x = x - 1, mincdf2)): 
      MinPDF := [[unapply(minpdf1, x), unapply(minpdf2, x)], 
          [xlo .. ylo - 1, ylo .. infinity], ["Discrete", "PDF"]]:
    fi:
  # X infinite, Y finite
  elif xformulaic and not(yformulaic) then
    # print(`X infinite, Y finite`):
    FX := CDF(X):
    cdfx := op(unapply(FX[1](x))(x)):
    mincdf := []:
    if xlo = ylo then
      # Explain in chapter why going from ylo to yhi
      # Use example: X ~ Geometric, Y := [],[1, 3],[]
      for i from ylo to yhi do
        cdfval := 1 - (1 - subs(x = i, cdfx)) * (1 - CDF(Y, i)):
        # print(cdfval):
        mincdf := [op(mincdf), cdfval]:
      od:
      # print(mincdf):
      MinPDF := PDF([mincdf, [$ylo .. yhi], ["Discrete", "CDF"]]):
    elif xlo > ylo then
      # print(`xlo is`, xlo):
      # print(`ylo is`, ylo):
      # print(yN):
      for END from 1 to yN while fY[2][END] <= xlo do
         # print(fY[2][END]):
      od:
      # print(`END is`, END):
      cdfsupp := [seq(fY[2][j], j = 1 .. END - 1)]:
      # print(`cdfsupp is`, cdfsupp):
      prev := 0:
      for j from 1 to END - 1 do
        # print(`j is`, j):
        # print(fY[1]):
        # print(fY[1][j]):
        mincdf := [op(mincdf), prev + fY[1][j]]:
        prev := prev + fY[1][j]:
        # print(`mincdf is`, mincdf):
      od:
      # print(`first part of cdf and mincdf are`):
      # print(cdfsupp): # print(mincdf):
      for i from xlo to yhi do
        cdfval := 1 - (1 - subs(x = i, cdfx)) * (1 - CDF(Y, i)):
        # print(cdfval):
        mincdf := [op(mincdf), cdfval]:
      od:
      # print(mincdf):
      MinPDF := PDF([mincdf, [op(cdfsupp), $xlo .. yhi], 
          ["Discrete", "CDF"]]):
    else
      # print(`xlo is`, xlo):
      # print(`ylo is`, ylo):
      END := ylo - xlo:
      # print(`END is`, END):
      cdfsupp := [$xlo .. yhi]:
      # print(`cdfsupp is`, cdfsupp):
      pdfx := op(unapply(fX[1](x))(x)):
      prev := 0:
      for j from xlo to END do
        # print(`j is`, j):
        cdfval := subs(x = j, cdfx):
        mincdf := [op(mincdf), cdfval]:
        # print(`mincdf is`, mincdf):
      od:
      # print(`first part of cdf and mincdf are`):
      # print(cdfsupp): # print(mincdf):
      for i from END + 1 to yhi do
        cdfval := 1 - (1 - subs(x = i, cdfx)) * (1 - CDF(Y, i)):
        # print(cdfval):
        mincdf := [op(mincdf), cdfval]:
      od:
      # print(mincdf):
      MinPDF := PDF([mincdf, cdfsupp, ["Discrete", "CDF"]]):     
    fi:
  # X finite, Y infinite
  elif not(xformulaic) and yformulaic then
    # print(`X finite, Y infinite`):
    FY := CDF(Y):
    cdfy := op(unapply(FY[1](x))(x)):
    mincdf := []:
    if ylo = xlo then
      # Explain in chapter why going from ylo to yhi
      # Use example: X ~ Geometric, Y := [],[1, 3],[]
      for i from xlo to xhi do
        cdfval := 1 - (1 - subs(x = i, cdfy)) * (1 - CDF(X, i)):
        # print(cdfval):
        mincdf := [op(mincdf), cdfval]:
      od:
      # print(mincdf):
      MinPDF := PDF([mincdf, [$xlo .. xhi], ["Discrete", "CDF"]]):
    elif ylo > xlo then
      # print(`xlo is`, xlo):
      # print(`ylo is`, ylo):
      # print(xN):
      for END from 1 to xN while fX[2][END] <= ylo do
         # print(fX[2][END]):
      od:
      # print(`END is`, END):
      cdfsupp := [seq(fX[2][j], j = 1 .. END - 1)]:
      # print(`cdfsupp is`, cdfsupp):
      prev := 0:
      for j from 1 to END - 1 do
        # print(`j is`, j):
        # print(fX[1]):
        # print(fX[1][j]):
        mincdf := [op(mincdf), prev + fX[1][j]]:
        prev := prev + fX[1][j]:
        # print(`mincdf is`, mincdf):
      od:
      # print(`first part of cdf and mincdf are`):
      # print(cdfsupp): # print(mincdf):
      for i from END to xhi do
        cdfval := 1 - (1 - subs(x = i, cdfy)) * (1 - CDF(X, i)):
        # print(cdfval):
        mincdf := [op(mincdf), cdfval]:
      od:
      # print(mincdf):
      MinPDF := PDF([mincdf, [op(cdfsupp), $END .. xhi], 
          ["Discrete", "CDF"]]):
    else
      # print(`xlo is`, xlo):
      # print(`ylo is`, ylo):
      END := xlo - ylo:
      # print(`END is`, END):
      cdfsupp := [$ylo .. xhi]:
      # print(`cdfsupp is`, cdfsupp):
      pdfy := op(unapply(fY[1](x))(x)):
      prev := 0:
      for j from ylo to END do
        # print(`j is`, j):
        cdfval := subs(x = j, cdfy):
        mincdf := [op(mincdf), cdfval]:
        # print(`mincdf is`, mincdf):
      od:
      # print(`first part of cdf and mincdf are`):
      # print(cdfsupp): # print(mincdf):
      for i from END + 1 to xhi do
        cdfval := 1 - (1 - subs(x = i, cdfy)) * (1 - CDF(X, i)):
        # print(cdfval):
        mincdf := [op(mincdf), cdfval]:
      od:
      # print(mincdf):
      MinPDF := PDF([mincdf, cdfsupp, ["Discrete", "CDF"]]):     
    fi:
  fi:
fi:
return(MinPDF):  
end:

#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: minimumiid1.map
#
#  Procedure Name: MinimumIID(X, n)
#
#  Other APPL Procedures Called: 
#
#  Date:  June 12, 2001
#
#  Purpose:  MinimumIID is a procedure that returns the PDF of the
#            maximum of n iid random variables 
#
#  Arguments: X: Discrete random variable, n: positive integer
#
#  Algorithm:
#
MinimumIID := proc(X, n)
local fX:

fX := OrderStat(X, n, 1):
return(fX):

end:
#1111111111222222222233333333334444444444555555555566666666667777777777#  
#  Filename: mixture10.map
#
#  Procedure Name: Mixture(MixParameters, MixRVs)
#
#  Other APPL Procedures Called: PDF 
#
#  Date: March 12, 1999
#
#  Purpose: "Mixes" random variables X1, X2, ... Xn by taking weighted sums of the 
#  distributions
#
#  Arguments: MixParameters: A list of probabilities p1, p2, ... pn, where p#
#  determines what proportion of the mixture density comes from distribution X#,
#  also p1 + p2 + ... + pn = 1;
#  MixRVs: X1, X2, ... Xn are the random variables of the component distributions
#  that make up the mixture distribution
# 
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Check that the first argument is a list
#    3.  Check that the second argument is a list
#    4.  Check that the length of MixParameters and MixRVs match
#    5.  Check for symbolic mixture parameters
#    6.  Check each element of MixParameters to make sure it is in [0, 1] 
#    7.  Check that the sum of the elements of the MixParameters argument is 1
#    8.  Check that each element of MixRVs represents a continuous random variable  
#    9.  Convert MixRVs to PDF form if not already in that form
#   10.  Compute the support of the mixture as the union of the supports of MixRVs
#   11.  Compute and return the mixed PDF in the list-of-3-lists format
#        (NOTE: A conditional expression was placed in the mixed PDF loop to 
#         check for PDF's that are NOT of the form [x -> !]; the Maple "op"
#         command reads these PDF's differently since the operation x is not
#         in the PDF's expression)
#  
Mixture := proc(MixParameters :: list, MixRVs :: list)
local NumMixParams, NumMixRVs, i, n, SumOfMixParams, RatSumOfMixParams, MixfX,
    MixSupp, MixSuppList, LengthMixSuppList, fXnew, newMixfX, j, m, k, buildfX:
#
#  Check for the appropriate number of arguments 
#
if (nargs <> 2) then
  print(`ERROR(Mixture): This procedure requires 2 arguments:`):
  print(`MixParameters and MixRVs`):
  print(`Both arguments need to be in a list format`):
  RETURN():
fi:
#
#  Check that the second argument is a list
#
NumMixParams := nops(MixParameters):
NumMixRVs := nops(MixRVs):
if not(type(MixRVs, list(list(list)))) then
  print(`ERROR(Mixture): The second argument, MixRVs, must be a list`):
  for i from 1 to NumMixRVs do
    if (not(type(MixRVs[i], list)) or nops(MixRVs[i]) != 3) then
      print(`Each RV component must be in a list of 3 lists format`):
      RETURN():
    fi:
  od:
  RETURN():
fi:
#
#  Check that the length of MixParameters and MixRVs match
#
if not(is(NumMixParams = NumMixRVs)) then
  print(`ERROR(Mixture): The length of the two arguments must match`):
  RETURN():
fi:
n := NumMixParams:
#
#  Note: it is impossible at this time (Maple V, Release 5) to assume that
#  the sum of MixParameters elements (if symbolic) is 1.  Therefore, the procedure 
#  returns an error message if it encounters a symbolic element in the
#  MixParameters argument
#
#  Check for symbolic mixture parameters
#
for i from 1 to n do
  if (whattype(evalf(MixParameters[i])) = symbol) then
    print(`ERROR(Mixture): No symbolic mix parameter elements`):
    RETURN():
  fi:
od:
#
# Check each element of the MixParameters argument to see if it is in [0, 1] 
#
for i from 1 to n do
  if (is(MixParameters[i] < 0) or is(MixParameters[i] > 1)) then
    print(`ERROR(Mixture): Each mix parameter p_i satisfies 0 <= p_i <= 1`):
    RETURN():
  fi:
od:
#
#  Check that the sum of the elements of the MixParameters argument is 1
#
SumOfMixParams := sum(MixParameters[j], j = 1 .. n):
RatSumOfMixParams := convert(SumOfMixParams, rational):
if (RatSumOfMixParams <> 1) then
  print(`ERROR(Mixture): The mix parameters (first argument) must sum to 1`):
  RETURN():
fi:
#
#  Check that each element of MixRVs represents a continuous random variable  
#
for i from 1 to n do
  if not(MixRVs[i][3][1] = "Continuous") then
    print(`ERROR(Mixture): MixRVs elements (second arg) must be continuous`):
    RETURN():
  fi:
od:
#
#  Convert MixRVs to PDF form if not already in that form
#
for i from 1 to n do
  if (MixRVs[i][3][2] = "PDF") then
    MixfX[i] := MixRVs[i]:
  else
    if ((MixRVs[i][3][2] = "CDF") or
        (MixRVs[i][3][2] = "SF") or
        (MixRVs[i][3][2] = "HF") or
        (MixRVs[i][3][2] = "CHF") or
        (MixRVs[i][3][2] = "IDF")) then
      MixfX[i] := PDF(MixRVs[i]):
    else
      print(`ERROR(Mixture): MixRVs elements (second arg) must be`):
      print(`PDF, CDF, SF, HF, CHF, or IDF`):
      RETURN():
    fi:
  fi:
od:
#
#  Compute the support of the mixture as the union of the supports of MixRVs
#
MixSupp := {op(MixfX[1][2])}:
for i from 2 to n do
  MixSupp := MixSupp union {op(MixfX[i][2])}
od:
MixSuppList := sort([op(MixSupp)], (x, y) -> evalb(evalf(x) < evalf(y))):
LengthMixSuppList := nops(MixSuppList):
#
#  Compute and return the mixed PDF in the list-of-3-lists format
#
fXnew := []:
for i from 1 to (LengthMixSuppList - 1) do
  newMixfX := 0:
  for j from 1 to n do
    m := nops(MixfX[j][2]) - 1:
    for k from 1 to m do   
      if (evalf(MixfX[j][2][k]) <= evalf(MixSuppList[i]) and
          evalf(MixSuppList[i + 1]) <= evalf(MixfX[j][2][k + 1])) then
        buildfX := unapply(simplify(MixfX[j][1][k](x) * MixParameters[j]), x):
        newMixfX := unapply(simplify(newMixfX(x) + buildfX(x)), x):
      fi:
    od:
  od:
  if is(whattype(op(1, unapply(simplify(newMixfX(x) + buildfX(x)), x))) = symbol)  
      then
    fXnew := [op(fXnew), op(newMixfX)]:
  else
    fXnew := [op(fXnew), newMixfX]:
  fi:
od:

RETURN([[op(fXnew)], [op(MixSuppList)], ["Continuous", "PDF"]]):
end:#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: mle7.map  (For number of arguments = 3 or 4)
#  CHANGE: if only 3 args, use Andy's formula from mle1.map, sometimes
#          likeloglihood function with CHF and HF has problems -- so
#          don't use this formula unless there is censoring!
#  
#  Procedure Name: MLE(X, Sample, Parameters, [Rightcensor]) 
#
#  Other APPL Procedures Called: CHF, HF
#
#  Date: June 27, 2000
#
#  Purpose: Returns the Maximum Likelihood Estimates (MLE) of a RV
#           given a sample data set drawn from the RV's distribution.
#           The optional argument, Rightcensor, allows for data values
#           to be right-censored.
#  
#  Arguments: X: Random Variable 
#             Sample: List of sample data points
#             Parameters: List of parameters to be estimated
#             Rightcensor (optional): Right-censoring vector of 1's and
#             0's, where 1 indicates an observed value and 0 indicates
#             a right-censored value
#
#  Algorithm: Rewrite ALGORITHM (6/27/2000)
#    1.  Check for the appropriate number of arguments: 3 or 4
#    4.  Make sure there are no piecewise RV's
#    3.  Check that the RV X is given in a list of 3 lists format

#    2.  If number of arguments is equal to 3, use *standard* (?) 
#        loglikelihood function

#     .  If number of arguments is equal to 4 (which indicated right-
#        censoring), use *censoring* (?) loglikelihood function
#    5.  Compute HF and CHF forms of X
#    6.  Split up the sample data into two lists, censored and
#        uncensored
#    7.  Compute and simplify the log likelihood function
#    8.  Differentiate the log likelihood function wrt each parameter 
#        and equate to 0
#    9.  Solve the system of log likehood equations from #8
#    10. Return the MLE's
#
MLE := proc(X :: list(list), Sample :: list, Parameters, 
    Rightcensor :: list(binary))
local nsegs, NumSubLists, n, npars, fX, LogLike, i, RcV, hX, chX,
    EqualTo1, NumUNCens, NumCens, j, k, UnCensored, Censored, UnC, C,
    Logh, Sumch, DiffLogLike, EqnSet, ParamSet, Solns, Estimate, 
    SolnList:
#
#  Check for the appropriate number of arguments: 3 or 4
#
if (nargs <> 3 and nargs <> 4) then
  print(`ERROR(MLE): This procedure requires either 3 or 4 arguments:`):
  print(`Random Variable, sample data set, parameters`):
  print(`to be estimated, right-censoring vector (optional)`):
  RETURN():
fi:
#
#  Make sure there are no piecewise RV's
#
nsegs := nops(X[1]):
if (nsegs > 1) then
  print(`ERROR(MLE): No piecewise RV's allowed`):
  RETURN():
fi:
#
#  Check that the RV X is given in a list of 3 lists format
#
NumSubLists := nops(X):
if (NumSubLists <> 3) then
  print(`ERROR(MLE): The RV X must be in a list of 3 lists format`):
  RETURN():
fi:
#
#  Check that X is in its PDF, CDF, SF, HF, CHF, or IDF format
#
if not((X[3][2] = "PDF") or
       (X[3][2] = "CDF") or
       (X[3][2] = "SF") or
       (X[3][2] = "HF") or
       (X[3][2] = "CHF") or
       (X[3][2] = "IDF")) then
  print(`ERROR(MLE): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  RETURN():
fi:
n := nops(Sample):
npars := nops(Parameters):
#
#  If only 3 arguments are given, all the data values are uncensored.
#  Use the *standard* (uncensored version) loglikelihood function
#
if (X[3][1] = "Continuous") then
   #print(`i'm here`):
  if (nargs = 3) then
    fX := PDF(X):
    LogLike := 0:
    for i from 1 to n do
      LogLike := ln(fX[1][1](Sample[i])) + LogLike:
    od:
    # print(LogLike):
  elif (nargs = 4) then
    #  print(`i'm here`):

    RcV := Rightcensor:
    hX := HF(X):
    # print(hX):
    chX := CHF(X):
    # print(chX):
#
#  Split up the sample data into two lists, censored and uncensored
#
    EqualTo1 := x -> is(x = 1):
    NumUNCens := nops(select(EqualTo1, RcV)):
    NumCens := n - NumUNCens:
    j := 1:
    k := 1:
    for i from 1 to n do
      if (is(RcV[i] = 1)) then
        UnCensored[j] := Sample[i]:
        j := j + 1:
      else
        Censored[k] := Sample[i]:
        k := k + 1:
      fi:
    od:
    UnC := [seq(UnCensored[i], i = 1 .. NumUNCens)]:
    C := [seq(Censored[i], i = 1 .. NumCens)]:
#
#  Compute and simplify the log likelihood function
#
    Logh := 0:
    Sumch := 0:
    for i from 1 to NumUNCens do
      Logh := (ln(hX[1][1](UnC[i])) + Logh):
    od:
    for i from 1 to n do
      Sumch := chX[1][1](Sample[i]) + Sumch:
    od:
    LogLike := simplify(Logh - Sumch):
  fi:
    #print(`LogLike is`, LogLike):
#
#  Differentiate the log likelihood function wrt each parameter and
#  equate to 0
#
  DiffLogLike := array(1 .. npars):
  for i from 1 to npars do
    DiffLogLike[i] := simplify(diff(LogLike, Parameters[i])):
    # print(DiffLogLike[i]):
  od:
  EqnSet := {seq(DiffLogLike[i] = 0, i = 1 .. npars)}:
   #print(EqnSet):
  ParamSet := {seq(Parameters[i], i = 1 .. npars)}:
   #print(ParamSet);
#
#  Solve the system of log likehood equations
#
  Solns := solve(EqnSet, ParamSet):
    #print(`The solns are`, Solns):
#  
# the following if series only applies to the Rayleigh dist
#
#  if (rhs(op(Solns[1])) > 0) then
#    Solns := Solns[1]:
#  elif (rhs(op(Solns[2])) > 0) then
#    Solns := Solns[2]:
#  else
#    Print(Solutionerror);
#  fi:
  #print(solnsisnow, Solns);
#
# end of Rayleigh
#
  Estimate := false:
  for i from 1 to npars do
# The command rhs causes a problem if there are two sets of solns; e.g.;
# {lambda = 1, kappa = 2}, {lambda = -1, kappa = 2}
   if type(rhs(Solns[i]), RootOf) then
     Estimate := true:
     Solns := fsolve(EqnSet, ParamSet):
     break:
   fi:
  od:
  if not(Estimate) then
    #print(`Solutions are`, Solns):
  else
    print(`Numerical method used to solve for parameter values`):
    print(`The approximate solutions are`, Solns):
  fi:
#
#  Return the MLEs as a list
#
  SolnList := []:
  for j from 1 to npars do
    SolnList := [op(SolnList), subs(op(Solns), Parameters[j])]:
  od:
  RETURN(SolnList):
else
  if nargs = 3 then
    return(MLEDiscrete(X, Sample, Parameters)):
  else
    return(MLEDiscrete(X, Sample, Parameters, Rightcensor)):
  fi:
fi:
end:



#11111111112222222222333333333344444444445555555555666666666677777777778888
#  Filename: mlediscrete1.map  (For number of arguments = 3 or 4)
#  Just writing for geometric and Purple Passion example first
#  Procedure Name: MLE(X, Sample, Parameters, [Censor]) 
#  need to write PDF for discrete distributions
#
#  Other APPL Procedures Called:
#
#  Date: July 1, 2000
#
#  Purpose: Returns the Maximum Likelihood Estimates (MLE) of a RV given a 
#
#  Algorithm:
#
MLEDiscrete := proc(X :: list(list), Sample :: list, Parameters, 
    Censor :: list(binary))
local n, EqualTo1, NumUNCens, NumCens, j, k, UnCensored, Censored, UnC, C,
fX, SX, Factor1, Factor2, LikeLi, LogLike, DiffLogLike, npars, EqnSet, ParamSet, i, Solns, NumSolns, SolnList:

if nargs = 4 then
#
#  Split up the sample data into two lists, censored and uncensored
#
n := nops(Sample):
EqualTo1 := x -> is(x = 1):
NumUNCens := nops(select(EqualTo1, Censor)):
NumCens := n - NumUNCens:
j := 1:
k := 1:
for i from 1 to n do
  if (is(Censor[i] = 1)) then
    UnCensored[j] := Sample[i]:
    j := j + 1:
  else
    Censored[k] := Sample[i]:
    k := k + 1:
  fi:
od:
UnC := [seq(UnCensored[i], i = 1 .. NumUNCens)]:
C := [seq(Censored[i], i = 1 .. NumCens)]:
# print(`The given sample is:`):
# print(Sample):
# print(`The uncensored data is:`):
# print(UnC):
# print(`The censored data is:`):
# print(C):
#
#  Compute and simplify the log likelihood function
#
fX := X:
SX := SF(X):
Factor1 := 1:
Factor2 := 1:
for i from 1 to NumUNCens do
  Factor1 := fX[1][1](UnC[i]) * Factor1:
od:
for i from 1 to NumCens do
  Factor2 := SX[1][1](C[i]) * Factor2:
od:
# print(`Factor 1 is`, Factor1):
# print(`Factor 2 is`, Factor2):
LikeLi := Factor1 * Factor2:
LogLike := ln(LikeLi):
# print(`LogLike is`, LogLike):
#
#  Differentiate the log likelihood function wrt each parameter and equate
#  to 0
#
npars := nops(Parameters):
DiffLogLike := array(1 .. npars):
for i from 1 to npars do
  DiffLogLike[i] := simplify(diff(LogLike, Parameters[i])):
od:
# print(`DiffLogLike is`, DiffLogLike):
EqnSet := {seq(DiffLogLike[i] = 0, i = 1 .. npars)}:
# print(`EqnSet is`, EqnSet):
ParamSet := {seq(Parameters[i], i = 1 .. npars)}:
# print(`ParamSet is`, ParamSet):
#
#  Solve the system of log likehood equations from above
#
Solns := solve(EqnSet, ParamSet):
# print(Solns):
#
#  Return the MLEs as a list
#
SolnList := []:
for j from 1 to npars do
  SolnList := [op(SolnList), subs(op(Solns), Parameters[j])]:
od:
fi:
RETURN(SolnList):
end:



#
#  Filename:  mlenhpp1.map
#
#  Procedure name: MLENHPP
#
#  Date:      July 1, 2000
#
#  Purpose:   Estimate the parameters for 
#             via maximum likelihood with arbitrary right censoring
#
#  Arguments: 1.  
#             2.  
#             4.  A list of the parameters to be estimated
#
#  Algorithm:
#
#  Warning:
#
MLENHPP := proc(X, Sample, Parameters, ObsTime)
local hX, n, c, Factor1, i, Factor2, LikeLi, LogLike, npars, DiffLogLike, EqnSet, ParamSet, Solns, SolnList, j, lambdahat, kappahat:

if X[3][1] = "Discrete" then
  print(`Error`):
fi:
hX := HF(X):
n := nops(Sample):
c := ObsTime:
Factor1 := 1:
for i from 1 to n do
  Factor1 := hX[1][1](Sample[i]) * Factor1:
od:
Factor2 := exp(-(int(hX[1][1](t), t = 0 .. c))):
# print(Factor2):
LikeLi := Factor1 * Factor2:
# print(LikeLi):
LogLike := ln(LikeLi):
# print(`LogLike is`):
# print(simplify(LogLike)):

npars := nops(Parameters):
DiffLogLike := array(1 .. npars):
for i from 1 to npars do
  # print(simplify(diff(LogLike, Parameters[i]))):
  DiffLogLike[i] := simplify(diff(LogLike, Parameters[i])):
od:
# print(`DiffLogLike is`, DiffLogLike):
EqnSet := {seq(DiffLogLike[i] = 0, i = 1 .. npars)}:
# print(`EqnSet is`, EqnSet):
ParamSet := {seq(Parameters[i], i = 1 .. npars)}:
# print(`ParamSet is`, ParamSet):

#
#  Solve the system of log likehood equations from above
#
Solns := solve(EqnSet, ParamSet):
# print(Solns):
# print(`Solns are`):
# print(Solns):
# print(whattype(Solns)):
# print(`hey`):

#
#  Return the MLEs as a list
#

#
#  Trying to prevent MLENHPP from returning the Solns as an 
#  uncalculated fsolve expression
#  
if hasfun(Solns, fsolve) then
  print(`helping MLENHPP solve for lambdahat and kappahat`):
  print(`for some data sets with a Weibull hazard function`):
  kappahat := n / (n * ln(c) - sum(ln(Sample[k]), k = 1 .. n)):
  print(kappahat):
  lambdahat := (n ^ (1 / kappahat)) / c:
  print(lambdahat):
  Solns := {lambda = lambdahat, kappa = kappahat}:
  print(Solns):
fi:
SolnList := []:
for j from 1 to npars do
  SolnList := [op(SolnList), subs(op(Solns), Parameters[j])]:
od:

RETURN(SolnList):
end:


#11111111112222222222333333333344444444445555555555666666666677777777778888
#  Filename:  mleweibull1.map
#
#  Procedure name: MLEWeibull(Sample, Rightcensor)
# 
#  Other APPL Procedures Called: None 
#
#  Date:      January 11, 2000
#
#  Purpose:   Estimate the parameters for a Weibull distribution  
#             via maximum likelihood with arbitrary right censoring
#
#  Arguments: Sample: The failure/right censoring times in list form;
#             Delta: An indicator list (1 observed, 0 right censored). 
#
#  Algorithm: From Braxton and Leemis (1998), "A fixed-point algorithm
#             for computing Weibull MLEs for a right-censored data set."
#
MLEWeibull := proc(Sample :: list, Rightcensor :: list)
local n, Delta, epsilon, c, r, i, s1, s2, s3, q, counter, chat, bhat,
    solnlist:
#
#  Check for the appropriate number of arguments: 1 or 2. If the number of
#  arguments is 1, assign the right censor list to contain all ones to
#  indicate the data values are uncensored
#
n := nops(Sample):
if (nargs = 2) then
  Delta := Rightcensor:
elif (nargs = 1) then
  Delta := [seq(1, i = 1 .. n)]:
else
  print(`ERROR(MLEWeibull): This procedure requires 1 or 2 arguments:`):
  print(`Sample data set and right-censoring vector (optional)`):
  RETURN():
fi:
#
#  Set tolerance and initial estimate
#
epsilon := 0.000000001:
c := 1:
#
#  Compute the number of observed failures
#
r := 0:
for i from 1 to n do
  r := r + Delta[i]:
od:
#
#  Calculate s1
#
s1 := 0:
for i from 1 to n do
  if (Delta[i] = 1) then 
    s1 := combine(s1 + log(Sample[i])):
  fi:
od:
#
#  Calculate s2 (beginning of random censoring adjustment)
#
s2 := 0:
for i from 1 to n do
  s2 := combine(s2 + Sample[i] ^ c):
od:
#
#  Calculate s3
#
s3 := 0:
for i from 1 to n do
  s3 := combine(s3 + Sample[i] ^ c * log(Sample[i])):
od:
#
#  Loop to assure that c is to the right of the vertical asymptote
#
while (evalf(r * s3 - s1 * s2) <= 0) do
  c := c * 1.1:
  s2 := 0:
  for i from 1 to n do
    s2 := combine(s2 + Sample[i] ^ c):
  od:
  s3 := 0:
  for i from 1 to n do
    s3 := combine(s3 + Sample[i] ^ c * log(Sample[i])):
  od:
od:  
#
#  Calculate s2 (beginning of first iteration of Repeat .. Until loop)
#
s2 := 0:
for i from 1 to n do
  s2 := combine(s2 + Sample[i] ^ c):
od:
#
#  Calculate s3
#
s3 := 0:
for i from 1 to n do
  s3 := combine(s3 + Sample[i] ^ c * log(Sample[i])):
od:
#
#  Calculate q and c 
#
q := r * s2 / (r * s3 - s1 * s2):
c := (c + q) / 2:
counter := 0:
while (evalf(abs(c - q)) > epsilon) and (counter < 100) do
  counter := counter + 1:
  s2 := 0:
  for i from 1 to n do
    s2 := evalf(s2 + Sample[i] ^ c):
  od:
  s3 := 0:
  for i from 1 to n do
    s3 := evalf(s3 + Sample[i] ^ c * log(Sample[i])):
  od:
  q := evalf(r * s2 / (r * s3 - s1 * s2)):
  # print(`q in the while loop is`, q):
  c := evalf((c + q) / 2):
  # print(`c in the while loop is`, c):
od:
#
#  Calculate the MLEs
#
chat := c:
s2 := 0:
for i from 1 to n do
  s2 := s2 + Sample[i] ^ c:
od:
bhat := (s2 / r) ^ (1 / c):
solnlist := [1 / bhat, chat]:
RETURN(solnlist):
end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: mom6.map--doesn't work for piecewise, like triangular
#  trying to fix this in mom8.map
#  
#  Procedure Name: MOM(X, Sample, Parameters) 
#
#  Other APPL Procedures Called: PDF, ExpectedValue
#
#  Date: August 20, 1999
#
#  Purpose: Returns the Method of Moments (MOM) Estimates for a complete
#           sample data set
#  
#  Arguments: X: Random variable,
#             Sample: List of sample data points, and
#             Parameters: List of parameters to be estimated
#
#  Algorithm: 
#    1.  Check for the appropriate number of arguments
#    2.  Check that the RV X is given in a list of 3 lists format
#    3.  Convert X to PDF form if not already in that form
#    4.  Check that parameters to be estimated are the same parameters
#        that have been assigned to the random variable X; that is, if 
#        X := GammaRV(a, b), then the parameters to be estimated must be
#        [a, b].  Return an error message if this is not the case. Also,
#        return an error message if a parameter variable name has been
#        used in the current Maple session without being unassigned
#        before defining the random variable X and running MOM
#    5.  Convert the values in the list Sample to rational numbers so
#        that Maple commands such as sum and solve will give exact
#        solutions instead of floating point approximations
#    6.  Compute and simplify the sample moments and distribution
#        moments
#    7.  Equate the distribution moments with their corresponding sample
#        moments
#    8.  Solve the system of equations; if Maple cannot determine the
#        exact solution(s) with "solve," then use Maple's numeric
#        solver, "fsolve"
#    9.  Return the MOMs as a list
#
MOM := proc(X :: list(list), Sample :: list, Parameters :: list(symbol))
local NumSubLists, fX, n, k, count, ParamCheck, RatSample, SampleMOM,
    DistMOM, j, EqnSet, ParamSet, Solns, NumSolns, Estimate, i, 
    SolnList:
description `Returns method of moment estimates`:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 3) then
  print(`ERROR(MOM): This procedure requires 3 arguments:`):
  print(`Random variable, data set, and`):
  print(`list of parameters to be estimated`):
  return:
fi:
#
#  Check that the RV X is given in a list of 3 lists format
#
NumSubLists := nops(X):
if (NumSubLists <> 3) then
  print(`ERROR(MOM): The RV X must be in a list of 3 lists format`):
  return:
fi:
#
#  Convert X to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
  fX := X:
elif ((X[3][2] = "CDF") or
      (X[3][2] = "CHF") or
      (X[3][2] = "HF") or
      (X[3][2] = "IDF") or
      (X[3][2] = "SF")) then
  fX := PDF(X):
else
  print(`ERROR(MOM): RV must be given as`):
  print(`CDF, CHF, HF, IDF, PDF, or SF`):
  return:
fi:
#
#  Check that parameters to be estimated are the same parameters that
#  have been assigned to the random variable X; that is, if 
#  X := GammaRV(a, b), then the parameters to be estimated must be 
#  [a, b].  Return an error message if this is not the case.  Also,
#  return an error message if a parameter variable name has been used in
#  the current Maple session without being unassigned before defining
#  the random variable X and running MOM
#
n := nops(Sample):
k := nops(Parameters):
# ParamCheck := op(X[1](x)):
# for count from 1 to k do
# if not(has(ParamCheck, Parameters[count])) then
# print(`ERROR(MOM): One of the two problems below has been 
# encountered:`):
# print(`(1) The parameters to be estimated are NOT the same as the`):
# print(`parameters assigned to the random variable X`):
# print(`If X := GammaRV(a, b), then the parameters to be estimated 
# MUST`):
# print(`be given as the list [a, b]`):
# print(``):
# print(`OR`):
# print(``):
# print(`(2) You are re-using a parameter variable name without first`):
# print(`unassigning it. Unassign parameter variable names before
# defining`):
# print(`your random variable X and then rerun MOM`):
# print(`Example: Unassign variable name lambda with: > unassign
# ('lambda');`):
# return:
# fi:
# od:
#
#  Convert the values in the list Sample to rational numbers so that
#  Maple commands such as sum and solve will give exact solutions
#  instead of floating point approximations
#
SampleMOM := array(1 .. k):
DistMOM := array(1 .. k):
RatSample := convert(Sample, rational):
#
#  Compute and simplify the sample moments and distribution moments
#
for j from 1 to k do
  SampleMOM[j] := simplify(sum(RatSample[i] ^ j, i = 1 .. n) / n):
  DistMOM[j] := ExpectedValue(fX, x -> x ^ j):
od:
#
#  Equate the distribution moments with their corresponding sample
#  moments
#
EqnSet := {seq(SampleMOM[j] = DistMOM[j], j = 1 .. k)}:
# print(EqnSet):
ParamSet := {seq(Parameters[j], j = 1 .. k)}:
# print(ParamSet):
#
#  Solve the system of equations from above; if Maple cannot determine
#  the exact solution(s), then use the numerical solver "fsolve"
#
Solns := solve(EqnSet, ParamSet):
# print(`Solns are`):
# print(Solns):
NumSolns := nops(Solns):
Estimate := false:
for i from 1 to NumSolns do
  if type(rhs(Solns[i]), RootOf) then
    Estimate := true:
    # Used for Ball Bearing Data Set
    # Solns := allvalues(Solns):
    Solns := fsolve(EqnSet, ParamSet, lambda = 0 .. 0.015):
    # Solns := fsolve(EqnSet, ParamSet):
    break:
  fi:
od:
if not(Estimate) then
  print(`Solutions are`, Solns):
else
  print(`A numerical method was used to solve for the values`):
  print(`of the parameters`):
  print(`The approximate solutions are`, Solns):
fi:
#
#  Return the MOMs as a list
#
SolnList := []:
for j from 1 to k do
  SolnList := [op(SolnList), subs(op(Solns), Parameters[j])]:
od:
return(SolnList):
end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename:  momerlang1.map
#
#  Procedure name: MOMErlang(Sample)
# 
#  Other APPL Procedures Called: ErlangRV,   
#
#  Date:      January 21, 2000
#
#  Purpose:   Estimate the parameters for a Erlang distribution via
#             method of moments estimation
#
#  Arguments: Sample: The data set in list form
#
#  Algorithm: 1. Check for 1 argument
#
MOMErlang := proc(Sample :: list)
local m, RatSample, i, fX, SampleMOM, DistMOM, EqnSet, ParamSet, Soln,
    Estimate, X, ksvalue:
#
#  Check for 1 argument
#
if (nargs <> 1) then
  print(`ERROR(MOMErlang): This procedure requires 1 argument:`):
  print(`The sample data in a list`):
  RETURN():
fi:
#
#  Define fX as the PDF of an Erlang RV
#
m :=nops(Sample):
RatSample := convert(Sample, rational):
# print(RatSample):

for i from 1 to 20 do
  unassign('lambda'):
  fX := ErlangRV(lambda, i): 
  # print(fX):

#
#  Compute and simplify the sample moments and distribution moments 
#  for the given integer value of the Erlang parameter n
#

  SampleMOM := simplify(sum(RatSample[j], j = 1 .. m) / m):
  #print(SampleMOM):
  DistMOM := ExpectedValue(fX, x -> x):
  #print(DistMOM):

#
#  Equate the distribution moments with their corresponding sample
#  moments
#

  EqnSet := {SampleMOM = DistMOM}:
  ParamSet := {lambda}:
  #print(EqnSet):

#
#  Solve the system of equations from above; if Maple cannot determine
#  the exact solution for the parameter lambda, then use the Maple 
#  numerical solver "fsolve"
#
 
  Soln := solve(EqnSet, ParamSet):
  Estimate := false:
  if type(rhs(op(Soln)), RootOf) then
    Estimate := true:
    Soln := fsolve(EqnSet, ParamSet):
    break:
  fi:
  print(`********************************************`):
  print(`the integer n is`, i):
  if not(Estimate) then
    print(`The exact value of the Erlang parameter lambda is`, Soln):
  else
    print(`A numerical method was used to solve for the Erlang`):
    print(`parameter lambda, which is approximately`, Soln):
  fi: 
  unassign('lambda'):
  unassign('n'):
  X := ErlangRV(lambda, n):
  ksvalue := KSTest(X, RatSample, [lambda = rhs(op(Soln)), n = i]):
od:
#
#  Return the parameter lambda as a list
#
# RETURN([op(Soln)]):
end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: movingheapconvolutionmethod1.map
#
#  Procedure Name: MovingHeapConvolutionMethod(X, Y)
#
#  Other APPL Procedures Called: 
#
#  Date: October 4, 2000
#
#  Purpose: 
#
#  Arguments: X, Y: Continuous random variables
#
#  Algorithm:
MovingHeapConvolutionMethod := proc() 
global H, Mimic, fX, fY:
local n, m, s, Probs, r, c, row1col2elt, row2col1elt, q, RootItem,
    RootPosition, a, b, size, NewPosition:

n := nops(fX[1]):
m := nops(fY[1]):
s := array(1 .. n * m, []):
Probs := array(1 .. n * m, []):
s[1] := fX[2][1] + fY[2][1]:
Probs[1] := fX[1][1] * fY[1][1]:
r := array(sparse, 1 .. n + 1, []):
c := array(sparse, 1 .. m + 1, []):
#
#  Place a 1 in row 1, column 2, row 2, and column 1 to indicate that
#  there is an "active" item in these rows and columns. Place a 1 in
#  row n + 1 and column m + 1 to indicate the end of the array in the
#  row and column directions
#
row1col2elt := [fX[2][1] + fY[2][2], fX[1][1] * fY[1][2]]:
r[1] := 1:
c[2] := 1:
row2col1elt := [fX[2][2] + fY[2][1], fX[1][2] * fY[1][1]]:
r[2] := 1:
c[1] := 1:
r[n + 1] := 1:
c[m + 1] := 1:
#
#  Create a left complete tree H for two elements and create a left
#  complete tree Mimic which contains the ordered positions (in the
#  fX and fY lists) of the elements placed in the heap H
#
H := array(1 .. 3, [-1 * 10 ^ 6, row1col2elt, row2col1elt]):
Mimic := array(1 .. 3, [-1 * 10 ^ 6, [1, 2], [2, 1]]):
#
#  Convert the trees H and Mimic into heaps
#
PercolateDownHeap(2, 3):
#
#  Remove the root from the heap and place it in the sum array s, 
#  unmark the row and column that had its element removed, rebuild the
#  heap with the remaining elements, insert allowable elements in the
#  heap, place a 1 in the row and column arrays indicating the added
#  element's position, repeat the process ...
#
for q from 2 to n * m do
#
#  Remove the minimum element (in the root) from the heap and place it
#  in the sum array s.  Mark the position of the removed element in the
#  array A as [row a, column b].
#
  RootItem := H[2]:
  RootPosition := Mimic[2]:
  s[q] := RootItem[1]:
  Probs[q] := RootItem[2]:
  a := RootPosition[1]:
  b := RootPosition[2]:
#
#  Place a 0 in the column and row from which the minimum element was
#  removed
#
  r[a] := 0:
  c[b] := 0:
#
#  Replace the root of the heap with the last element in the heap, 
#  decrease the size of the heap by one (eliminating the position of
#  the last element which was moved into the root), and rebuild the
#  heap from top down
#
  size := nops(convert(H, list)):
  H[2] := H[size]:
  Mimic[2] := Mimic[size]:
  H := array(1 .. size - 1, [seq(H[i], i = 1 .. size - 1)]):
  Mimic := array(1 .. size - 1, [seq(Mimic[i], i = 1 .. size - 1)]):
  RebuildHeap(2, size - 1):
#
#  The element in array position [row a, column b] was removed from
#  the heap. If row a and column b + 1 do not contain an active 
#  element, then insert a new sum value into array position 
#  [row a, column b + 1].  Place a 1 in row a and column b + 1 to
#  indicate that there is an "active" item in this row and column
#
  if r[a] = 0 and c[b + 1] = 0 then
    r[a] := 1:
    c[b + 1] := 1:
    NewPosition := [a, b + 1]:
    InsertHeapConvolution(NewPosition):
  fi:
#
#  The element in array position [row a, column b] was removed from
#  the heap. If row a + 1 and column b do not contain an active 
#  element, then insert a new sum value into array position 
#  [row a + 1, column b].  Place a 1 in row a + 1 and column b to
#  indicate that there is an "active" item in this row and column
#
  if r[a + 1] = 0 and c[b] = 0 then
    r[a + 1] := 1:
    c[b] := 1:
    NewPosition := [a + 1, b]:
    InsertHeapConvolution(NewPosition):
  fi:
od:
return(s, Probs):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: movingheapproductmethod1.map
#
#  Procedure Name: MovingHeapProductMethod(X, Y)
#
#  Other APPL Procedures Called: 
#
#  Date: October 4, 2000
#
#  Purpose: 
#
#  Arguments: X, Y: Continuous random variables
#
#  Algorithm:
MovingHeapProductMethod := proc() 
global H, Mimic, fX, fY:
local n, m, prods, Probs, r, c, row1col2elt, row2col1elt, q, RootItem,
    RootPosition, a, b, size, NewPosition:

n := nops(fX[1]):
m := nops(fY[1]):
prods := array(1 .. n * m, []):
Probs := array(1 .. n * m, []):
prods[1] := fX[2][1] * fY[2][1]:
Probs[1] := fX[1][1] * fY[1][1]:
r := array(sparse, 1 .. n + 1, []):
c := array(sparse, 1 .. m + 1, []):
#
#  Place a 1 in row 1, column 2, row 2, and column 1 to indicate that
#  there is an "active" item in these rows and columns. Place a 1 in
#  row n + 1 and column m + 1 to indicate the end of the array in the
#  row and column directions
#
# if (n > 1) then
row1col2elt := [fX[2][2] * fY[2][1], fX[1][2] * fY[1][1]]:
r[1] := 1:
c[2] := 1:
# fi:
# if (m > 1) then
row2col1elt := [fX[2][1] * fY[2][2], fX[1][1] * fY[1][2]]:
r[2] := 1:
c[1] := 1:
# fi:
r[n + 1] := 1:
c[m + 1] := 1:
#
#  Create a left complete tree H for two elements and create a left
#  complete tree Mimic which contains the ordered positions (in the
#  fX and fY lists) of the elements placed in the heap H
#
H := array(1 .. 3, [-1 * 10 ^ 6, row1col2elt, row2col1elt]):
Mimic := array(1 .. 3, [-1 * 10 ^ 6, [2, 1], [1, 2]]):
#
#  Convert the trees H and Mimic into heaps
#
PercolateDownHeap(2, 3):
#
#  Remove the root from the heap and place it in the sum array prods, 
#  unmark the row and column that had its element removed, rebuild the
#  heap with the remaining elements, insert allowable elements in the
#  heap, place a 1 in the row and column arrays indicating the added
#  element's position, repeat the process ...
#
for q from 2 to n * m do
#
#  Remove the minimum element (in the root) from the heap and place it
#  in the sum array prods.  Mark the position of the removed element in
#  the
#  array A as [row a, column b].
#
  RootItem := H[2]:
  RootPosition := Mimic[2]:
  prods[q] := RootItem[1]:
  Probs[q] := RootItem[2]:
  a := RootPosition[1]:
  b := RootPosition[2]:
#
#  Place a 0 in the column and row from which the minimum element was
#  removed
#
  r[a] := 0:
  c[b] := 0:
#
#  Replace the root of the heap with the last element in the heap, 
#  decrease the size of the heap by one (eliminating the position of
#  the last element which was moved into the root), and rebuild the
#  heap from top down
#
  size := nops(convert(H, list)):
  H[2] := H[size]:
  Mimic[2] := Mimic[size]:
  H := array(1 .. size - 1, [seq(H[i], i = 1 .. size - 1)]):
  Mimic := array(1 .. size - 1, [seq(Mimic[i], i = 1 .. size - 1)]):
  RebuildHeap(2, size - 1):
#
#  The element in array position [row a, column b] was removed from
#  the heap. If row a and column b + 1 do not contain an active 
#  element, then insert a new sum value into array position 
#  [row a, column b + 1].  Place a 1 in row a and column b + 1 to
#  indicate that there is an "active" item in this row and column
#
  if r[a] = 0 and c[b + 1] = 0 then
    r[a] := 1:
    c[b + 1] := 1:
    NewPosition := [a, b + 1]:
    InsertHeapProduct(NewPosition):
  fi:
#
#  The element in array position [row a, column b] was removed from
#  the heap. If row a + 1 and column b do not contain an active 
#  element, then insert a new sum value into array position 
#  [row a + 1, column b].  Place a 1 in row a + 1 and column b to
#  indicate that there is an "active" item in this row and column
#
  if r[a + 1] = 0 and c[b] = 0 then
    r[a + 1] := 1:
    c[b] := 1:
    NewPosition := [a + 1, b]:
    InsertHeapProduct(NewPosition):
  fi:
od:
return(prods, Probs):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: movingheapproductq1q31.map
#
#  Procedure Name: MovingHeapProductQ1Q3(X, Y)
#
#  Other APPL Procedures Called: 
#
#  Date: January 10, 2001
#
#  Purpose: 
#
#  Arguments: X, Y: Discrete random variables
#
#  Algorithm:
MovingHeapProductQ1Q3 := proc() 
global H, Mimic, fXNeg, fXPos, fYNeg, fYPos, Q1H, Q1Mimic, Q3H, 
    Q3Mimic:
local xneg, xpos, yneg, ypos, Q1Q3Prod, Q1Q3Prob, Q1row1col1,
    Q3row1col1, Q1r, Q1c, Q3r, Q3c, Q1row1col2, Q1row2col1, Q3row1col2,
    Q3row2col1, i,a, b, size, NewPosition:

xneg := nops(fXNeg[1]):
xpos := nops(fXPos[1]):
yneg := nops(fYNeg[1]):
ypos := nops(fYPos[1]):
Q1Q3Prod := array(1 .. xpos * ypos + xneg * yneg):
Q1Q3Prob := array(1 .. xpos * ypos + xneg * yneg):
Q1row1col1 := [fXPos[2][1] * fYPos[2][1], fXPos[1][1] * fYPos[1][1]]:
Q3row1col1 := [fXNeg[2][1] * fYNeg[2][1], fXNeg[1][1] * fYNeg[1][1]]:
Q1r := array(sparse, 1 .. xpos + 1, []):
Q1c := array(sparse, 1 .. ypos + 1, []):
Q3r := array(sparse, 1 .. xneg + 1, []):
Q3c := array(sparse, 1 .. yneg + 1, []):
Q1r[xpos + 1] := 1:
Q1c[ypos + 1] := 1:
Q3r[xneg + 1] := 1:
Q3c[yneg + 1] := 1:
if Q1row1col1[1] <= Q3row1col1[1] then
  Q1Q3Prod[1] := Q1row1col1[1]:
  Q1Q3Prob[1] := Q1row1col1[2]:
  Q1row1col2 := [fXPos[2][2] * fYPos[2][1], fXPos[1][2] * fYPos[1][1]]:
  Q1r[1] := 1:
  Q1c[2] := 1:
  Q1row2col1 := [fXPos[2][1] * fYPos[2][2], fXPos[1][1] * fYPos[1][2]]:
  Q1r[2] := 1:
  Q1c[1] := 1:
  Q1H := array(1 .. 3, [-1 * 10 ^ 6, Q1row1col2, Q1row2col1]):
  Q1Mimic := array(1 .. 3, [-1 * 10 ^ 6, [2, 1], [1, 2]]):
  Q3r[1] := 1:
  Q3c[1] := 1:
  PercolateDownHeapQ1(2, 3):
  Q3H := array(1 .. 2, [-1 * 10 ^ 6, Q3row1col1]):
  Q3Mimic := array(1 .. 2, [-1 * 10 ^ 6, [1, 1]]):
else
  Q1Q3Prod[1] := Q3row1col1[1]:
  Q1Q3Prob[1] := Q3row1col1[2]:
  Q3row1col2 := [fXNeg[2][2] * fYNeg[2][1], fXNeg[1][2] * fYNeg[1][1]]:
  Q3r[1] := 1:
  Q3c[2] := 1:
  Q3row2col1 := [fXNeg[2][1] * fYNeg[2][2], fXNeg[1][1] * fYNeg[1][2]]:
  Q3r[2] := 1:
  Q3c[1] := 1:
  Q3H := array(1 .. 3, [-1 * 10 ^ 6, Q3row1col2, Q3row2col1]):
  Q3Mimic := array(1 .. 3, [-1 * 10 ^ 6, [2, 1], [1, 2]]):
  Q1r[1] := 1:
  Q1c[1] := 1:
  PercolateDownHeapQ3(2, 3):
  Q1H := array(1 .. 2, [-1 * 10 ^ 6, Q1row1col1]):
  Q1Mimic := array(1 .. 2, [-1 * 10 ^ 6, [1, 1]]):
fi:
# print(`Q1r, Q1c are`, Q1r, Q1c):
# print(`Q3r, Q3c are`, Q3r, Q3c):
# print(`Q1H is`, Q1H):
# print(`Q3H is`, Q3H):
# print(`Q1Q3 is`, Q1Q3Prod):
for i from 2 to (xpos * ypos + xneg * yneg) do
  if Q1H[2][1] <= Q3H[2][1] then
    Q1Q3Prod[i] := Q1H[2][1]:
    Q1Q3Prob[i] := Q1H[2][2]:
    a := Q1Mimic[2][1]:
    b := Q1Mimic[2][2]:
    Q1r[a] := 0:
    Q1c[b] := 0:
    size := nops(convert(Q1H, list)):
    Q1H[2] := Q1H[size]:
    Q1Mimic[2] := Q1Mimic[size]:
    Q1H := array(1 .. size - 1, [seq(Q1H[i], i = 1 .. size - 1)]):
    Q1Mimic := array(1 .. size - 1, 
        [seq(Q1Mimic[i], i = 1 .. size - 1)]):
    RebuildHeapQ1(2, size - 1):
    if Q1r[a] = 0 and Q1c[b + 1] = 0 then
      Q1r[a] := 1:
      Q1c[b + 1] := 1:
      NewPosition := [a, b + 1]:
      InsertHeapProductQ1(NewPosition):
    fi:
    if Q1r[a + 1] = 0 and Q1c[b] = 0 then
      Q1r[a + 1] := 1:
      Q1c[b] := 1:
      NewPosition := [a + 1, b]:
      InsertHeapProductQ1(NewPosition):
    fi:
    Q1H := convert(Q1H, list): 
    # print(`Q1H is`, Q1H):
    # print(`Q1r is`, Q1r):
    # print(`Q1c is`, Q1c):
    if nops(Q1H) = 1 then
      Q1H := array(1 .. 2, [Q1H[1], [1 * 10 ^ 10, 0]]):
    fi:
  else
    Q1Q3Prod[i] := Q3H[2][1]:
    Q1Q3Prob[i] := Q3H[2][2]:
    a := Q3Mimic[2][1]:
    b := Q3Mimic[2][2]:
    Q3r[a] := 0:
    Q3c[b] := 0:
    size := nops(convert(Q3H, list)):
    Q3H[2] := Q3H[size]:
    Q3Mimic[2] := Q3Mimic[size]:
    Q3H := array(1 .. size - 1, [seq(Q3H[i], i = 1 .. size - 1)]):
    Q3Mimic := array(1 .. size - 1, 
        [seq(Q3Mimic[i], i = 1 .. size - 1)]):
    RebuildHeapQ3(2, size - 1):
    if Q3r[a] = 0 and Q3c[b + 1] = 0 then
      Q3r[a] := 1:
      Q3c[b + 1] := 1:
      NewPosition := [a, b + 1]:
      # print(`Q3H is`, Q3H):
      InsertHeapProductQ3(NewPosition):
      # print(`Q3H is`, Q3H):
    fi:
    if Q3r[a + 1] = 0 and Q3c[b] = 0 then
      Q3r[a + 1] := 1:
      Q3c[b] := 1:
      NewPosition := [a + 1, b]:
      # print(`Q3H is`, Q3H):
      InsertHeapProductQ3(NewPosition):
      # print(`Q3H is`, Q3H):
    fi:
    # print(`Q3H is`, Q3H):
    # print(`Q1r, Q1c are`, Q1r, Q1c):
    # print(`Q3r, Q3c are`, Q3r, Q3c):
    Q3H := convert(Q3H, list):
    if nops(Q3H) = 1 then
      Q3H := array(1 .. 2, [Q3H[1], [1 * 10 ^ 10, 0]]):
    fi:
  fi:
  # print(`Q1Q3 is`, Q1Q3Prod):
od:
return(Q1Q3Prod, Q1Q3Prob):
end:


#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: movingheapproductq2q41.map
#
#  Procedure Name: MovingHeapProductQ2Q4(X, Y)
#
#  Other APPL Procedures Called: 
#
#  Date: January 10, 2001
#
#  Purpose: 
#
#  Arguments: X, Y: Discrete random variables
#
#  Algorithm:
MovingHeapProductQ2Q4 := proc() 
global H, Mimic, fXNeg, fXPos, fYNeg, fYPos, Q2H, Q2Mimic, Q4H, 
    Q4Mimic:
local xneg, xpos, yneg, ypos, Q2Q4Prod, Q2Q4Prob, Q2row1col1,
    Q4row1col1, Q2r, Q2c, Q4r, Q4c, Q2row1col2, Q2row2col1, Q4row1col2,
    Q4row2col1, i, a, b, size, NewPosition:

xneg := nops(fXNeg[1]):
xpos := nops(fXPos[1]):
yneg := nops(fYNeg[1]):
ypos := nops(fYPos[1]):
Q2Q4Prod := array(1 .. xneg * ypos + xpos * yneg):
Q2Q4Prob := array(1 .. xneg * ypos + xpos * yneg):
Q2row1col1 := [fXNeg[2][1] * fYPos[2][1], fXNeg[1][1] * fYPos[1][1]]:
Q4row1col1 := [fXPos[2][1] * fYNeg[2][1], fXPos[1][1] * fYNeg[1][1]]:
Q2r := array(sparse, 1 .. xneg + 1, []):
Q2c := array(sparse, 1 .. ypos + 1, []):
Q4r := array(sparse, 1 .. xpos + 1, []):
Q4c := array(sparse, 1 .. yneg + 1, []):
#
#  Place a 1 in the last row and column of Q2 and Q4 to indicate the
#  end of the arrays in the row and column directions.
#
Q2r[xneg + 1] := 1:
Q2c[ypos + 1] := 1:
Q4r[xpos + 1] := 1:
Q4c[yneg + 1] := 1:
#
#  Since ProductDiscrete is caling movingheapproductq2q4, then Q2 is at
#  least a 2 x 2 array AND Q4 is at least a 2 x 2 array
#
#  If the element in the (1, 1) cell of Q2 is smaller than the element 
#  in the (1, 1) cell of Q4, then place Q2row1col1 as the first item in
#  the Q2Q4Prod array. 
#
if Q2row1col1[1] <= Q4row1col1[1] then
  Q2Q4Prod[1] := Q2row1col1[1]:
  Q2Q4Prob[1] := Q2row1col1[2]:
#
#  Incorporate the elements in cells (1, 2) and (2, 1) of Q2 as
#  active elements. Place a 1 in row 1, column 2, row 2, and column 1
#  to indicate this.
#
  Q2row1col2 := [fXNeg[2][2] * fYPos[2][1], fXNeg[1][2] * fYPos[1][1]]:
  Q2r[1] := 1:
  Q2c[2] := 1:
  Q2row2col1 := [fXNeg[2][1] * fYPos[2][2], fXNeg[1][1] * fYPos[1][2]]:
  Q2r[2] := 1:
  Q2c[1] := 1:
  Q2H := array(1 .. 3, [-1 * 10 ^ 6, Q2row1col2, Q2row2col1]):
  Q2Mimic := array(1 .. 3, [-1 * 10 ^ 6, [2, 1], [1, 2]]):
#
# Indicate that Q4 still has an active element in cell (1, 1).
#
  Q4r[1] := 1:
  Q4c[1] := 1:
#
# Convert the trees Q2H and Q2Mimic into heaps
#
  PercolateDownHeapQ2(2, 3):
#
# Q4H and Q4Mimic are already heaps; PercoleteDownHeapQ4 is not needed
#
  Q4H := array(1 .. 2, [-1 * 10 ^ 6, Q4row1col1]):
  Q4Mimic := array(1 .. 2, [-1 * 10 ^ 6, [1, 1]]):
else
  Q2Q4Prod[1] := Q4row1col1[1]:
  Q2Q4Prob[1] := Q4row1col1[2]:
#
#  Incorporate the elements in cells (1, 2) and (2, 1) of Q4 as
#  active elements. Place a 1 in row 1, column 2, row 2, and column 1
#  to indicate this.
#
  Q4row1col2 := [fXPos[2][2] * fYNeg[2][1], fXPos[1][2] * fYNeg[1][1]]:
  Q4r[1] := 1:
  Q4c[2] := 1:
  Q4row2col1 := [fXPos[2][1] * fYNeg[2][2], fXPos[1][1] * fYNeg[1][2]]:
  Q4r[2] := 1:
  Q4c[1] := 1:
  Q4H := array(1 .. 3, [-1 * 10 ^ 6, Q4row1col2, Q4row2col1]):
  Q4Mimic := array(1 .. 3, [-1 * 10 ^ 6, [2, 1], [1, 2]]):
#
# Indicate that Q2 still has an active element in cell (1, 1)
#
  Q2r[1] := 1:
  Q2c[1] := 1:
#
# Convert the trees Q4H and Q4Mimic into heaps
#
  PercolateDownHeapQ4(2, 3):
#
# Q2H and Q2Mimic are already heaps; PercolateDownHeapQ4 is not needed
#
  Q2H := array(1 .. 2, [-1 * 10 ^ 6, Q2row1col1]):
  Q2Mimic := array(1 .. 2, [-1 * 10 ^ 6, [1, 1]]):
fi:
#
#  Continue to extract roots from each heap, determine the minimum of
#  the roots, and rebuild the heaps.
#
for i from 2 to (xneg * ypos + xpos * yneg) do
#
#  Determine the minimum of the roots of heaps Q2H and Q4H.
#
  if Q2H[2][1] <= Q4H[2][1] then
    Q2Q4Prod[i] := Q2H[2][1]:
    Q2Q4Prob[i] := Q2H[2][2]:
    a := Q2Mimic[2][1]:
    b := Q2Mimic[2][2]:
#
#  Unmark the row and column of Q2 that had its element removed
#
    Q2r[a] := 0:
    Q2c[b] := 0:
#
#  Replace the root of heap Q2H with the last element in the heap, 
#  decrease the size of the heap by one (eliminating the position of
#  the last element which was moved into the root), and rebuild the
#  heap from top down
#
    size := nops(convert(Q2H, list)):
    Q2H[2] := Q2H[size]:
    Q2Mimic[2] := Q2Mimic[size]:
    Q2H := array(1 .. size - 1, [seq(Q2H[i], i = 1 .. size - 1)]):
    Q2Mimic := array(1 .. size - 1, 
        [seq(Q2Mimic[i], i = 1 .. size - 1)]):
    RebuildHeapQ2(2, size - 1):
#
#  The element in array position [row a, column b] was removed from
#  the heap Q2H. If row a and column b + 1 do not contain an active 
#  element, then insert a new sum value into array position 
#  [row a, column b + 1].  Place a 1 in row a and column b + 1 to
#  indicate that there is an "active" item in this row and column
#
    if Q2r[a] = 0 and Q2c[b + 1] = 0 then
      Q2r[a] := 1:
      Q2c[b + 1] := 1:
      NewPosition := [a, b + 1]:
      InsertHeapProductQ2(NewPosition):
    fi:
#
#  The element in array position [row a, column b] was removed from
#  the heap Q2H. If row a + 1 and column b do not contain an active 
#  element, then insert a new sum value into array position 
#  [row a + 1, column b].  Place a 1 in row a + 1 and column b to
#  indicate that there is an "active" item in this row and column
#
    if Q2r[a + 1] = 0 and Q2c[b] = 0 then
      Q2r[a + 1] := 1:
      Q2c[b] := 1:
      NewPosition := [a + 1, b]:
      InsertHeapProductQ2(NewPosition):
    fi:
    Q2H := convert(Q2H, list): 
#
#  If Q2 is empty, add a positive element in its second position so
#  loop will pick up the rest of the elements from Q4
#
    if nops(Q2H) = 1 then
      Q2H := array(1 .. 2, [Q2H[1], [1, 0]]):
    fi:
  else
    Q2Q4Prod[i] := Q4H[2][1]:
    Q2Q4Prob[i] := Q4H[2][2]:
    a := Q4Mimic[2][1]:
    b := Q4Mimic[2][2]:
#
#  Unmark the row and column of Q4 that had its element removed
#
    Q4r[a] := 0:
    Q4c[b] := 0:
#
#  Replace the root of heap Q4H with the last element in the heap, 
#  decrease the size of the heap by one (eliminating the position of
#  the last element which was moved into the root), and rebuild the
#  heap from top down
#
    size := nops(convert(Q4H, list)):
    Q4H[2] := Q4H[size]:
    Q4Mimic[2] := Q4Mimic[size]:
    Q4H := array(1 .. size - 1, [seq(Q4H[i], i = 1 .. size - 1)]):
    Q4Mimic := array(1 .. size - 1, 
        [seq(Q4Mimic[i], i = 1 .. size - 1)]):
    if (size > 2) then
      RebuildHeapQ4(2, size - 1):
    fi:
#
#  The element in array position [row a, column b] was removed from
#  the heap Q4H. If row a and column b + 1 do not contain an active 
#  element, then insert a new sum value into array position 
#  [row a, column b + 1].  Place a 1 in row a and column b + 1 to
#  indicate that there is an "active" item in this row and column
#
    if Q4r[a] = 0 and Q4c[b + 1] = 0 then
      Q4r[a] := 1:
      Q4c[b + 1] := 1:
      NewPosition := [a, b + 1]:
      InsertHeapProductQ4(NewPosition):
    fi:
#
#  The element in array position [row a, column b] was removed from
#  the heap Q4H. If row a + 1 and column b do not contain an active 
#  element, then insert a new sum value into array position 
#  [row a + 1, column b].  Place a 1 in row a + 1 and column b to
#  indicate that there is an "active" item in this row and column
#
    if Q4r[a + 1] = 0 and Q4c[b] = 0 then
      Q4r[a + 1] := 1:
      Q4c[b] := 1:
      NewPosition := [a + 1, b]:
      InsertHeapProductQ4(NewPosition):
    fi:
    Q4H := convert(Q4H, list):
#
#  If Q4 is empty, add a positive element in its second position so
#  loop will pick up the rest of the elements from Q2
#
    if nops(Q4H) = 1 then
      Q4H := array(1 .. 2, [Q4H[1], [1, 0]]):
    fi:
  fi:
od:
return(Q2Q4Prod, Q2Q4Prob):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: nextcombo2.map
#
#  Procedure Name: NextCombination(Previous, N)
#
#  Other APPL Procedures Called: None
#
#  Date: May 11, 2000
#
#  Purpose: The code generates the next lexicographical ("alphabetical
#           order") combination of size n (the size of the previous
#           combination) of the integers {1, 2, ..., N}. It was created
#           for use in the OrderStat code.
#
#  Arguments: Previous: A set of integers (written in a Maple list)
#             which is the previous combination. WLOG the code assumes
#             that the underlying set is {1, 2, ..., N}.
#             N: The size of the underlying set of integers from which 
#             the combination is to be formed.
#
#  Algorithm: 
#    1. Error check for the correct number of arguments
#    2. If the final position in the combination is not the maximum
#       value it can attain, N, then increment it by 1. For example, if
#       the previous combination is [1, 2, 4, 6] and N = 10, then
#       increment the final position by 1 and return the next
#       combination as [1, 2, 4, 7].
#    3. If the final position in the combination list is already at its
#       maximum value, N, then move left through the combination and
#       find the next possible value that can be incremented. In other
#       words, scan the previous combination from right to left to 
#       locate the rightmost element that has not yet attained its
#       maximum value. If n is the size of the combination, then index 
#       position i's maximum attainable value is N + i - n. For 
#       example, if the previous combination is [1, 4, 9, 10] and 
#       N = 10, then increment position 2 by 1: [1, 5, 9, 10]. 
#    4. Upon incrementing the rightmost element in position i, reset
#       each value in the jth position (j = 1, 2, ... , n - i) to the
#       right of the ith position to 1 more than the value in the
#       preceding position. In the example above from step 3, the 
#       values in positions 3 and 4 need to be reset. The next
#       combination is [1, 5, 6, 7].
#    5. Return the next combination.
#
NextCombination := proc(Previous :: list, N :: posint)
local Next, n, MoveLeft, i, j:

if (nargs <> 2) then
  print(`ERROR(NextCombination): This procedure requires 2 arguments`):
  RETURN():
fi:
Next := Previous:
n := nops(Previous):
#
#  If the value in the final position of the combination is not the
#  maximum value it can attain, N, then increment it by 1.
#
if (Next[n] <> N) then
  Next[n] := Next[n] + 1:
#
#  If the final position in the combination is already at its maximum
#  value, N, then move left through the combination and find the next
#  possible value that can be incremented. Index position i's maximum
#  attainable value is N + i - n. 
#
else
  MoveLeft := true:
  for i from (n - 1) by -1 to 1 while (MoveLeft = true) do
    if (Next[i] < N + i - n) then
      Next[i] := Next[i] + 1:
#
#  Upon incrementing the rightmost element in position i, reset each 
#  value in the jth position (j = 1, 2, ... , n - i) to the right of
#  the ith position to 1 more than the value in the preceding position. 
#
      for j from 1 to (n - i) do
        Next[i + j] := Next[(i + j) - 1] + 1:
      od:
    MoveLeft := false:
    fi:
  od:
fi:
RETURN(Next):

end:
    
 
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: nextperm3.map
#
#  Procedure Name: NextPermutation(Previous)
#
#  Other APPL Procedures Called: None
#
#  Date: May 12, 2000
#
#  Purpose: The code generates the next lexicographical ("alphabetical
#           order") permutation. WLOG the code assumes the elements of
#           the set to be permuted are {1, 2, ..., k}. This code was
#           created for use in the OrderStat code.
#
#  Arguments: Previous: A set of integers (written in a Maple list)
#             which is the previous permutation. 
#
#  Algorithm: 
#    1. Error check for the correct number of arguments.
#    2. Find the largest index value i for which Next[i] < Next[i + 1].
#    3. Find the smallest value Next[j] for which Next[i] < Next[j] and
#       i < j.
#    4. Interchange the values Next[i] and Next[j].
#    5. Reverse the order of the values to the right of the leftmost
#       swapped value, which is now Next[j].
#    6. Return the next permutation.
#  
#    Example: Let A := [1, 4, 3, 2]. Find NextPermutation(A).
#    1. Error check ok: 1 argument.
#    2. Assign Next := [1, 4, 3, 2]. The largest index value i in which
#       Next[i] < Next[i + 1] is i = 1.
#    3. The smallest value Next[j] s.t. Next[i] < Next[j] is 2 = 
#       Next[4].
#    4. Swap the values in position i = 1 and j = 4. Next becomes
#       [2, 4, 3, 1].
#    5. Reverse the order of the values to the right of 2. Next becomes
#       [2, 1, 3, 4].
#    6. Return [2, 1, 3, 4] as the next permutation.
# 
NextPermutation := proc(Previous :: list)
local Next, n, flag, i, OrigVal, SwapIndex, j, Temp1, k, Temp2, m:

if (nargs <> 1) then
  print(`ERROR(NextPermutation): This procedure requires 1 argument`):
  RETURN():
fi:
Next := Previous:
n := nops(Previous):
flag := false:
#
#  Find the largest index value i for which Next[i] < Next[i + 1]
#
for i from n - 1 to 1 by -1 while not(flag) do
  if (Next[i] < Next[i + 1]) then
    flag := true:
    OrigVal := Next[i]:
    SwapIndex := i + 1:
#
#  Find the smallest value Next[j] for which Next[i] < Next[j] and i < j
#
    for j from n to SwapIndex by -1 do
      if ((Next[j] < Next[SwapIndex]) and (Next[j] > OrigVal)) then
        SwapIndex := j:
      fi:
    od:
    Temp1 := Next[SwapIndex]:
    Next[SwapIndex] := Next[i]:
    Next[i] := Temp1:
#
#  Reverse the order of the values to the right of the leftmost swapped
#  value
#
    for k from i + 1 to n do
      Temp2[k] := Next[k]:
    od:
    for m from i + 1 to n do
      Next[m] := Temp2[n + i + 1 - m]:
    od:
  fi:
od:
RETURN(Next): 
end:

#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: normalvariate1.map
#  
#  Procedure Name: NormalVariate(mu, sigma)
#
#  Other APPL Procedures Called: None
#
#  Date: June 1, 1999
#
#  Purpose: 
#
#  Arguments:
#
#  Algorithm:
#
NormalVariate := proc(mu, sigma)
local variate, rnd:

rnd := x -> rand() / 1000000000000:
variate := (-2 * ln(rnd())) ^ (1 / 2) * cos(2 * Pi * rnd()):
variate := variate * sigma + mu:
RETURN(evalf(variate)):

end:

#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: orderstat30.map  moved SX because now using it both in 
#  w\ and w\out replacement cases
#  adding infinite, without replacement -- couple cases
#  moved CDF to after PDF with SF -- nope, might need to move in future
#
#  9/5 -- ConvertToNumeric ... switch this in the future to 
#  ConvertToNoDot
#
#
#  OrderStat Procedure:
#  I.  X is a continuous random variable
#  II. X is a discrete random variable
#      A. Items are sampled with replacement
#         i.  X has numeric PDF
#         ii. X has symbolic PDF
#      B. Items are sampled without replacement
#         i.  X has finite support
#             a. PDF of X has equally likely probabilities
#             b. PDF of X has non-equally likely probabilities
#         ii. X has infinite support
#
#  Procedure Name: OrderStat(X, n, r, ["wo"])
#
#  Other APPL Procedures Called: PDF, CDF, Convert, SF,
#                                ConvertToNumeric
#
#  Date: May 17, 2000
#
#  Purpose: OrderStat is a procedure that returns the PDF of the rth 
#           order statistic of a random variable when ordering n
#           observations from the population with PDF fX(x)
#
#  Arguments: X: A random variable,
#             n: The number of items drawn randomly from the population
#                with PDF fX(x), 
#             r: The index of the desired order statistic,
#             "wo" (optional): A variable that indicates if the items 
#                drawn from the population are done so without (wo)
#                replacement (for discrete distributions only)
#
#  Algorithm:
#    1. Check for the appropriate number of arguments
#    2. Check that the order statistic index, r, is not greater than
#       the number of random items drawn from the population, n
#    3. Check that the RV X is a list of 3 sublists
#    4. Convert X to PDF form if not already in that form
#    5. If the RV X is continuous, find the PDF of the rth order
#       statistic. The RV X must have a tractable CDF for this to be
#       possible.
#    6. If the RV X is discrete, then call the procedure Convert(X) to
#       convert the discrete random variable's support to a standard
#       APPL discrete random variable support format: 
#           standard "dot" support format:
#       [anything .. anything, incremented by k, transformed by g(x)]
#           standard "no dot" support format:        
#       [a1, a2, a3, ... , aN]
#    7. Determine if the random variable X has a "dot" support format
#       (which indicates a symbolic PDF) or a "nodot" support format
#       (which indicates a numeric support format). Return an error
#       message for symbolic support values in the "dot" format, such
#       as X := [[x -> x/6], [1 .. n], ["Discrete", "PDF"]];
#    8. If only 3 arguments are given, by default items are sampled
#       with replacement  
#    9. If X has a numeric PDF, then calculate the PDF of the rth order
#       statistic by looping through the formula given in the code for
#       each value of x from min(support of X) to max(support of X)
#   10. If X has a symbolic PDF, then calculate the PDF of the rth order
#       statistic by obtaining a general expression for the PDF with the
#       same formula used in the numeric case. Since the first term of
#       the PDF is calculated with FX = 1, calculate the first term 
#       separate from the other general terms of the PDF. If the general
#       expression for the order stat PDF evaluated at x = min(support
#       of X) is equal to the same value as the first term of the order
#       stat PDF, then combine them as one expression. Otherwise, leave
#       the order stat PDF as a piecewise function with 2 terms.
#   11. If 4 arguments are provided, check if the fourth argument is
#       the string "wo." If it is, then items are drawn from the RV's
#       population without replacement 
#   12. Determine if the random variable X has a symbolic PDF. If it
#       does and also has finite support, then call the procedure
#       ConvertToNumeric to convert its PDF and support to the standard
#       APPL numeric list format. The conversion is necessary in order
#       to have list inputs for the procedures NextPermutation and
#       NextCombination.
#   13. Check that the sample size n is not greater than the population
#       size N. If it is, return an error message.
#   14. If X has fijite support, check to see if it has equally likely 
#       probabilities. If so, compute the PDF of the rth order statistic
#       by a combinatorial formula given in the code.
#   15. If X has finite support, but not equally likely probabilities,
#       the PDF of the rth order statistic is computed differently if 
#       n = 1, n = N, or n = 2, 3, ... N - 1. If n = 1, the PDF of the
#       rth order statistic is the same as the population PDF. If n = N, 
#       the PDF of the rth order statistic 1 for x = r, and 0 otherwise.
#   16. If n = 2, 3, ... N - 1, create an "n by N" array, ProbStorage,
#       to store the rth order statistic PDF values for r from 1 to n,
#       and x from 1 to N. Initialize ProbStorage to contain all zeros.
#   17. Create the first lexicographical combination of n items. 
#   18. Assign perm as the current combination. For each combination,
#       the algorithm finds every possible permutation of that
#       combination.
#   19. For each permutation, compute the probability of obtaining that
#       given permutation.
#   20. Order each permutation and determine which value sits in the rth
#       ordered position. Store the permutation's probability in the
#       appropriate positions in the array ProbStorage.
#   21. Find the next lexicographical combination, and repeat steps 18 -
#       20.
#   22. If X has infinite support, then:
#         (a) if n = 1, the PDF of the rth order statistic is the same
#             as the population PDF,
#         (b) if n = 2 and r = 1, a general formula for the PDF of the 
#             rth order statistic is computed,
#         (c) at present, OrderStat is unable to handle infinite support
#             without replacement cases for n > 2, r > 1. This is an 
#             open area for future work. Return a message to the user
#             stating this.
#   23. If 4 arguments are provided and the fourth one is not the
#       string "wo", then return an error message
#   24. If the RV X is neither continuous or discrete, return an error
#       message
#   25. Return the rth order statistic in the list of sublists format
#
OrderStat := proc(X :: list(list), n :: {posint, symbol}, r :: {posint,
    symbol}, indicator :: string)
local NumLists, fX, FX, nsegs, fXOS, i, ffX, N, Lo, Hi, Symbolic, SX, k, 
    fXOS1, fXOS2, RealValue, Finite, EqLike, index, ProbStorage, j,
    combo, perm, PermProb, cumsum, m, orderedperm:
with(combinat, binomial):
with(combinat, multinomial):
#
#  Check for the appropriate number of arguments
#
if ((nargs <> 3) and (nargs <> 4)) then
  print(`ERROR(OrderStat): This procedure requires 3 or 4 arguments:`):
  print(`A random variable X,`):
  print(`the number of random items sampled from the population n,`):
  print(`the index of the order statistic r, and`):
  print(`an optional argument "wo", which indicates sampling *without*`): 
  print(`replacement for discrete random variables`):
  RETURN():
fi:
#
#  Check that the order statistic index, r, is not greater than the
#  number of items drawn randomly from the population, n; i.e.
#  check r <= n if r and n are integers (not symbolic parameters)
#
if (type(r, posint) and type(n, posint)) then
  if (r > n) then
    print(`ERROR(OrderStat): The order statistic index, r, cannot be`):
    print(`greater than the size of the random sample drawn, n`):
    RETURN():
  fi:
fi:
#
#  Check that the RV X is a list of 3 sublists
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(OrderStat): The RV X must be a list of 3 lists`):
  RETURN():
fi:
#
#  Convert X to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
  fX := X:
elif ((X[3][2] = "CDF") or
      (X[3][2] = "SF") or
      (X[3][2] = "HF") or
      (X[3][2] = "CHF") or
      (X[3][2] = "IDF")) then
  fX := PDF(X):
else
  print(`ERROR(OrderStat): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  RETURN():
fi:
FX := CDF(fX):
#
#  If the RV X is continuous and it CDF is tractable, find the PDF of
#  the rth order statistic
#
if (fX[3][1] = "Continuous") then
  nsegs := nops(fX[1]):
  fXOS := []:
  if(n=1) then
    fXOS := fX[1];
  else
# ??? DLE: (5/16) simplify should be inside the unapply to do any good
    for i from 1 to nsegs do
      ffX := simplify(unapply(n! / ((r - 1)! * (n - r)!) * (FX[1][i](x))
          ^ (r - 1) * (1 - FX[1][i](x)) ^ (n - r) * fX[1][i](x), x)):
      fXOS := [op(fXOS), op(ffX)]: 
    od:
  fi;
#
#  If the RV X is discrete, then call the procedure Convert(X) to
#  convert the discrete random variable's support to a standard APPL
#  discrete RV support format. See the introductory comments (#6) for
#  the structure of these support formats.
#
elif (fX[3][1] = "Discrete") then
  fX := Convert(fX):
  if (fX = false) then
    print(`ERROR(OrderStat): Discrete RV X is NOT in legal APPL form`):
    RETURN():
  fi:
  SX := SF(fX):
#
#  Determine if the random variable X has a "dot" support format (which
#  indicates a symbolic PDF) or a "nodot" support format (which
#  indicates a numeric support format). Return an error message for 
#  symbolic support values in the "dot" format, such as:
#  X := [[x -> x/6], [1 .. n], ["Discrete", "PDF"]];
#
  if type(fX[2][1], dot) then
    Lo := lhs(fX[2][1]):
    Hi := rhs(fX[2][1]):
    if type(Hi, symbol) and not(evalb(Hi = infinity)) then 
      print(`ERROR(OrderStat): RV's support must be numeric`):
      RETURN():
    elif type(Lo, symbol) or evalb(Lo = -infinity) then 
      print(`ERROR(OrderStat): RV's lower support must be`):
      print(`a finite numerical value`):
      RETURN():
    else
      Symbolic := true:
    fi:
  else
    N := nops(fX[2]):
    Symbolic := false:
  fi:
#
#  If only 3 arguments are given, by default items are sampled with
#  replacement  
# 
  if (nargs = 3) then
#
#  RV has numeric PDF
#  Example:  X := [[1/6, 1/3, 1/2], [1, 2, 3], ["Discrete", "PDF"]];
#
#  DISCRETE/WITH REPLACEMENT/NUMERIC PDF
#
    if not(Symbolic) then
      # print(`not symbolic`):
      fXOS := [seq(0, i = 1 .. N)]:
      for k from 1 to N do
        if (N = 1) then
          fXOS[1] := 1:
        elif (k = 1 and k <> N) then
          fXOS[1] := sum(binomial(n, w) * 
                     1 * (fX[1][1] ^ (n - w)) * (SX[1][2] ^ w),
                     w = 0 .. (n - r)):
        elif (k = N and k <> 1) then
          fXOS[N] := sum(binomial(n, u) * 
                     (FX[1][N - 1] ^ u) * (fX[1][N] ^ (n - u)) * 1,
                     u = 0 .. (r - 1)):
        else
          # Maple will only return multinomial expression in answer
	  # Changed code with defn of multinomial on 6/7/2007
	  fXOS[k] := sum(sum(n! / (u! * (n - u - w)! * w!) * 
                    (FX[1][k - 1] ^ u) * (fX[1][k] ^ (n - u - w)) * 
                    (SX[1][k + 1] ^ w), w = 0 .. (n - r)), 
                     u = 0 .. r - 1):	  
	  # fXOS[k] := sum(sum(multinomial(n, u, n - u - w, w) * 
          #          (FX[1][k - 1] ^ u) * (fX[1][k] ^ (n - u - w)) * 
          #          (SX[1][k + 1] ^ w), w = 0 .. (n - r)), 
          #           u = 0 .. r - 1):
	  # print(`multinomial from here`):
        fi:
      od:
#
#  RV has symbolic PDF
#  Example:  X := [[x -> x/6], [1 .. 3], ["Discrete", "PDF"]];
#
#  fXOS1 holds the (numeric) PDF value of the rth order statistic at Lo.
#  fXOS2 holds the (symbolic) expression for the PDF of the rth order
#  statistic at Lo + 1, Lo + 2, ... 
#
#  DISCRETE/WITH REPLACEMENT/SYMBOLIC PDF
#
    else
      # print(`symbolic`):
      # Substitute Lo in fX, Lo + 1 in SX, and assign FX = 1
      fXOS1 := sum(binomial(n, w) * 1 * 
        ((subs(x = Lo, op(unapply(fX[1](x))(x)))) ^ (n - w))
        * (subs(x = Lo + 1, op(unapply(SX[1](x))(x))) ^ w), 
        w = 0 .. (n - r)):
      # print(fXOS1): 
      fXOS1 := simplify(fXOS1):
      # Substitute k - 1 in FX, k in fX, and k + 1 in SX
      fXOS2 := sum(sum(n! / (u! * (n - u - w)! * w!) * 
          (subs(x = k - 1, op(unapply(FX[1](x))(x))) ^ u) * 
          ((subs(x = k, op(unapply(fX[1](x))(x)))) ^ (n - u - w)) *
          (subs(x = k + 1, op(unapply(SX[1](x))(x))) ^ w), 
           w = 0 .. (n - r)), u = 0 .. r - 1):
      # Maple will only return multinomial expression in answer for fXOS2
      # Changed code with defn of multinomial on 6/22/2007
      fXOS2 := simplify(fXOS2):
      # Write the PDF in terms of x, instead of k
      fXOS2 := subs(k = x, fXOS2):
      # print(fXOS2):
      # Special fix for Possion RV
# NOTE: PUT IN THE FOLLOWING 3 LINES 8/16/2000 -- fixed the
# discrepancy of getting GAMMA(x + 1) vs x * GAMMA(x) ... this subs
# does the job!
      if has(denom(fXOS2), GAMMA(x + 1)) then
        fXOS2 := subs(GAMMA(x + 1) = x * GAMMA(x), fXOS2):
      fi:
      if has(denom(fXOS2), GAMMA(x)) then
        fXOS2 := convert(fXOS2, factorial):
      fi:
      RealValue := subs(x = Lo, fXOS2):
      #  print(RealValue):
      #
      #  ACTUALLY, could just call CleanUp? (BELOW)
      #  Is it working for Discrete RVs? 
      #  5/26/01
      #
      #  If fXOS1 is the same value as fXOS2 evaluated at x = Lo, then
      #  then combine fXOS1 and fXOS2 into one formula
      #
      if ((evalb(evalf(RealValue, Digits + 2) = 
                evalf(fXOS1, Digits + 2))) or 
           evalb(simplify(RealValue) = fXOS1)) then
        fXOS := [unapply(fXOS2, x)]:
        fX[2]:= [Lo .. Hi]:
      else
        # print(`why going here?`):
        fXOS := [fXOS1, unapply(fXOS2, x)]: 
        fX[2] := [Lo, Lo + 1 .. Hi]:
      fi:
    fi:
#
#  If 4 arguments are provided and the 4th argument is the string "wo",
#  then items are sampled *without replacement*
#
  elif ((nargs = 4) and is(indicator = "wo")) then
    Finite := true:
#
#  Determine if the random variable X has a symbolic PDF.  If it does 
#  and also has finite support, then call the procedure ConvertToNumeric
#  to convert its PDF and support to the standard APPL numeric list
#  format.  The conversion is necessary in order to have list inputs for
#  the procedures NextPermutation and NextCombination.
#
    if (Symbolic) then
      if (is(Lo, infinity) or is(Hi, infinity))
          then 
        Finite := false:
      else
        fX := ConvertToNoDot(fX):
        print(`fX is`, fX):
        N := nops(fX[2]):
      fi:
    fi:
#
#  The random variable X has finite support
#
    if (Finite) then
      if type(r, posint) then
        fXOS := [seq(0, i = r .. N - n + r)]:
        fX[2] := fX[2][r .. N - n + r]:
      fi:
#
#  Check that the sample size n is not greater than the population
#  size N. If it is, return an error message.
#
      if (n > N) then
        print(`ERROR(OrderStat): When sampling *without* replacement,`):
        print(`n CANNOT be larger than the population size`, N):
        RETURN():
      fi:
#
#  Determine if the PDF has equally likely probabilities
#
      EqLike := true:  
      for i from 1 to N while EqLike do
        if (fX[1][1] <> fX[1][i]) then
          EqLike := false:
        fi:
      od:
#
#  Find the PDF of the rth order statistic given that the support is 
#  finite and the discrete probabilities are equally likely
#
#  DISCRETE/WITHOUT REPLACEMENT/FINITE SUPPORT/EQUALLY LIKELY PROBS
#
      if (EqLike) then
        if type(r, symbol) then
          unapply('x'):
          fXOS := [(binomial(x - 1, r - 1) * binomial(1, 1) * 
              binomial(N - x, n - r)) / binomial(N, n)]:
          RETURN([fXOS, [x = r .. N - n + r], ["Discrete", "PDF"]]):
        else
          index := 1:
          for i from r to (N - n + r) do
            fXOS[index] := (binomial(i - 1, r - 1) * binomial(1, 1) * 
                binomial(N - i, n - r)) / binomial(N, n):
            index := index + 1:
          od:
        fi:
#
#  Find the PDF of the rth order statistic given that the support is 
#  finite, but the discrete probabilities are not equally likely. Treat
#  n = 1 and n = N as special cases.
#
#  DISCRETE/FINITE SUPPORT/WITHOUT REPLACEMENT/NON-EQUALLY LIKELY PROBS
#
      elif not(EqLike) then
        # n is 1 
        if is(n = 1) then
          fXOS := fX[1]:
        # n is N; fXOS is a list with only 1 element
        elif is(n = N) then
          fXOS[1] := 1:
#
#  n is neither 1 nor N; i.e. n = 2, 3, ... N-1. Create an "n by N" 
#  array, ProbStorage, to store the rth order statistic PDF values for
#  r from 1 to n, and x from 1 to N. Initialize ProbStorage to contain
#  all zeros.
#
        else
          ProbStorage := array(1 .. n, 1 .. N):
          for i from 1 to n do
            for j from 1 to N do
              ProbStorage[i, j] := 0:
            od:
          od:
          # Create the first lexicographical combination of n items
          combo := [seq(i, i = 1 .. n)]:
          for i from 1 to binomial(N, n) do
            # Assign perm as the current combo
            perm := combo:
#
#  Compute the probability of obtaining the given permutation, perm
#
            for j from 1 to n! do
              # print(`perm is`, perm):
              PermProb := fX[1][perm[1]]:
              cumsum := fX[1][perm[1]]:
              for m from 2 to n do
                PermProb := PermProb * fX[1][perm[m]] / (1 - cumsum):
                # print(`PermProb is`, PermProb):
                cumsum := cumsum + fX[1][perm[m]]:
              od:
#
#  Order each permutation and determine which value sits in the rth
#  ordered position. Store the permutation's probability in the
#  appropriate positions in the array ProbStorage.
#
              orderedperm := sort(perm):
              for m from 1 to n do
                for k from 1 to N do
                  if (orderedperm[m] = k) then
                    ProbStorage[m, k] := PermProb + ProbStorage[m, k]:
                    #print(`m is`, m):
                    #print(`k is`, k):
                    #print(`ProbStorage[m, k] is`, ProbStorage[m, k]):
                  fi:
                od:
              od:
              # Find the next lexicographical permutation
              perm := NextPermutation(perm):
            od:
            # Find the next lexicographical combination
            combo := NextCombination(combo, N):
          od:
          index := 1:
          for m from r to N - n + r do
            fXOS[index] := ProbStorage[r, m]:
            index := index + 1:
          od:
        fi:
      fi:
#
#  If X has infinite support, then:
#    (a) if n = 1, the PDF of the rth order statistic is the same as the
#        population PDF,
#    (b) if n = 2 and r = 1 or 2, a general formula for the PDF of the rth
#        order statistic is computed,
#    (c) at present, OrderStat is unable to handle infinite support/
#        without replacement cases for n > 2, r > 2. Return a message to
#        the user stating this.
#
#  DISCRETE/INFINITE SUPPORT/WITHOUT REPLACEMENT
#
    else
      fX[2] := X[2]:
      if (n = 1) then
        fXOS := fX[1]:
      elif (n = 2) and (r = 1) then
        fXOS := [unapply(simplify(op(unapply(fX[1](x))(x)) * 
                subs(x = x + 1, op(unapply(SX[1](x))(x))) 
                / (1 -  op(unapply(fX[1](x))(x)))) + 
                op(unapply(fX[1](x))(x)) * 
                sum(subs(x = y, op(unapply(fX[1](x))(x))) /
                subs(x = y, 1 - op(unapply(fX[1](x))(x))), 
                y = x + 1 .. infinity), x)]:    
      elif (n = 2) and (r = 2) then    
        fXOS := [unapply(simplify(op(unapply(fX[1](x))(x)) * 
                subs(x = x - 1, op(unapply(FX[1](x))(x))) 
                / (1 -  op(unapply(fX[1](x))(x)))) + 
                op(unapply(fX[1](x))(x)) * 
                sum(subs(x = y, op(unapply(fX[1](x))(x))) /
                subs(x = y, 1 - op(unapply(fX[1](x))(x))), 
                y = 1 .. x - 1), x)]:    
      else
        print(`ERROR(OrderStat): At present, OrderStat cannot handle`):
        print(`this infinite support RV in the without replacement`):
        print(`case`):
        RETURN():
      fi:
    fi:
#
#  If 4 arguments are provided and the fourth one is not the string
#  "wo", then return an error message
#
  else
    print(`ERROR(OrderStat): The 4th argument must be the string`):
    print(`"wo" to indicate items are drawn *without* replacement`):
    RETURN():
  fi:
#
#  If the RV X is neither continuous or discrete, return an error
#  message
#
else
  print(`ERROR(OrderStat): The RV X must be continuous or discrete`):
  RETURN():
fi:
#
#  Return the PDF of the rth order statistic in the list of sublists 
#  format
#
RETURN([fXOS, fX[2], fX[3]]): 

end:

#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: pdf6.map
#  
#  Procedure Name: PDF(X, [x])
#
#  Other APPL Procedures Called: IDF, Convert, HF, SF, CDF
#
#  Date: March 17, 2001
#
#  Purpose: PDF is a procedure that:
#          (1) Returns the probability density function (continuous)
#              or the probability mass function (discrete) of a 
#              random variable X in the APPL list of 3 lists format if
#              the only argument given is X, or
#          (2) Returns the value Pr(X = x) if it is given the optional
#              argument x in addition to the RV X
#
#  Arguments: X: A continuous or discrete random variable; 
#             x (optional argument): A numeric value entered when
#                trying to determine Pr(X = x)
#
#  Algorithm: 1. Perform error checking on user entered arguments
#             2. The PDF of X is determined by sending it to its 
#                appropriate category, which is based on whether:
#                A. X is continuous or discrete
#                B. X is entered in its PDF, CDF, SF, HF, CHF, or IDF
#                   format 
#             3. If only 1 argument (the random variable X) is entered
#                by the user, return the probability density function of
#                X in the APPL list of 3 lists format 
#             4. If 2 arguments are provided, return the value Pr(X = x)
# 
PDF := proc(X :: list(list), st)
local numlists, nsegments, fX,fXXX, supp, i, ffx, hX, FX, solns, nsolns, j,
    c, ii, t, itp, a, prob, Y, Range, lo, hi, incr, transf, cdf, pdf,
    sf, hf, hfprod, chf, idf, idforig, pieces, k, numops, noceil,
    ceilpiece, val, invfound, idfval, losupp, hisupp, sublist1, n, SX,
    notfound, count:
#
#  Check for the appropriate number of arguments
#
if ((nargs <> 1) and (nargs <> 2)) then
  print(`ERROR(PDF): This procedure requires 1 or 2 arguments:`):
  print(`A random variable X and an optional argument x for`):
  print(`computing Pr(X = x)`):
  return:
fi:
#
#  Check that the RV X is in the list of 3 lists format
#
numlists := nops(X):
if (numlists <> 3) then
  print(`ERROR(PDF): The RV X must be a list of 3 lists`):
  return:
fi:
#
#  Make sure X is given as a PDF, CDF, SF, HF, CHF, or IDF
#
if not(member(X[3][2], {"PDF", "CDF", "SF", "HF", "CHF", "IDF"})) then
  print(`ERROR(PDF): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
#
#  If the RV X is continuous, find and return the PDF of X
#
if (X[3][1] = "Continuous") then
  nsegments := nops(X[1]):
  fX := []:
  supp := X[2]:
#
#  The RV X is given in its PDF form. Nothing needs to be done to X.
#
  if X[3][2] = "PDF" then
    fX := X[1]:
#
#  The RV X is given in its CDF form
#
  elif (X[3][2] = "CDF") then 
    for i from 1 to nsegments do
      ffx := unapply(diff(X[1][i](x), x), x):	
      fX := [op(fX), op([unapply(simplify(ffx(x)), x)])]:
    od:
#
#  The RV X is given in its SF form
#
  elif (X[3][2] = "SF") then 
    for i from 1 to nsegments do
      ffx := unapply(-diff(X[1][i](x), x), x):	
      fX := [op(fX), op([unapply(simplify(ffx(x)), x)])]:
    od:
#
#  The RV X is given in its HF form
#
  elif (X[3][2] = "HF") then
#    for i from 1 to nsegments do
#      hX := X[1][i](t):
#      hhX := subs(t = x, hX):
#      print(`hhx`,hhX);
#      ffx := hhX * exp(-int(hX, t = X[2][i] .. x)):
#      print(`segment num`,i,`ffx `,ffx);
#      fX := [op(fX), op([unapply(simplify(ffx), x)])]:
#    od:
     SX:=SF(X):
     fXXX:=PDF(SX):
     fX:=fXXX[1]:	

#
#  The RV X is given in its CHF form
#
  elif (X[3][2] = "CHF") then
    for i from 1 to nsegments do
      ffx := unapply(diff(X[1][i](x))(x)) * 
             exp(-unapply(X[1][i](x))(x)):
      fX := [op(fX), op([unapply(simplify(ffx), x)])]:
    od:
#
#  The RV X is given in its IDF form
#
  elif (X[3][2] = "IDF") then
    FX[1] := []:
    for i from 1 to nsegments do  
      solns := [solve(X[1][i](x) = s, x)]:
      nsolns := nops(solns):  
      solns := [seq(unapply(simplify(solns[j]), s), 
          j = 1 .. nsolns)]:
      # Find right inverse
      if (nsolns = 1) then 
        # If there is only one inverse, assign it to ginv.
        FX[1] := [op(FX[1]), solns[1]]: 
      else 
        # If there is more than one inverse, find the appropriate one.
        # Find midpoints of each segment
        c := array(1 .. nsegments):
        for ii from 1 to nsegments do
          c[ii] := (X[2][ii] + X[2][ii + 1]) / 2:
        od:
        for t from 1 to nsolns do 
          # Evaluate each inverse of the CDF at the midpoint of the
          # subinterval.  Set IDX[1][i] to that inverse for which 
          # gtemp(g(x)) = x.
          itp := solns[t](X[1][i](c[i])): 
          if (whattype(evalf(X[1][i](c[i]))) <> float) then 
            # print(notafloat, simplify(itp), c[i]):
          else 
            # print(isafloat, itp, c[i]):
          fi:
          if (((whattype(evalf(X[1][i](c[i]))) <> float) and
                (itp = c[i])) or 
             ((whattype(evalf(X[1][i](c[i]))) = float) and 
                (evalf(itp) >= evalf(X[2][i]) and 
                (evalf(itp) <= evalf(X[2][i + 1]))))) then
            FX[1] := [op(FX[1]), solns[t]]: 
            break:
          else
            print(`ERROR(PDF): Could not find the appropriate inverse`):
          fi:  
        od:
      fi:
    od:
    supp := []: 
    for i from 1 to (nsegments + 1) do 
      supp := [op(supp), limit(a, a = IDF(X, X[2][i]))]:
    od:
    for i from 1 to nsegments do
      ffx := unapply(diff(FX[1][i](x), x), x):	
      fX := [op(fX), op([unapply(simplify(ffx(x)), x)])]:
    od:
  fi:
#
#  Only 1 argument, X, given for the procedure
#
  if (nargs = 1) then
    return([fX, supp, ["Continuous", "PDF"]]):
#
#  Two arguments, X and x, provided for the procedure
#
  elif (nargs = 2) then
    if not(type(evalf(st), {numeric, infinity})) then
      if nsegments = 1 then
        prob := fX[1](st):
        return(prob):
      else
        print(`ERROR(PDF): Symbolic second arguments with a piecewise`):
        print(`PDF are not allowable in APPL at this time`):
        return:
      fi:
    fi:

    if (evalf(st) = evalf(supp[nops(supp)])) then
      prob := fX[nsegments](st):
      return(prob):
    else
      for i from 1 to nsegments do 
        if ((evalf(st) >= evalf(supp[i])) and (evalf(st) < evalf(supp[i
            + 1]))) then
          break:
        fi:
      od:
      prob := fX[i](st):
      return(prob):
    fi:
  fi:
#
#  The RV X is a discrete random variable
#
elif (X[3][1] = "Discrete") then
#
#  If the RV X is discrete, then call the procedure Convert(X) to
#  convert the discrete random variable's support to a standard APPL
#  discrete RV support format. Assign the converted random variable
#  to the Maple variable Y.
#
  Y := Convert(X):
  fX[1] := Y[1]:
  fX[2] := Y[2]:
#
# X has dot support
#
  if type(Y[2][1], range) then
    Range := Y[2][1]:
    lo := lhs(Range):
    hi := rhs(Range):
    if member(Y[3][2], {"PDF", "CDF", "SF", "HF", "CHF"}) then
      incr := Y[2][2]:
      transf := Y[2][3]:
#
#  Report the support of new random variable back to the user in its
#  simplest form
#
      if (incr = 1 and unapply(transf(x))(x) = x) then
        fX[2] := [Range]:
      elif (not(incr = 1) and unapply(transf(x))(x) = x) then
        fX[2] := [Range, incr]:
      elif ((incr = 1) and not(unapply(transf(x))(x) = x)) then
        fX[2] := [Range, Y[2][3]]:
      else 
        fX[2] := [Range, incr, Y[2][3]]:
      fi:
    fi:
#
#  APPL is not programmed to convert to a PDF format when the increment
#  is not 1 and/or the transformation is not x -> x
#
#      elif not(incr = 1 and unapply(transf(x))(x) = x) then
#        print(`ERROR(PDF): APPL is currently unable to evaluate`):
#        print(`this RV`):
#        return:
#      fi:
#    fi:

#
#  If X is given in its PDF form, then nothing needs to be done to X.
#
    if (Y[3][2] = "PDF") then
#
#  The RV X is given in its CDF form
#
    elif Y[3][2] = "CDF" then
      cdf := unapply(op(Y[1])(x))(x):
      pdf := simplify(subs(x = x, cdf) - subs(x = x - 1, cdf)):
      fX[1] := [unapply(pdf, x)]:
#
#  The RV X is given in its SF form
#
    elif Y[3][2] = "SF" then
      sf := unapply(op(Y[1])(x))(x):
      pdf := simplify(subs(x = x, sf) - subs(x = x + 1, sf)):
      fX[1] := [unapply(pdf, x)]:
#
#  The RV X is given in its HF form
#
    elif (Y[3][2] = "HF") then
      hf := unapply(op(Y[1])(w))(w):
      # sf := product(1 - hf, w = lo .. (x - 1)):
      # pdf := simplify(subs(x = x, sf) - subs(x = x + 1, sf)):
      # print(`old way`, pdf):
      hfprod := product(1 - hf, w = lo .. (x - 1)):
      pdf := simplify(subs(w = x, hf) * subs(w = x, hfprod)):
      fX[1] := [unapply(pdf, x)]:
#
#  If X is given in its CHF form
#
    elif (Y[3][2] = "CHF") then
      chf := unapply(op(Y[1])(x))(x):
      sf := exp(-chf):
      pdf := simplify(subs(x = x, sf) - subs(x = x + 1, sf)):
      fX[1] := [unapply(pdf, x)]:
#
#  If X is given in its IDF form
#
    elif (Y[3][2] = "IDF") then
      # need to look for a ceil function here!
      # Received help from MUG: James McCarron, Robert Israel
      # > f := ceil(1 / 2 + 1 / 2 * sqrt(1 + 120 * x)) - 1;
      # > eval(f, ceil = (x -> x));   
      idf := unapply(op(Y[1])(y))(y):
      idforig := idf:
      # print(`idf is`, idf):
      # print(`[op(idf)] is`, [op(idf)]):
      idf := eval(idf, ceil = (y -> y)):
      # print(`idf is now`, %):
      # pieces := [op(idf)]:
      # numops := nops(pieces):
      # print(numops):
      # noceil := true:
      # for i from 1 to numops while noceil do
      #   if has(pieces, ceil) then
      #     print(`has ceil`):
      #     noceil := false:
      #     ceilpiece := i:
      #   fi:
      # od:
      # if not(noceil) then
      #   print(pieces[ceilpiece]):
      #   pieces[ceilpiece] := op(pieces[ceilpiece]):
      #   idf := sum(pieces[k], k = 1 .. numops):
      # fi:
      # print(idf):
      solns := [solve(idf = x, y)]:
      # print(solns):
      nsolns := nops(solns):
      # Find the correct inverse
      if (nsolns = 1) then 
        # If there is only one inverse, assign it to cdf.
        cdf := solns[1]:
      else
        if lo = -infinity then
          if hi = infinity then
            val := 1:
          else 
            val := hi:
          fi: 
        else
          val := lo:  
        fi:   
        # print(`val is`, val):
        invfound := false:
        for j from 1 to nsolns do 
          # Evaluate each inverse of the IDF at the value "val" assigned
          # above. If CDF(IDF(val)) = val, then assign idf equal to that
          # inverse. 
          idfval := subs(x = val, idf):
          if evalf(subs(x = idfval, solns[j])) = evalf(val) then
            cdf := solns[j]:
            invfound := true:
            break:
          fi: 
        od:
        if not(invfound) then       
          print(`ERROR(PDF): Could not find the appropriate inverse`):
        fi:  
      fi:
      pdf := simplify(subs(x = x, cdf) - subs(x = x - 1, cdf)):
      fX[1] := [unapply(pdf, x)]:
#  CAUTION: losupp is incorrect in some cases -- currently don't know
#  how to fix this, need to be able to retrieve the first cdf value and
#  sub it into idf as lo
      losupp := evalf(subs(y = lo, idforig)):
      hisupp := evalf(subs(y = hi, idforig)): 
      fX[2] := [losupp .. hisupp]:
    fi:
#
#  X has no dot support
#
  else
    sublist1 := Y[1]:
    n := nops(sublist1):
#
#  If X is given in its PDF form, then nothing needs to be done to X.
#
    if (Y[3][2] = "PDF") then
#
#  If X is given in its CDF form
#
    elif (Y[3][2] = "CDF") then
      for i from n by -1 to 2 do
        fX[1][i] := sublist1[i] - sublist1[i - 1]:
      od:
      fX[1][1] := sublist1[1]:
#
#  If X is given in its SF form
#
    elif (Y[3][2] = "SF") then 
      for i from 1 to n - 1 do
        fX[1][i] := sublist1[i] - sublist1[i + 1]:
      od:
      fX[1][n] := sublist1[n]:
#
#  If X is given in its HF or CHF form
#
    elif member(Y[3][2], {"HF", "CHF"}) then
      hX := HF(Y):
      SX := SF(hX):
      for i from 1 to n do
        fX[1][i] := hX[1][i] * SX[1][i]:
      od:
#
#  If X is given in its IDF form
#
    elif (Y[3][2] = "IDF") then
      FX := CDF(Y):
      sublist1 := FX[1]:
      for i from n by -1 to 2 do
        fX[1][i] := sublist1[i] - sublist1[i - 1]:
      od:
      fX[1][1] := sublist1[1]:
      fX[2] := FX[2]:
    fi:
  fi:
#
#  Only 1 argument, X, given for the procedure
#
  if (nargs = 1) then
    return([fX[1], fX[2], ["Discrete", "PDF"]]):
#
#  Two arguments, X and x, provided for the procedure
#
  elif (nargs = 2) then
    if type(Y[2][1], range) then
#
#  Determine (if possible) if 'st' is in the support of fX; if not,
#  Pr(X = st) = 0.
#
      if not(type(lo, infinity) or type(hi, infinity)) then
#
#  CAUTION: Maple does not consider 1.0 a member of the set {1, 2, 3};
#  Problem if user chooses 'st' to be a float and the set contains
#  integers or vice versa
#
        if not(member(st, {$lo .. hi})) then
          prob := 0:
          return(prob):
        fi:
      fi:
      prob := op(fX[1](st)): 
    else
      prob := 0:
      notfound := true:
      count := 1:
      for k from 1 to n while notfound do
        if evalf(fX[2][k]) = evalf(st) then
          notfound := false:
          prob := fX[1][count]: 
        fi:
        count := count + 1:
      od:
    fi:
    return(prob):
  fi:
#
#  X is neither continuous nor discrete
else
  print(`ERROR(PDF): X must be continuous or discrete`):
fi:
end: #1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: percolatedown2.map
#  for H and B
#
#  Procedure Name: PercolateDown(H, B, i, n)
#
#  Other APPL Procedures Called: 
#
#  Date: September 8, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
PercolateDown := proc(H :: array, Probs :: array, i :: integer, n ::
    integer) 
local ParentValue, HoldValue, Child:

ParentValue := H[i]:
HoldValue := Probs[i]:
# print(`i is`, i):
if i * 2 <= (n + 1) then
#
#  Assign Child to the left child since there may not exist a right 
#  child in a left complete tree
#
  Child := i * 2 - 1:
#
#  If there are 2 children and the right child's value is greater than
#  the left child's value, then update Child to be the right child
#
  if ((Child <> n) and (H[Child + 1] > H[Child])) then
    Child := Child + 1:
  fi:
  # print(`ParentValue is`, ParentValue):
  # print(`Child value is`, H[Child]):
  if ParentValue < H[Child] then
    H[i] := H[Child]:
    H[Child] := ParentValue:
    Probs[i] := Probs[Child]:
    Probs[Child] := HoldValue:
    # print(`H is`, H):
    # print(`Child is`, Child):
    # print(`n is`, n):
    PercolateDown(H, Probs, Child, n):
    # print(`H is`, H):
  fi:
fi:
return(H, Probs):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: percolatedownheap1.map
#  for CreateMinHeap
#
#  Procedure Name: PercolateDownHeap(H, i, n)
#
#  Other APPL Procedures Called: 
#
#  Date: September 16, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
PercolateDownHeap := proc(i :: integer, n :: integer) 
global H, Mimic:
local ParentValue, ProbValue, MimicParentValue, Child:

ParentValue := H[i][1]:
ProbValue := H[i][2]:
MimicParentValue := Mimic[i]:
if i * 2 <= (n + 1) then
#
#  Assign Child to the left child since there may not exist a right 
#  child in a left complete tree
#
  Child := i * 2 - 1:
#
#  If there are 2 children and the right child's value is greater than
#  the left child's value, then update Child to be the right child
#
  if ((Child <> n) and (H[Child + 1][1] < H[Child][1])) then
    Child := Child + 1:
  fi:
  if ParentValue > H[Child][1] then
    H[i] := H[Child]:
    Mimic[i] := Mimic[Child]:
    H[Child][1] := ParentValue:
    H[Child][2] := ProbValue:
    Mimic[Child] := MimicParentValue:
    PercolateDownHeap(Child, n):
  fi:
fi:
return:

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: percolatedownheapq11.map
#
#  Procedure Name: PercolateDownHeapQ1(H, i, n)
#
#  Other APPL Procedures Called: 
#
#  Date: January 11, 2001
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
PercolateDownHeapQ1 := proc(i :: integer, n :: integer) 
global Q1H, Q1Mimic:
local ParentValue, ProbValue, MimicParentValue, Child:

ParentValue := Q1H[i][1]:
ProbValue := Q1H[i][2]:
MimicParentValue := Q1Mimic[i]:
if i * 2 <= (n + 1) then
#
#  Assign Child to the left child since there may not exist a right 
#  child in a left complete tree
#
  Child := i * 2 - 1:
#
#  If there are 2 children and the right child's value is greater than
#  the left child's value, then update Child to be the right child
#
  if ((Child <> n) and (Q1H[Child + 1][1] < Q1H[Child][1])) then
    Child := Child + 1:
  fi:
  if ParentValue > Q1H[Child][1] then
    Q1H[i] := Q1H[Child]:
    Q1Mimic[i] := Q1Mimic[Child]:
    Q1H[Child][1] := ParentValue:
    Q1H[Child][2] := ProbValue:
    Q1Mimic[Child] := MimicParentValue:
    PercolateDownHeapQ1(Child, n):
  fi:
fi:

return:

end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: percolatedownheapq21.map
#  for CreateMinHeap
#
#  Procedure Name: PercolateDownHeapQ2(H, i, n)
#
#  Other APPL Procedures Called: 
#
#  Date: September 16, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
PercolateDownHeapQ2 := proc(i :: integer, n :: integer) 
global Q2H, Q2Mimic:
local ParentValue, ProbValue, MimicParentValue, Child:

ParentValue := Q2H[i][1]:
ProbValue := Q2H[i][2]:
MimicParentValue := Q2Mimic[i]:
if i * 2 <= (n + 1) then
#
#  Assign Child to the left child since there may not exist a right 
#  child in a left complete tree
#
  Child := i * 2 - 1:
#
#  If there are 2 children and the right child's value is greater than
#  the left child's value, then update Child to be the right child
#
  if ((Child <> n) and (Q2H[Child + 1][1] < Q2H[Child][1])) then
    Child := Child + 1:
  fi:
  if ParentValue > Q2H[Child][1] then
    Q2H[i] := Q2H[Child]:
    Q2Mimic[i] := Q2Mimic[Child]:
    Q2H[Child][1] := ParentValue:
    Q2H[Child][2] := ProbValue:
    Q2Mimic[Child] := MimicParentValue:
    PercolateDownHeapQ2(Child, n):
  fi:
fi:

return:

end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: percolatedownheapq31.map
#
#  Procedure Name: PercolateDownHeapQ3(i, n)
#
#  Other APPL Procedures Called: 
#
#  Date: January 11, 2001
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
PercolateDownHeapQ3 := proc(i :: integer, n :: integer) 
global Q3H, Q3Mimic:
local ParentValue, ProbValue, MimicParentValue, Child:

ParentValue := Q3H[i][1]:
ProbValue := Q3H[i][2]:
MimicParentValue := Q3Mimic[i]:
if i * 2 <= (n + 1) then
#
#  Assign Child to the left child since there may not exist a right 
#  child in a left complete tree
#
  Child := i * 2 - 1:
#
#  If there are 2 children and the right child's value is greater than
#  the left child's value, then update Child to be the right child
#
  if ((Child <> n) and (Q3H[Child + 1][1] < Q3H[Child][1])) then
    Child := Child + 1:
  fi:
  if ParentValue > Q3H[Child][1] then
    Q3H[i] := Q3H[Child]:
    Q3Mimic[i] := Q3Mimic[Child]:
    Q3H[Child][1] := ParentValue:
    Q3H[Child][2] := ProbValue:
    Q3Mimic[Child] := MimicParentValue:
    PercolateDownHeapQ3(Child, n):
  fi:
fi:
return:

end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: percolatedownheapq41.map
#  for CreateMinHeap
#
#  Procedure Name: PercolateDownHeapQ4(i, n)
#
#  Other APPL Procedures Called: 
#
#  Date: September 16, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
PercolateDownHeapQ4 := proc(i :: integer, n :: integer) 
global Q4H, Q4Mimic:
local ParentValue, ProbValue, MimicParentValue, Child:

ParentValue := Q4H[i][1]:
ProbValue := Q4H[i][2]:
MimicParentValue := Q4Mimic[i]:
if i * 2 <= (n + 1) then
#
#  Assign Child to the left child since there may not exist a right 
#  child in a left complete tree
#
  Child := i * 2 - 1:
#
#  If there are 2 children and the right child's value is greater than
#  the left child's value, then update Child to be the right child
#
  if ((Child <> n) and (Q4H[Child + 1][1] < Q4H[Child][1])) then
    Child := Child + 1:
  fi:
  if ParentValue > Q4H[Child][1] then
    Q4H[i] := Q4H[Child]:
    Q4Mimic[i] := Q4Mimic[Child]:
    Q4H[Child][1] := ParentValue:
    Q4H[Child][2] := ProbValue:
    Q4Mimic[Child] := MimicParentValue:
    PercolateDownHeapQ4(Child, n):
  fi:
fi:
return:

end:
#1111111111222222222233333333334444444444555555555566666666667777777777 
#  Filename: plotdist7.map
#
#  NOTE (6/24/00): plotdist3.map having trouble with KSRV(n) when
#  lo and hi are given -- see plotdist3.mws; Fixed in plotdist4
#  Problem -- if range given by user, the new max range value for X does
#  not automatically become that high value -- need to figure out what
#  segment that high value falls in in a piecewise function ... same
#  with low
#
#  NOTE: plotdist6.map has discrete capabilities
#
#  NOTE: plotdist7.map defines lo and hi for infinite support range
#  as IDF(X, 0.025), IDF(X, 0.975)
#
#  NOTE: plotdist.map only works for 1 argument in discrete case right
#  now -- user cannot supply his own range ... APPL determines the best
#  support range for graphing
#
#  Procedure name: PlotDist(X, low, high)
#
#  Date: May 16, 2001
#
#  Purpose: For the random variable X, plot the function indicated in 
#  the  random variable X's list-of-sublists (PDF, CDF, SF, HF, CHF,
#  or IDF) 
#
#  Arguments: X: Random variable; 
#             low, high (optional values): values provided by the user
#             to indicate over what range the function is to be plotted
#  
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Check that the RV X is in a list-of-lists format
#    3.  Check that X is in its PDF, CDF, SF, HF, CHF, or IDF format
#
PlotDist := proc(X :: list(list), low, high)
local NumLists, nsegs, Xsegs, i, Xrange, lo, hi, Y, incr, formulaic, N,
    pdf, Cross, Circle, pdfplot, cdf, Open0, Open, Closed, CrossN,
    ClosedN, cdfplot, sf, Cross0, Closed0, OpenN, sfplot, hf, hfplot, 
    chf, chfplot, idf, idfplot:
# print(`X is`, X):
# print(`Low is`, low):
# print(`High is`, high):
#
#  Check for the appropriate number of arguments
#
if ((nargs <> 1) and (nargs <> 3)) then
  print(`ERROR(PlotDist): This procedure requires either 1 or 3`):
  print(`arguments`):
  return:
fi:
#
#  Check that the RV X is in a list-of-lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(PlotDist): X must be in a list-of-sublists format`):
  return:
fi:
#
#  Check that X is in its PDF, CDF, SF, HF, CHF, or IDF format
#
if not((X[3][2] = "PDF") or
       (X[3][2] = "CDF") or
       (X[3][2] = "SF") or
       (X[3][2] = "HF") or
       (X[3][2] = "CHF") or
       (X[3][2] = "IDF")) then
  print(`ERROR(PlotDist): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
#
#  If the user does not provide values for low and high, set 
#  the default values as the lower and upper range values in sublist 2
#
if (X[3][1] = "Continuous") then
  nsegs := nops(X[1]): 
  # print(`nsegs is`, nsegs):
  Xsegs := array(1 .. nsegs):
  if (nargs = 1) then
    for i from 1 to nsegs do
      Xsegs[i] := plot(X[1][i](x), x = X[2][i] .. X[2][i + 1], 
          labels = [x, X[3][2]]): 
    od:
    plots[display]({seq(Xsegs[j], j = 1 .. nsegs)}, 
        scaling = unconstrained):
#
#  The user has provided values for low and high
#
  elif (nargs = 3) then
    Xrange := X[2]:
    lo := 1:
    hi :=nsegs:
#
#  Inform the user that the values for low and high have been reset if
#  they are out of the random variable's support range
#
    if (evalf(low) < evalf(X[2][1])) then
      print(`WARNING(PlotDist): Low value provided by user`, low):
      print(`is less than minimum support value of random variable`):
      print(X[2][1]):
      print(`Resetting low to RV's minimum support value`):
      Xrange[1] := X[2][1]:
    else
      for i from nsegs to 1 by -1 do
        if (evalf(X[2][i]) <= evalf(low)) then
          lo := i:
          break:
        fi:
      od:
      Xrange[lo] := low:
    fi:
    if (evalf(high) > evalf(X[2][nsegs + 1])) then
      print(`WARNING(PlotDist): High value provided by user`, high):
      print(`is greater than maximum support value of the random`):
      print(`variable`, X[2][nsegs + 1]):
      print(`Resetting high to RV's maximum support value`):
      Xrange[nsegs + 1] := X[2][nsegs + 1]:
    else 
      for i from 1 to nsegs do
        if (evalf(X[2][i]) >= evalf(high)) then
          hi := i - 1:
          break:
        fi:
      od:
      Xrange[hi + 1] := high:
    fi:
    # print(`Xrange is`, Xrange):
    # print(lo, hi):
    for i from lo to hi do
      # print(X[1][i]):
      # print(X[2][i], X[2][i + 1]):
# Just using for the ps plot
      Xsegs[i] := plot(X[1][i](x), x = Xrange[i] .. Xrange[i + 1],
          labels = ["x", X[3][2]], 
          labeldirections = [horizontal, horizontal]):
    od:
    plots[display]({seq(Xsegs[j], j = lo .. hi)}, 
        scaling = unconstrained):
  fi:
else
  Y := Convert(X):
  if (Y = false) then
    print(`ERROR(PlotDist): Discrete RV X is NOT in legal APPL form`):
    return:
  fi:
# print(Y[2]):
# for IDF: Convert procedure needs to return *dot* standard format
# for IDF -- convert4.map currently doesn't 
  if type(Y[2][1], range) then
    formulaic := true:
    lo := lhs(Y[2][1]):
    hi := rhs(Y[2][1]):
    incr := Y[2][2]:
    if type(hi, symbol) then
      if evalb(hi = infinity) then
        hi := IDF(Y, 0.975):
        # hi contains something like a "rootof" expression
        if type(hi, function) then
          hi := 4:
# print(`ERROR(PlotDist): Please try again, but provide`):
# print(`the procedure with low and high range values`):
# return:
        fi:  
        # convert to a float value
        hi := evalf(hi):
      else
        print(`ERROR(PlotDist): RV's support must be numeric`):
        return:
      fi:
    elif type(lo, symbol) or evalb(lo = -infinity) then 
      print(`ERROR(PlotDist): RV's lower support must be`):
      print(`a finite numerical value.`): 
# print(`Please try again, but provide`):
# print(`the procedure with low and high range values`):
      return:
    fi:
  else
    N := nops(Y[2]):
    lo := Y[2][1]:
    hi := Y[2][N]:
    formulaic := false:
  fi:
  if (Y[3][2] = "PDF") then
    pdf := {}:
    if not(formulaic) then
      for i from 1 to N do
        pdf := pdf union {[[Y[2][i], 0], [Y[2][i], Y[1][i]]]}:
        Cross[i] := PLOT(POINTS([Y[2][i], Y[1][i]], SYMBOL(CROSS))):
        Circle[i] := PLOT(POINTS([Y[2][i], Y[1][i]], SYMBOL(CIRCLE))):
      od:
      pdfplot := plot(pdf, x = lo - 0.5 .. hi + 0.5, 
          labels = ["x", "PDF"],
          labeldirections = [horizontal, horizontal]):
      plots[display]({pdfplot, seq(Cross[i], i = 1 .. N), 
          seq(Circle[i], i = 1 .. N)}):
    # ONLY CONSIDERING CASE WITH x -> x TRANSFORMATION
    else # formulaic pdf
      for i from lo by incr to hi do
        pdf := pdf union {[[i, 0], [i, op(Y[1](i))]]}:
        Cross[i] := PLOT(POINTS([i, evalf(op(Y[1](i)))], 
            SYMBOL(CROSS))):
        Circle[i] := PLOT(POINTS([i, evalf(op(Y[1](i)))], 
            SYMBOL(CIRCLE))):
        # print(Cross[i]):
      od:
      # print(pdf):
      pdfplot := plot(pdf, x = lo - 0.5 .. hi + 0.5, 
          labels = ["x", "PDF"],
          labeldirections = [horizontal, horizontal], color = black,
          linestyle = 1):
      plots[display]({pdfplot, seq(Cross[i], i = lo .. hi), 
          seq(Circle[i], i = lo .. hi)}):
    fi:
  elif (Y[3][2] = "CDF") then
    if not(formulaic) then
      cdf := {[[0, 0], [Y[2][1], 0]]}:
      Open0 := PLOT(POINTS([Y[2][1], 0], SYMBOL(CIRCLE))):
      for i from 1 to N - 1 do
        cdf := cdf union {[[Y[2][i], Y[1][i]], [Y[2][i + 1], Y[1][i]]]}:
        Open[i] := PLOT(POINTS([Y[2][i + 1], Y[1][i]], 
            SYMBOL(CIRCLE))):
        Cross[i] := PLOT(POINTS([Y[2][i], Y[1][i]], SYMBOL(CROSS))):
        Closed[i] := PLOT(POINTS([Y[2][i], Y[1][i]], SYMBOL(CIRCLE))):
      od:
      cdf := cdf union {[[Y[2][N], 1], [Y[2][N] + hi, 1]]}:
      CrossN := PLOT(POINTS([Y[2][N], 1], SYMBOL(CROSS))):
      ClosedN := PLOT(POINTS([Y[2][N], 1], SYMBOL(CIRCLE))):
      # print(cdf):
      cdfplot := plot(cdf, x = lo - 0.5 .. hi + 0.5, 
          labels = ["x", "CDF"], color = black,
          labeldirections = [horizontal, horizontal]):
      plots[display]({cdfplot, Open0, seq(Open[i], i = 1 .. N - 1),
          seq(Cross[i], i = 1 .. N - 1), 
          seq(Closed[i], i = 1 .. N - 1), CrossN, ClosedN}):
    # ONLY CONSIDERING CASE WITH x -> x TRANSFORMATION
    else # formulaic cdf
      cdf := {[[0, 0], [lo, 0]]}:
      Open0 := PLOT(POINTS([lo, 0], SYMBOL(CIRCLE))):
      for i from lo by incr to hi do
        cdf := cdf union {[[i, op(Y[1](i))], [i + 1, op(Y[1](i))]]}:
        Open[i] := PLOT(POINTS([i + 1, op(Y[1](i))], SYMBOL(CIRCLE))):
        Cross[i] := PLOT(POINTS([i, op(Y[1](i))], SYMBOL(CIRCLE))):
        Closed[i] := PLOT(POINTS([i, op(Y[1](i))], SYMBOL(CROSS))):
        # print(cdf):
      od:
      cdf := cdf union {[[hi, 1], [hi + hi, 1]]}:
      ClosedN := PLOT(POINTS([hi, 1], SYMBOL(CROSS))):
      # print(cdf):
      cdfplot := plot(cdf, x = lo - 0.5 .. hi + 0.5, 
          labels = ["x", "CDF"], color = black,
          labeldirections = [horizontal, horizontal]):
      plots[display]({cdfplot, Open0, seq(Open[i], i = lo .. hi),
          seq(Cross[i], i = lo .. hi), 
          seq(Closed[i], i = lo .. hi), ClosedN}):
    fi:
  elif (Y[3][2] = "SF") then
    if not(formulaic) then
      sf := {[[0, 1], [Y[2][1], 1]]}:
      Cross0 := PLOT(POINTS([Y[2][1], 1], SYMBOL(CROSS))):
      Closed0 := PLOT(POINTS([Y[2][1], 1], SYMBOL(CIRCLE))):
      for i from 1 to N - 1 do
        sf := sf union {[[Y[2][i], Y[1][i + 1]], 
            [Y[2][i + 1], Y[1][i + 1]]]}:
        Cross[i] := PLOT(POINTS([Y[2][i + 1], Y[1][i + 1]], 
            SYMBOL(CROSS))):
        Closed[i] := PLOT(POINTS([Y[2][i + 1], Y[1][i + 1]], 
            SYMBOL(CIRCLE))):
        Open[i] := PLOT(POINTS([Y[2][i], Y[1][i + 1]], SYMBOL(CIRCLE))):
      od:
      sf := sf union {[[Y[2][N], 0], [Y[2][N] + hi, 0]]}:
      OpenN := PLOT(POINTS([Y[2][N], 0], SYMBOL(CIRCLE))):
      # print(sf):
      sfplot := plot(sf, x = lo - 0.5 .. hi + 0.5, 
          labels = ["x", "SF"],
          labeldirections = [horizontal, horizontal]):
      plots[display]({sfplot, Cross0, Closed0, 
          seq(Cross[i], i = 1 .. N - 1), seq(Closed[i], i = 1 .. N - 1), 
          seq(Open[i], i = 1 .. N - 1), OpenN}):
    # ONLY CONSIDERING CASE WITH x -> x TRANSFORMATION
    else # formulaic sf
      sf := {[[0, 1], [lo, 1]]}:
      Cross0 := PLOT(POINTS([lo, 1], SYMBOL(CROSS))):
      Closed0 := PLOT(POINTS([lo, 1], SYMBOL(CIRCLE))):
      for i from lo by incr to hi do
        sf := sf union {[[i, op(Y[1](i + 1))], 
            [i + 1, op(Y[1](i + 1))]]}:
        Open[i] := PLOT(POINTS([i, op(Y[1](i + 1))], SYMBOL(CIRCLE))):
        Cross[i] := PLOT(POINTS([i + 1, op(Y[1](i + 1))], 
            SYMBOL(CIRCLE))):
        Closed[i] := PLOT(POINTS([i + 1, op(Y[1](i + 1))], 
            SYMBOL(CROSS))):
        # print(sf):
      od:
      sf := sf union {[[hi, 0], [hi + hi, 0]]}:
      OpenN := PLOT(POINTS([hi, 0], SYMBOL(CIRCLE))):
      # print(cdf):
      sfplot := plot(sf, x = lo - 0.5 .. hi + 0.5, 
          labels = ["x", "SF"],
          labeldirections = [horizontal, horizontal]):
      plots[display]({sfplot, Cross0, Closed0, 
          seq(Open[i], i = lo .. hi),
          seq(Cross[i], i = lo .. hi), 
          seq(Closed[i], i = lo .. hi), OpenN}):
    fi:
  elif (Y[3][2] = "HF") then
    hf := {}:
    if not(formulaic) then
      for i from 1 to N do
        hf := hf union {[[Y[2][i], 0], [Y[2][i], Y[1][i]]]}:
        Cross[i] := PLOT(POINTS([Y[2][i], Y[1][i]], SYMBOL(CROSS))):
        Circle[i] := PLOT(POINTS([Y[2][i], Y[1][i]], SYMBOL(CIRCLE))):
      od:
      hfplot := plot(hf, x = lo - 0.5 .. hi + 0.5, 
          labels = ["x", "HF"],
          labeldirections = [horizontal, horizontal]):
      plots[display]({hfplot, seq(Cross[i], i = 1 .. N), 
          seq(Circle[i], i = 1 .. N)}):
    # ONLY CONSIDERING CASE WITH x -> x TRANSFORMATION
    else # formulaic hf
      for i from lo by incr to hi do
        hf := hf union {[[i, 0], [i, op(Y[1](i))]]}:
        Cross[i] := PLOT(POINTS([i, op(Y[1](i))], SYMBOL(CROSS))):
        Circle[i] := PLOT(POINTS([i, op(Y[1](i))], SYMBOL(CIRCLE))):
      od:
      # print(hf):
      hfplot := plot(hf, x = lo - 0.5 .. hi + 0.5, 
          labels = ["x", "HF"],
          labeldirections = [horizontal, horizontal]):
      plots[display]({hfplot, seq(Cross[i], i = lo .. hi), 
          seq(Circle[i], i = lo .. hi)}):
    fi:
  elif (Y[3][2] = "CHF") then
    if not(formulaic) then
      chf := {[[0, 0], [Y[2][1], 0]]}:
      Cross0 := PLOT(POINTS([Y[2][1], 0], SYMBOL(CROSS))):
      Closed0 := PLOT(POINTS([Y[2][1], 0], SYMBOL(CIRCLE))):
      for i from 1 to N - 1 do
        chf := chf union {[[Y[2][i], Y[1][i + 1]], 
            [Y[2][i + 1], Y[1][i + 1]]]}:
        Open[i] := PLOT(POINTS([Y[2][i], evalf(Y[1][i + 1])], 
            SYMBOL(CIRCLE))):
        Cross[i] := PLOT(POINTS([Y[2][i + 1], evalf(Y[1][i + 1])], 
            SYMBOL(CROSS))):
        Closed[i] := PLOT(POINTS([Y[2][i + 1], evalf(Y[1][i + 1])], 
            SYMBOL(CIRCLE))):
      od:
      # print(chf):
      chfplot := plot(chf, x = lo - 0.5 .. hi + 0.5, 
          labels = ["x", "CHF"],
          labeldirections = [horizontal, horizontal]):
      plots[display]({chfplot, Cross0, Closed0, 
          seq(Open[i], i = 1 .. N - 1),
          seq(Cross[i], i = 1 .. N - 1), 
          seq(Closed[i], i = 1 .. N - 1)}):
    # ONLY CONSIDERING CASE WITH x -> x TRANSFORMATION
    else # formulaic chf
      chf := {[[0, 0], [lo, 0]]}:
      Cross0 := PLOT(POINTS([lo, 0], SYMBOL(CROSS))):
      Closed0 := PLOT(POINTS([lo, 0], SYMBOL(CIRCLE))):
      for i from lo by incr to hi - 1 do
        chf := chf union {[[i, op(Y[1](i + 1))], 
            [i + 1, op(Y[1](i + 1))]]}:
        Open[i] := PLOT(POINTS([i, evalf(op(Y[1](i + 1)))], 
            SYMBOL(CIRCLE))):
        Cross[i] := PLOT(POINTS([i + 1, evalf(op(Y[1](i + 1)))], 
            SYMBOL(CROSS))):
        Closed[i] := PLOT(POINTS([i + 1, evalf(op(Y[1](i + 1)))], 
            SYMBOL(CIRCLE))):
        # print(chf):
      od:
      chfplot := plot(chf, x = lo - 0.5 .. hi + 0.5, 
          labels = ["x", "CHF"],
          labeldirections = [horizontal, horizontal]):
      plots[display]({chfplot, Cross0, Closed0, 
          seq(Open[i], i = lo .. hi - 1),
          seq(Cross[i], i = lo .. hi - 1), 
          seq(Closed[i], i = lo .. hi - 1)}):
    fi:
  elif (Y[3][2] = "IDF") then
    if not(formulaic) then
      idf := {[[0, Y[1][1]], [Y[2][1], Y[1][1]]]}:
      Open0 := PLOT(POINTS([0, Y[1][1]], SYMBOL(CIRCLE))):
      for i from 1 to N - 1 do
        idf := idf union {[[Y[2][i], Y[1][i + 1]], 
            [Y[2][i + 1], Y[1][i + 1]]]}:
        Open[i] := PLOT(POINTS([Y[2][i], Y[1][i + 1]], 
            SYMBOL(CIRCLE))):
        Cross[i] := PLOT(POINTS([Y[2][i], Y[1][i]], SYMBOL(CROSS))):
        Closed[i] := PLOT(POINTS([Y[2][i], Y[1][i]], SYMBOL(CIRCLE))):
      od:
      CrossN := PLOT(POINTS([Y[2][N], Y[1][N]], SYMBOL(CROSS))):
      ClosedN := PLOT(POINTS([Y[2][N], Y[1][N]], SYMBOL(CIRCLE))):
      # print(idf):
      idfplot := plot(idf, x = 0 .. 1, labels = ["x", "IDF"],
          labeldirections = [horizontal, horizontal]):
      plots[display]({idfplot, Open0, seq(Open[i], i = 1 .. N - 1),
          seq(Cross[i], i = 1 .. N - 1), 
          seq(Closed[i], i = 1 .. N - 1)}, CrossN, ClosedN):
    # ONLY CONSIDERING CASE WITH x -> x TRANSFORMATION
    else # formulaic idf
      print(`idf plot for this case not completed yet`):
    fi:
  fi:
fi:
end:


#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: plotempcdf1.map
#
#  Procedure name: PlotEmpCDF(Sample, [low], [high])
#
#  Other APPL Procedures Called: PDF
# 
#  Date: January 7, 2000
#
#  Purpose: Plot the empirical cumulative distribution function of a
#           random sample
#
#  Arguments: Sample: A random sample; 
#             low, high (optional values): Values provided by the user 
#             indicating the left and right end values of the plot
#
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Sort the sample list
#        Example:  Sample := [1, 10, 5, 10, 5, 7, 3, 2.5];
#                  SortedSample := [1, 2.5, 3, 5, 5, 7, 10, 10]
#    3.  Construct the empirical CDF as a set of lists, where each list
#        contains either:
#        (a)  The endpoints of a given "step" of the empirical CDF, or
#        Example: [[1, 1/8], [2, 1/8]]
#        (b)  The points needed to connect the "steps" of the empirical CDF
#        Example: [[1, 0], [1, 1/8]]
#        The counter is used to determine the length of the line which
#        connects the steps in (b)
#    4.  The empirical CDF is plotted on the range low to high.  If the 
#        values low and high are not provided by the user, the default
#        value for low is the smallest sample point and the default value
#        for high is the largest sample point
#
PlotEmpCDF := proc(Sample :: list, lo, hi)
local SortedSample, n, low, high, EmpCDF, counter, i:
#
#  Check for the appropriate number of arguments
#
if ((nargs <> 1) and (nargs <> 3)) then
  print(`ERROR(PlotEmpCDF): This procedure requires 1 or 3 arguments`):
  RETURN():
fi:

SortedSample := sort(Sample):
n := nops(Sample):
if (nargs = 1) then
  low := SortedSample[1]:
  high := SortedSample[n]:
elif (nargs = 3) then
  low := lo:
  high := hi:
fi:
counter := 0:
EmpCDF := {[[low, 0], [SortedSample[1], 0]]}:
for i from 1 to n - 1 do 
  counter := counter + 1:
  if SortedSample[i] < SortedSample[i + 1] then
    EmpCDF := EmpCDF union {[[SortedSample[i], i / n], [SortedSample[i + 1],
        i / n]]} union {[[SortedSample[i], (i - counter) / n], [SortedSample
        [i], i / n]]}:
    counter := 0:
  fi:
od:
# plot(EmpCDF, x = low .. high):
counter := counter + 1:
EmpCDF := EmpCDF union {[[SortedSample[n], 1], [high, 1]]} union 
    {[[SortedSample[n], (i - counter) / n], [SortedSample[n], 1]]}:
# print(EmpCDF):
plot(EmpCDF, x = low .. high, color = blue, labels = ["x", "CDF"], labeldirections = 
    [horizontal, horizontal]): 
end:
#111111111122222222223333333333444444444455555555556666666666777777777788888  
#  Filename: plotempcif1.map
#
#  Procedure name: PlotEmpCIF(Sample, lo, hi)
#
#  Other APPL Procedures Called:
# 
#  Date: July 18
#
#  NEED TO WORK ON COMMENTS AT A LATER TIME (7/18/2000)
#
#  Purpose: Plot the empirical cumulative intensity function
#
#  Arguments: Sample: A random sample; 
#             low, high (optional values): Values provided by the user 
#             indicating the left and right end values of the plot
#
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Sort the sample list
#        Example:  Sample := [1, 10, 5, 10, 5, 7, 3, 2.5];
#                  SortedSample := [1, 2.5, 3, 5, 5, 7, 10, 10]
#    3.  Construct the empirical CDF as a set of lists, where each list
#        contains either:
#        (a)  The endpoints of a given "step" of the empirical CDF, or
#        Example: [[1, 1/8], [2, 1/8]]
#        (b)  The points needed to connect the "steps" of the empirical CDF
#        Example: [[1, 0], [1, 1/8]]
#        The counter is used to determine the length of the line which
#        connects the steps in (b)
#    4.  The empirical CDF is plotted on the range low to high.  If the 
#        values low and high are not provided by the user, the default
#        value for low is the smallest sample point and the default value
#        for high is the largest sample point
#
PlotEmpCIF := proc(Sample :: list, lo, hi)
local n, SortedSample, low, high, EmpCIF, i:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 1 and nargs <> 3) then
  print(`ERROR(PlotEmpCIF): This procedure requires 1 or 3 argument`):
  RETURN():
fi:
n := nops(Sample):
SortedSample := sort(Sample):
if (nargs = 1) then
  low := SortedSample[1]:
  high := SortedSample[n]:
elif (nargs = 3) then
  low := lo:
  high := hi:
fi:
EmpCIF := {[[low, 0], [SortedSample[1], 0]]} union {[[SortedSample[1], 0],
    [SortedSample[1], 1]]}:
for i from 1 to n - 1 do 
  if SortedSample[i] < SortedSample[i + 1] then
    EmpCIF := EmpCIF union {[[SortedSample[i], i], [SortedSample[i + 1],
        i]]} union {[[SortedSample[i + 1], i], [SortedSample
        [i + 1], i + 1]]}:
  fi:
od:
EmpCIF := EmpCIF union {[[SortedSample[n], n], [high, n]]}:

# union {[[SortedSample[n], (i - counter) / n], [SortedSample[n], 1]]}:
# print(EmpCDF):
plot(EmpCIF, x = low .. high, color = blue, labels = ["x", "CIF"], labeldirections = 
    [horizontal, horizontal]): 
end:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: plotempsf1.map
#
#  Procedure name: PlotEmpSF(Sample, Censor)
#
#  Other APPL Procedures Called:
# 
#  Date: June 28, 2000
#
#  NEED TO WORK ON COMMENTS AT A LATER TIME (6/28/2000)
#
#  Purpose: Plot the empirical survivor function of a random sample
#
#  Arguments: Sample: A random sample; 
#             Censor: Right-censoring vector
#
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Sort the sample list
#        Example:  Sample := [1, 10, 5, 10, 5, 7, 3, 2.5];
#                  SortedSample := [1, 2.5, 3, 5, 5, 7, 10, 10]
#    3.  Construct the empirical SF as a set of lists, where each list
#        contains either:
#        (a)  The endpoints of a given "step" of the empirical CDF, or
#        Example: [[1, 1/8], [2, 1/8]]
#        (b)  The points needed to connect the "steps" of the empirical
#              CDF
#        Example: [[1, 0], [1, 1/8]]
#        The counter is used to determine the length of the line which
#        connects the steps in (b)
#    4.  The empirical SF is plotted on the range low to high.  If the 
#        values low and high are not provided by the user, the default
#        value for low is the smallest sample point and the default
#        value
#        for high is the largest sample point
#
PlotEmpSF := proc(Sample :: list, Censor :: list)
local m, y, d, n, RigCensor, counter, RigSample, NumItems, i, Size,
    KMSurvFctn, Prev:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 2) then
  print(`ERROR(PlotEmpSF): This procedure requires 2 arguments`):
  RETURN():
fi:

m := nops(Sample):
y := []:
d := []:
n := [m]:
#
#  Construct the list y
#
for i from 1 to m do
  if (Censor[i] = 1) and not(member(Sample[i], y)) then
    y := [op(y), Sample[i]]:
  fi:
od:
#
#  Construct the list d
#
RigCensor := [op(Censor), 0]:
RigSample := [op(Sample), Sample[m]]:
counter := 1:
for i from 1 to m do
  if RigCensor[i] = 1 then
    if RigSample[i] = RigSample[i + 1] and RigCensor[i + 1] = 1 then
      counter := counter + 1:
    elif RigSample[i] <> RigSample[i + 1] or RigCensor[i + 1] = 0 then 
      d := [op(d), counter]:
      counter := 1:
    fi: 
  fi:
od:
#
#  Construct the list n
#
NumItems := m:
for i from 1 to m do
  if RigSample[i] = RigSample[i + 1] or RigCensor[i + 1] = 0 then
    NumItems := NumItems - 1:
  else
    NumItems := NumItems - 1:
    n := [op(n), NumItems]:
  fi:
od:
# print(`y is`, y):
# print(`d is`, d):
# print(`n is`, n):

Size := nops(y):
KMSurvFctn := {[[0, 1], [y[1], 1]]} union {[[y[1], 1 - (d[1] / n[1])], 
    [y[1], 1]]}:
Prev := 1:
for i from 1 to Size - 1 do 
  Prev := Prev * (1 - (d[i] / n[i])):
  KMSurvFctn := KMSurvFctn union {[[y[i], Prev], [y[i + 1], Prev]]} union 
   {[[y[i + 1], Prev], [y[i + 1], Prev * (1 - (d[i + 1] / n[i + 1]))]]}:
od:
# print(KMSurvFctn):
plot(KMSurvFctn, 0 .. y[Size], 0 .. 1, color = blue, labels = ["t", "SF"]): 
end:
#111111111122222222223333333333444444444455555555556666666666777777777788888  
#  Filename: plotempvsfittedcdf1.map
#
#  Procedure name: PlotEmpVsFittedCDF(X, Sample, Parameters, [low], [high])
#
#  Other APPL Procedures Called: CDF, PlotDist, PlotEmpCDF
#
#  Date: January 9, 2000
#
#  Purpose: Plot the random variable X's empirical CDF and fitted CDF
#           together
#
#  Arguments: X: Random variable; 
#             Sample: List of sample data points
#             Parameters: List of parameters set equatl to their estimated
#               values to be substituted into the CDF of X
#  
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Check that the RV X is in a list-of-lists format
#    3.  Check that X is in its PDF, CDF, SF, HF, CHF, or IDF format
#    4.  Define EmpCDFPlot as the plot of the empirical CDF
#    5.  Define FittedCDFPlot as the plot of the fitted CDF
#    6.  Plot the empirical CDF and fitted CDF together
#
PlotEmpVsFittedCDF := proc(X :: list(list), Sample :: list, Parameters ::
    list, low :: numeric, high :: numeric)
local NumLists, n, SortedSample, lo, hi, EmpCDFPlot, FX, SubList1,
    SubList1Expr, NewSubList1, i, FittedCDFPlot:
#
#  Check for the appropriate number of arguments
#
if ((nargs <> 3) and (nargs <> 5)) then
  print(`ERROR(PlotEmpVsFittedCDF): This procedure 3 or 5 arguments`):
  RETURN():
fi:
#
#  Check that the RV X is in a list-of-lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(PlotEmpVsFittedCDF): The RV X must be in a`): 
  print(`list of 3 lists format`):
  RETURN(): 
fi:
#
#  Check that X is in its PDF, CDF, SF, HF, CHF, or IDF format
#
if not((X[3][2] = "PDF") or
       (X[3][2] = "CDF") or
       (X[3][2] = "SF") or
       (X[3][2] = "HF") or
       (X[3][2] = "CHF") or
       (X[3][2] = "IDF")) then
  print(`ERROR(PlotEmpVsFittedCDF): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  RETURN():
fi:
#
#  Set the lower and upper plot range
#
n := nops(Sample):
SortedSample := sort(Sample):
if (nargs = 5) then
  lo := low:
  hi := high:
else
  lo := SortedSample[1]:
  hi := SortedSample[n]:
fi:
#
#  Define EmpCDFPlot as the plot of the empirical CDF
#
# print(PlotEmpCDF(SortedSample, lo, hi)):
EmpCDFPlot := PlotEmpCDF(SortedSample, lo, hi):

#
#  Define FittedCDFPlot as the plot of the fitted CDF
#
FX := CDF(X):
SubList1 := FX[1]:
SubList1Expr := unapply(SubList1(x))(x):
FX[1] := []:
# print(nops(SubList1)):
for i from 1 to nops(SubList1) do
  FX[1] := [op(FX[1]), unapply(subs({op(Parameters)}, SubList1Expr[i]), x)]:
   print(`FX[1] is`, FX[1]):
od: 
#if hasfun(op(unapply(FX[1](x))(x)), int) then
#  print(`ERROR(PlotEmpVsFittedCDF): CDF of X contains an integral that #can't`): 
#  print(`be simplified.  Plot cannot be made`):
#  RETURN():
#fi:
# print(PlotDist(FX, lo, hi)): 
FittedCDFPlot := PlotDist(FX, lo, hi): 

#
#  Plot the empirical CDF and fitted CDF together, [] used so that
#  labels from EmpCDFPlot used 
#
plots[display]([EmpCDFPlot, FittedCDFPlot], scaling = unconstrained):
end:


#111111111122222222223333333333444444444455555555556666666666777777777788888  
#  Filename: plotempvsfittedcif1.map
#
#  Procedure name: PlotEmpVsFittedCIF(X, Sample, Parameters, low, high)
#
#  Other APPL Procedures Called:
# 
#  Date: July 18
#
#  NEED TO WORK ON COMMENTS AT A LATER TIME (7/18/2000)
#
#  Purpose: Plot the empirical cumulative distribution function of a random
#           sample
#
#  Arguments: Sample: A random sample; 
#             low, high (optional values): Values provided by the user 
#             indicating the left and right end values of the plot
#
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Sort the sample list
#        Example:  Sample := [1, 10, 5, 10, 5, 7, 3, 2.5];
#                  SortedSample := [1, 2.5, 3, 5, 5, 7, 10, 10]
#    3.  Construct the empirical CDF as a set of lists, where each list
#        contains either:
#        (a)  The endpoints of a given "step" of the empirical CDF, or
#        Example: [[1, 1/8], [2, 1/8]]
#        (b)  The points needed to connect the "steps" of the empirical CDF
#        Example: [[1, 0], [1, 1/8]]
#        The counter is used to determine the length of the line which
#        connects the steps in (b)
#    4.  The empirical CDF is plotted on the range low to high.  If the 
#        values low and high are not provided by the user, the default
#        value for low is the smallest sample point and the default value
#        for high is the largest sample point
#
PlotEmpVsFittedCIF := proc(X, Sample :: list, Parameters, 
    lo, hi)
local ChX, SubList1, SubList1Expr, i, FittedSFPlot, CIFPlot, FittedCHFPlot:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 5) then
  print(`ERROR(PlotEmpVsFittedCIF): This procedure requires 5 args`):
  RETURN():
fi:

#
#  Define CIFPlot as the plot of the empirical cumulative intensity function
#
CIFPlot := PlotEmpCIF(Sample, lo, hi):
# print(PlotEmpCIF(Sample, lo, hi)):

#
#  Define FittedCHFPlot as the plot of the fitted CHF
#
ChX := CHF(X):
SubList1 := ChX[1]:
SubList1Expr := unapply(SubList1(x))(x):
ChX[1] := []:
# print(nops(SubList1)):
for i from 1 to nops(SubList1) do
  ChX[1] := [op(ChX[1]), unapply(subs({op(Parameters)}, SubList1Expr[i]), x)]:
  # print(`ChX[1] is`, ChX[1]):
od: 
# print(PlotDist(ChX, lo, hi)): 

FittedCHFPlot := PlotDist(ChX, lo, hi): 

#
#  Plot the empirical SF and fitted SF together
#
plots[display]([CIFPlot, FittedCHFPlot], scaling = unconstrained):
end:

#1111111111222222222233333333334444444444555555555566666666667777777777#  
#  Filename: plotempvsfittedsf1.map
#
#  Procedure name: PlotEmpVsFittedSF(X, Sample, Parameters, Censor)
#
#  Other APPL Procedures Called:
# 
#  Date: June 28, 2000
#
#  NEED TO WORK ON COMMENTS AT A LATER TIME (6/28/2000)
#
#  Purpose: Plot the empirical survivor function of a random
#           sample
#
#  Arguments: Sample: A random sample; 
#             low, high (optional values): Values provided by the user 
#             indicating the left and right end values of the plot
#
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Sort the sample list
#        Example:  Sample := [1, 10, 5, 10, 5, 7, 3, 2.5];
#                  SortedSample := [1, 2.5, 3, 5, 5, 7, 10, 10]
#    3.  Construct the empirical CDF as a set of lists, where each list
#        contains either:
#        (a)  The endpoints of a given "step" of the empirical CDF, or
#        Example: [[1, 1/8], [2, 1/8]]
#        (b)  The points needed to connect the "steps" of the empirical
# CDF
#        Example: [[1, 0], [1, 1/8]]
#        The counter is used to determine the length of the line which
#        connects the steps in (b)
#    4.  The empirical CDF is plotted on the range low to high.  If the 
#        values low and high are not provided by the user, the default
#        value for low is the smallest sample point and the default
# value
#        for high is the largest sample point
#
PlotEmpVsFittedSF := proc(X, Sample :: list, Parameters, 
    Censor :: list, lo, hi)
local EmpSFPlot, SX, SubList1, SubList1Expr, i, FittedSFPlot:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 6) then
  print(`ERROR(PlotKaplanMeierVsFittedSF): This procedure requires`):
  print(`6 arguments`):
  RETURN():
fi:

#
#  Define KMFPlot as the plot of the Kaplan Meier SF
#
EmpSFPlot := PlotEmpSF(Sample, Censor):

#
#  Define FittedSFPlot as the plot of the fitted SF
#
SX := SF(X):
SubList1 := SX[1]:
SubList1Expr := unapply(SubList1(x))(x):
SX[1] := []:
# print(nops(SubList1)):
for i from 1 to nops(SubList1) do
  SX[1] := [op(SX[1]), unapply(subs({op(Parameters)}, 
      SubList1Expr[i]), x)]:
  # print(`SX[1] is`, SX[1]):
od: 
FittedSFPlot := PlotDist(SX, lo, hi): 

#
#  Plot the empirical SF and fitted SF together
#
plots[display]([EmpSFPlot, FittedSFPlot], scaling = unconstrained):
end:

#1111111111222222222233333333334444444444555555555566666666667777777777  
#  Filename: ppplot1.map
#
#  Procedure name: PPPlot(X, Sample, Parameters)
#
#  Other APPL Procedures Called:
#
#  Date: June 26, 2000
#
#  Purpose: Plots the model probability F^hat(X) versus the sample 
#           probability 
#
#  Arguments: X: Random variable
#             Sample: List of sample data points
#             Parameters
#  
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Check that the RV X is in a list-of-lists format
#    3.  Check that X is in its PDF, CDF, SF, HF, CHF, or IDF format
#
PPPlot := proc(X :: list(list), Sample :: list, Parameters)
local NumLists, n, p, SortedSample, FX, SubList1, SubList1Expr, Model, 
    FittedPoints, i, DataPoints:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 3) then
  print(`ERROR(PPPlot): This procedure requires 3 arguments`):
  RETURN():
fi:
#
#  Check that the RV X is in a list-of-lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(PPPlot): The RV X must be in a`): 
  print(`list of 3 lists format`):
  RETURN(): 
fi:
#
#  Check that X is in its PDF, CDF, SF, HF, CHF, or IDF format
#
if not((X[3][2] = "PDF") or
       (X[3][2] = "CDF") or
       (X[3][2] = "SF") or
       (X[3][2] = "HF") or
       (X[3][2] = "CHF") or
       (X[3][2] = "IDF")) then
  print(`ERROR(PPPlot): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  RETURN():
fi:

with(plots):
n := nops(Sample):
p := [seq((i - (1 / 2)) / n, i = 1 .. n)]:
SortedSample := sort(Sample):
# print(`p is`, p):

FX := CDF(X):
SubList1 := FX[1]:
SubList1Expr := op(unapply(SubList1(x))(x)):
Model := subs({op(Parameters)}, SubList1Expr):
FittedPoints := []:
for i from 1 to n do
  FittedPoints := [op(FittedPoints), subs(x = SortedSample[i], Model)]:
od:
# print(FittedPoints):

DataPoints := []:
for i from 1 to n do
  DataPoints := [op(DataPoints), [p[i], FittedPoints[i]]]:
od:
# print(DataPoints):
pointplot(DataPoints, view = [0 .. 1, 0 .. 1], labels = ["sample",
    " model"], scaling = constrained, title = "P-P Plot"):

end:


#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: probs1.map
#
#  Procedure names:  BirthdayProb
#                    CrapsProb
#                    HatCheckGirlProb
#                    PointsProb
#
#  Other APPL Procedures Called: None
#
#  Date:  
#
#  Purpose:  
#
#  Arguments:  The parameters of the distribution of the random
#              variable
#
#  Algorithm: (NEED TO REDO FOR PROBABILITIES)
#    1.  Check for the appropriate number of arguments
#    2.  Check parameter space when parameters are numeric
#    3.  Check to see that the parameters are finite
#    4.  Make assumptions about any symbolic parameters
#    6.  Return the list of lists
# 
#  Note:  Could define a type in startup about p being between 0 and 1
#

#
#  Birthday Probability
#
BirthdayProb := proc(n)
print(`Sorry ... this procedure is not completed`):
return:
if (nargs <> 1) then
  print(`ERROR(BirthdayProb): This procedure requires 1 argument`):
  return:
fi:
end:

#
#  Craps Probability
#
CrapsProb := proc()
print(`Sorry ... this procedure is not completed`):
return:
end:

#
#  Hat Check Girl Probability
#
HatCheckGirlProb := proc(n, k)
print(`Sorry ... this procedure is not completed`):
return:
end:

#
#  Points Probability
#
PointsProb := proc()
print(`Sorry ... this procedure is not completed`):
return:
end:

#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: prodiid1.map
#  
#  Procedure Name: ProductIID(X, n)
#
#  Other APPL Procedures Called: PDFRV, Product
#
#  Date: June 1, 1999
#
#  Purpose: 
#
#  Arguments: X: Continuous random variable
#
#  Algorithm:
#
ProductIID := proc(X, n) 
local i, fprod, fX:
if (n < 2) then
  print(`ERROR(ProductIID): n must be > 1`):
  RETURN():
fi:

fX := PDF(X):
fprod := Product(fX, fX):
for i from 3 to n do
  # print(here1, i):
  fprod := Product(fX, fprod):
  # print(here2, i, fprod):
od:
RETURN(fprod):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: product9.map
#  calls productcontinuous or product discrete
#
#  Procedure Name: Product(X, Y)
#
#  Other APPL Procedures Called: ProductContinuous, ProductDiscrete
#
#  Date: January 7, 2001
#
#  Purpose: 
#
#  Arguments: X, Y
#
#  Algorithm:
Product := proc(X :: list(list), Y :: list(list), Z :: list(list)) 
local Prod1, Prod2, i, NumLists, fX, fY, fZ:
#
#  6/23/2007: ADDED these next three lines for an example in the APPL
#  Monongraph in which we wanted to find the product of 3 different 
#  random variables with the Product procedure
# 
if (nargs = 3) then
  Prod1 := Product(X, Y):
  Prod2 := Product(Prod1, Z):
  return(Prod2):
fi:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 2) then
  print(`ERROR(Product): This procedure requires 2 arguments:`):
  print(`A random variable X, and a random variable Y`):
  return:
fi:
#
#  Check that the first RV is a list of 3 sublists
#
for i from 1 to nargs do
  NumLists := nops(args[i]):
  if (NumLists <> 3) then
    print(`ERROR(Product): The RV must be a list of 3 lists`):
    return:
  fi:
od:
#
#  Convert the RV to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
  fX := X:
elif member(X[3][2], {"CDF", "SF", "HF", "CHF", "IDF"}) then
  fX := PDF(X):
else
  print(`ERROR(Product): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
#
#  Convert Y to PDF form if not already in that form
#
if (Y[3][2] = "PDF") then
  fY := Y:
elif member(Y[3][2], {"CDF", "SF", "HF", "CHF", "IDF"}) then
  fY := PDF(Y):
else
  print(`ERROR(Product): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:

if (X[3][1] = "Continuous") then
  fZ := ProductContinuous(fX, fY):
elif (X[3][1] = "Discrete") then
  fZ := ProductDiscrete(fX, fY):
else
  print(`ERROR(Product): This procedure requires a`):
  print(`Continuous or Discrete random variable`):
  return:
fi:
return(fZ):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: productcontinuous1.map
#  
#  Procedure Name: ProductContinuous(X, Y)
#
#  Other APPL Procedures Called: PDF, ReduceList, CleanUp
#
#  Date: August 8, 2000
#
#  Revised: March 11, 2008
#
#  Purpose: 
#
#  Arguments: X, Y: Continuous random variables
#
#  Algorithm:
#
ProductContinuous := proc(X, Y) 
local fXc, fYc, f, XStar, n, g, YStar, m, VStarSet, VStar, Xtemp, ftemp,
    temp1, temp2, i, i3,  zeropsn, Ytemp, gtemp, j, nn, v, h, a, b, c, d, f1,
    f2, f3, f4, ii, hh, fV, axc, axd, bxc, bxd, minVdist, floaterror, used:

fXc := X:
fYc := Y:



f := fXc[1]:
XStar := fXc[2]:
n := nops(XStar):

g := fYc[1]:
YStar := fYc[2]:
m := nops(YStar):

#
#see if we have positive X and Y
#
#if(fXc[2][1] >= 0 and fYc[2][1] >= 0) then
#  assume(v > 0);
#elif(fXc[2][n] <= 0 and fYc[2][m] <= 0) then
#  assume(v > 0);
#else
#  assume(v, real);
#fi;



VStarSet := {}:
VStar := []:
#
#  Insert 0 into XStar (if necessary)
#
Xtemp := []:  
ftemp := []:
temp1 := XStar[1]:
temp2 := XStar[n]:
if (evalf(temp1) < 0 and evalf(temp2) > 0 and not(member(0, XStar)))
    then
  for i from 1 to n do
    temp1 := XStar[i]:
    temp2 := XStar[i + 1]:
    if (evalf(temp1) < 0 and evalf(temp2) > 0) then
      zeropsn := i + 1:
      break:
    fi: 
  od:
  for i from 1 to (zeropsn - 1) do  
    Xtemp := [op(Xtemp), XStar[i]]:
    ftemp := [op(ftemp), f[i]]:
  od:
  Xtemp := [op(Xtemp), 0]:
  ftemp := [op(ftemp), f[zeropsn - 1]]:
  for i from (zeropsn + 1) to (n + 1) do 
    Xtemp := [op(Xtemp), XStar[i - 1]]:  
  od:
  for i from (zeropsn + 1) to (n) do 
    ftemp := [op(ftemp), f[i - 1]]: 
  od:
  n := n + 1: 
  XStar := Xtemp:
  f := ftemp: 
fi:
# print(`XStar is`, XStar):

#
#  Insert 0 into YStar (if necessary)
#
Ytemp := []:  
gtemp := []:
temp1 := YStar[1]:
temp2 := YStar[m]:
if (evalf(temp1) < 0 and evalf(temp2) > 0 and not(member(0, YStar)))
    then
  for i from 1 to m do
    temp1 := YStar[i]:
    temp2 := YStar[i + 1]:
    if (evalf(temp1) < 0 and evalf(temp2) > 0) then
      zeropsn:= i + 1:
      break:
    fi: 
  od:
  for i from 1 to (zeropsn - 1) do  
    Ytemp := [op(Ytemp), YStar[i]]:
    gtemp := [op(gtemp), g[i]]:
  od:
  Ytemp := [op(Ytemp), 0]:
  gtemp := [op(gtemp), g[zeropsn - 1]]:
  for i from zeropsn + 1 to (m + 1) do 
    Ytemp := [op(Ytemp), YStar[i - 1]]:  
  od:
  for i from zeropsn + 1 to (m) do 
    gtemp := [op(gtemp), g[i - 1]]: 
  od:
  m := m + 1: 
  YStar := Ytemp:
  g := gtemp: 
fi:
# print(`YStar is`, YStar):

#
#  Set up the support list VStar
#
for i from 1 to n do:
  for j from 1 to m do:
    VStarSet := VStarSet union {limit(limit(b, b = XStar[i]) * a, a =
        YStar[j])}:
  od: 
od:
#
#  Convert VStar from a set to a list.  Then order VStar and remove
#  redundancies
#
VStarSet := simplify(VStarSet);
VStar := sort([op(VStarSet)], (x, y) -> evalb(evalf(x) < evalf(y))):
VStar:= ReduceList(VStar):  
nn := nops(VStar):
 # print(`VStar is`, VStar,`VstarSet is`,VStarSet):

#
#  Set up the proper assumption about v so that integration can be done 
#  properly
#
if(evalf(limit(x, x = VStar[1])) >= 0) then
  # assume(v > 0):
elif(evalf(limit(x, x = VStar[nn])) <= 0) then
  # assume(v < 0):
else
  # assume(v, real):
fi:
# about(v):

#
#  Find the min distance in Vstar to create and even smaller float point error
#  adjustment term 'floaterror'
#

minVdist := abs(VStar[1] - VStar[2]);
for i3 from 2 to (nn - 1) do
  if (evalf(abs(VStar[i3+1]-VStar[i3])) < evalf(minVdist)) then
     minVdist := evalf(abs(VStar[i3 +1]-VStar[i3]));
  fi;
od;
if(minVdist=0) then
  floaterror := 1/1000000
elif(evalf(minVdist/100000) < infinity) then
  floaterror := evalf(minVdist/100000);
else
  floaterror := 1/1000000;
fi;

 # print("minVdist and floaterror", evalf(minVdist), floaterror);


#
#  Initialize every function in h to be zero
#
h := array(1 .. (nn - 1), [seq(0, i = 1 .. nn - 1)]):

#
#  Integration for each segment of X times each segment of Y
#
for i from 1 to n - 1 do
  for j from 1 to m - 1 do
    a := XStar[i]:
    b := XStar[i + 1]:
    c := YStar[j]:
    d := YStar[j + 1]:
    axc := simplify(a * c);
    axd := simplify(a * d);
    bxc := simplify(b * c);
    bxd := simplify(b * d);

#
#  The two segments transform into the 1st Quadrant
#
    if (evalf(a)  + floaterror >= 0 and evalf(c)  + floaterror >= 0) then
       # print(`in first quadrant abcd`,a,b,c,d);
      assume(vv > 0);
      # print(f[i](x)):
      # print(g[j](v / x)):
      # print(f[i](x) * g[j](v / x) / x):
      # print(f1): # print(evalf(a)): # print(evalf(b)): 
      # print(Int(f[i](x) * g[j](v / x) / x, x = a .. b)):
      f1 := int(f[i](x) * g[j](vv / x) / x, x = a .. b):
      f1 := unapply(f1, vv);
      f1 := f1(v);
      if (evalf(d) < infinity) then 
        # print(here1);
        f2 := int(f[i](x) * g[j](vv / x) / x, x = (vv / d) .. b):
        f2 := unapply(f2, vv);
        f2 := f2(v);
      fi:
      if (evalf(c) > 0) then 
        # print(here2);
        f3 := int(f[i](x) * g[j](vv / x) / x, x = a .. (vv / c)):
        f3 := unapply(f3, vv);
        f3 := f3(v);
      fi:
      if (evalf(c) > 0 and evalf(d) < infinity and  
          evalf(axd) < evalf(bxc)) then
        # print(here3);
        f4 := int(f[i](x) * g[j](vv / x) / x, x = (vv / d) .. (vv / c)):
        f4 := unapply(f4, vv);
        f4 := f4(v);
      fi:
      # print(f1, f2, f3, f4):

#
#  1st Quadrant, Scenario A
#
      if (evalf(c) = 0 and is(d, infinity)) then
         # print(ScenarioA):
        for ii from 1 to (nn - 1) do
          temp1 := VStar[ii]:
          temp2 := VStar[ii + 1]:
          if (evalf(temp1)  + floaterror >= 0) then
            h[ii] := h[ii] + f1: 
          fi: 
        od:
# 
#  1st Quadrant, Scenario B 
#
      elif (evalf(c) = 0 and evalf(d) < infinity) then
         # print(ScenarioB):
        for ii from 1 to (nn - 1) do
          temp1 := VStar[ii]:
          temp2 := VStar[ii + 1]:
          if (evalf(temp1)  + floaterror >= 0 and evalf(temp2) <= floaterror +  evalf(axd))
              then
            h[ii] := h[ii] + f1: 
          #  print(usedf1);
          fi:
          if (evalf(temp1)  + floaterror >= evalf(axd) and evalf(temp2) <= floaterror + 
              evalf(bxd)) then
            h[ii] := h[ii] + f2: 
          #  print(usedf2);
          fi: 
        od:
#
#  1st Quadrant, Scenario C 
#
      elif (evalf(c) > 0 and is(d, infinity)) then
         # print(ScenarioC):
        for ii from 1 to (nn - 1) do:
          temp1 := VStar[ii]:
          temp2 := VStar[ii + 1]:
          if (evalf(temp1)  + floaterror >= evalf(bxc) and 
              evalf(temp2) <= infinity) then
            h[ii] := h[ii] + f1: 
          fi:
          if (evalf(temp1)  + floaterror >= evalf(axc) and 
              evalf(temp2) <= floaterror + evalf(bxc))
              then
            h[ii] := h[ii] + f3: 
          fi: 
        od:
#
#  1st Quadrant, Scenario D 
#
      elif (evalf(c) > 0 and evalf(d) < infinity) then
          # print(ScenarioD, "print ad bc and evalfh of each",axd, bxc, evalf(axd), evalf(bxc)):
#  Scenario D, Case 1
        if (evalf(axd) < evalf(bxc)) then
           # print(Case1): 
          for ii from 1 to (nn - 1) do
            used:=0;
            temp1 := VStar[ii]:
            temp2 := VStar[ii + 1]:
            if (evalf(temp1)  + floaterror >= evalf(axc) and evalf(temp2) <= floaterror +
                evalf(axd)) then
              h[ii] := h[ii] + f3: used:=1; 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(axd) and evalf(temp2) <= floaterror +
                evalf(bxc)) then
              h[ii] := h[ii] + f4: used:=2;
            fi:
            if (evalf(temp1)  + floaterror >= evalf(bxc) and evalf(temp2) <= floaterror +
                evalf(bxd)) then  
              h[ii] := h[ii] + f2: used:=3;
            fi: 
             # print(wascase1used, used);
          od:
#  Scenario D, Case 2
        elif (evalf(axd) = evalf(bxc)) then
            # print(Case2,floaterror):
          for ii from 1 to (nn - 1) do 
            used:=0;
            temp1 := VStar[ii]:
            temp2 := VStar[ii + 1]:
            # print("comparing case1 v1>=ac and v2<=ad", evalf(temp1)+floaterror, evalf(axc), evalf(temp2), evalf(axd)+floaterror);
            if (evalf(temp1)  + floaterror >= evalf(axc) and evalf(temp2) <= floaterror +
                evalf(axd)) then
              h[ii] := h[ii] + f3: used:=1;
            fi:
            # print("comparing case2 v1>=bc and v2<=bd", evalf(temp1),evalf(temp1+floaterror), evalf(bxc), evalf(temp2), evalf(bxd)+floaterror);
            if (evalf(temp1)  + floaterror >= evalf(bxc) and evalf(temp2) <= floaterror +
                evalf(bxd)) then
              h[ii] := h[ii] + f2: used:=2;
            fi: 
             # print(wascase2used, used);
          od: 
#  Scenario D, Case 3 
        elif (evalf(axd) > evalf(bxc)) then
            # print(Case3):
          for ii from 1 to (nn - 1) do
            used:=0;
            temp1 := VStar[ii]:
            temp2 := VStar[ii + 1]:
            # print("temp1 2 and evalf",temp1, temp2, evalf(temp1), evalf(temp2));
            # print("evalfac bc",evalf(axc),evalf(bxc));
            if (evalf(temp1)  + floaterror >= evalf(axc) and evalf(temp2) <= floaterror +
                evalf(bxc)) then
              h[ii] := h[ii] + f3: used:=1;
            fi:
            if (evalf(temp1)  + floaterror >= evalf(bxc) and evalf(temp2) <= floaterror +
                evalf(axd)) then
              h[ii] := h[ii] + f1: used:=2;
            fi:
            if (evalf(temp1)  + floaterror >= evalf(axd) and evalf(temp2) <= floaterror +
                evalf(bxd)) then
              h[ii] := h[ii] + f2: used:=3;
            fi: 
             # print(wascase3used, used);
          od: 
        fi: 
      fi:
     
#
#  The two segments transform into the 2nd Quadrant
#
    elif (evalf(a) < 0 and evalf(c) < 0) then
      assume(vv > 0);
      # print(QuadTwo):
      f1 := -int(f[i](x) * g[j](vv / x) /x, x = a .. b):
      f1 := unapply(f1, vv);
      f1 := f1(v);
      if (evalf(d) < 0) then 
        f2 := -int(f[i](x) * g[j](vv / x) /x, x = (vv / d) .. b):
        f2 := unapply(f2, vv);
        f2 := f2(v);
      fi:
      if (evalf(c) > -infinity) then 
        f3 := - int(f[i](x) * g[j](vv / x) /x, x = a .. (vv / c)):
        f3 := unapply(f3, vv);
        f3 := f3(v);
      fi:
      if (evalf(c) > -infinity  and evalf(d) < 0 and
          evalf(axd)  > evalf(bxc)) then 
        f4 := -int(f[i](x) * g[j](vv / x) /x, x = (vv / d) .. (vv / c)):
        f4 := unapply(f4, vv);
        f4 := f4(v);
      fi:

#
#  2nd Quadrant, Scenario A
# 
      if (is(c, infinity) and evalf(d) = 0) then
        # print(ScenarioA):
        for ii from 1 to (nn - 1) do
          temp1 := VStar[ii]:
          temp2 := VStar[ii + 1]:
          if (evalf(temp1)  + floaterror >= 0) then
            h[ii] := h[ii] + f1: 
          fi: 
        od: 
#
#  2nd Quadrant, Scenario B 
#
      elif (is(c, infinity)and evalf(d) < 0) then
        # print(ScenarioB):
        for ii from 1 to (nn - 1) do
          temp1 := VStar[ii]:
          temp2 := VStar[ii + 1]:
          if (evalf(temp1)  + floaterror >= evalf(axd) and evalf(temp2) <= floaterror +
              infinity) then
            h[ii] := h[ii] + f1: 
          fi:
          if (evalf(temp1)  + floaterror >= evalf(bxd) and evalf(temp2) <= floaterror + 
              evalf(axd)) then
            h[ii] := h[ii] + f2: 
          fi: 
        od: 
#
#  2nd Quadrant, Scenario C 
#
      elif (evalf(c) > -infinity and evalf(d) = 0) then
        # print(ScenarioC):
        for ii from 1 to (nn - 1) do
          temp1 := VStar[ii]:
          temp2 := VStar[ii + 1]:
          if (evalf(temp1)  + floaterror >= 0 and evalf(temp2) <= floaterror + evalf(bxc))
              then
            h[ii] := h[ii] + f1: 
          fi:
          if (evalf(temp1)  + floaterror >= evalf(bxc) and evalf(temp2) <= floaterror + 
              evalf(axc)) then
            h[ii] := h[ii] + f3: 
          fi: 
        od:
#
#  2nd Quadrant, Scenario D 
#
      elif (evalf(c) > -infinity and evalf(d) < 0) then
        # print(ScenarioD):
#  Scenario D, Case 1 
        if (evalf(axd) > evalf(bxc)) then
          # print(Case1):
          for ii from 1 to (nn - 1) do
            temp1 := VStar[ii]:
            temp2 := VStar[ii + 1]:
            if (evalf(temp1)  + floaterror >= evalf(axd) and evalf(temp2) <= floaterror +
                evalf(axc)) then
              h[ii] := h[ii] + f3:  
            fi:
            if (evalf(temp1)  + floaterror >= evalf(bxc) and evalf(temp2) <= floaterror +
                evalf(axd)) then
              h[ii] := h[ii] + f4: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(bxd) and evalf(temp2) <= floaterror +
                evalf(bxc)) then
              h[ii] := h[ii] + f2: 
            fi: 
          od:
#  Scenario D, Case 2
        elif (evalf(axd) = evalf(bxc)) then
          # print(Case2):
          for ii from 1 to (nn - 1) do
            temp1 := VStar[ii]:
            temp2 := VStar[ii + 1]:
            if (evalf(temp1)  + floaterror >= evalf(axd) and evalf(temp2) <= floaterror + 
                evalf(axc)) then
              h[ii] := h[ii] + f3: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(bxd) and evalf(temp2) <= floaterror +
                evalf(bxc)) then
              h[ii] := h[ii] + f2: 
            fi: 
          od:
#  Scenario D, Case 3
        elif (evalf(axd) < evalf(bxc)) then
          # print(Case3):
          for ii from 1 to (nn - 1) do
            temp1 := VStar[ii]:
            temp2 := VStar[ii + 1]:
            if (evalf(temp1)  + floaterror >= evalf(bxc) and evalf(temp2) <= floaterror + 
                evalf(axc)) then
              h[ii] := h[ii] + f3: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(axd) and evalf(temp2) <= floaterror +
                evalf(bxc)) then
              h[ii] := h[ii] + f1: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(bxd) and evalf(temp2) <= floaterror +
                evalf(axd)) then
              h[ii] := h[ii] + f2:  
            fi: 
          od: 
        fi: 
      fi:
    
#
#  The two segments transform into the 3rd Quadrant
#
    elif (evalf(a) < 0 and evalf(c)  + floaterror >= 0) then
      assume(vv < 0);
      # print(QuadThree):
      f1 := -int(f[i](x) * g[j](vv / x) / x, x = a .. b):
      f1 := unapply(f1, vv);
      f1 := f1(v);
      #print(hereisf1now,f1);
      if (evalf(d) < infinity) then 
        f2 := -int(f[i](x) * g[j](vv / x) / x, x = a .. (vv / d)): 
        #print(hereisf2, f2);
        f2 := unapply(f2, vv);
        f2 := f2(v);
        #print(hereisf2now,f2);
      fi:
      if (evalf(c) > 0) then 
        f3 := -int(f[i](x) * g[j](vv / x) / x, x = (vv / c) .. b): 
        f3 := unapply(f3, vv);
        f3 := f3(v);

      fi:
      if (evalf(c) > 0 and evalf(d) < infinity and 
          evalf(bxd)  > evalf(axc)) then 
        f4 := -int(f[i](x) * g[j](vv / x) / x, x = (vv / c) .. (vv / d)): 
        f4 := unapply(f4, vv);
        f4 := f4(v);

      fi:

#
# 3rd Quadrant, Scenario A 
#
      if (evalf(c) = 0 and is(d, infinity)) then
        # print(ScenarioA):
        for ii from 1 to (nn - 1) do
          temp1 := VStar[ii]:
          temp2 := VStar[ii + 1]:
          if (evalf(temp2) <= floaterror + 0) then
            h[ii] := h[ii] + f1: 
          fi: 
        od:
#
# 3rd Quadrant, Scenario B 
#
      elif (evalf(c) = 0 and evalf(d) < infinity) then
        # print(ScenarioB):
        for ii from 1 to (nn - 1) do
          temp1 := VStar[ii]:
          temp2 := VStar[ii + 1]:
          if (evalf(temp1)  + floaterror >= evalf(bxd) and evalf(temp2) <= floaterror + 0) then
            h[ii] := h[ii] + f1: 
          fi:
          if (evalf(temp1)  + floaterror >= evalf(axd) and evalf(temp2) <= floaterror + 
              evalf(bxd)) then
            h[ii] := h[ii] + f2: 
          fi: 
        od:
#
# 3rd Quadrant, Scenario C
#
      elif (evalf(c) > 0 and is(d, infinity))
            then
        # print(ScenarioC):
        for ii from 1 to (nn - 1) do
          temp1 := VStar[ii]:
          temp2 := VStar[ii + 1]:
          if (evalf(temp1)  + floaterror >= -infinity and evalf(temp2) <= floaterror + 
              evalf(axc)) then
            h[ii] := h[ii] + f1:   
          fi:
          if (evalf(temp1)  + floaterror >= evalf(axc) and evalf(temp2) <= floaterror + 
              evalf(bxc))
              then
            h[ii] := h[ii] + f3: 
          fi: 
        od:
#
#  3rd Quadrant, Scenario D
#
      elif (evalf(c) > 0 and evalf(d) < infinity)
            then
        # print(ScenarioD):
        if (evalf(bxd) > evalf(axc)) then
#  Scenario D, Case 1 
          # print(Case1):
          for ii from 1 to (nn - 1) do
            temp1 := VStar[ii]:
            temp2 := VStar[ii + 1]:
            if (evalf(temp1)  + floaterror >= evalf(bxd) and evalf(temp2) <= floaterror +
                evalf(bxc)) then
              h[ii] := h[ii] + f3: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(axc) and evalf(temp2) <= floaterror +
                evalf(bxd)) then
              h[ii] := h[ii] + f4: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(axd) and evalf(temp2) <= floaterror +
                evalf(axc)) then
              h[ii] := h[ii] + f2: 
            fi: 
          od:
#  Scenario D, Case 2
        elif (evalf(axc) = evalf(bxd)) then
          # print(Case2):
          for ii from 1 to (nn - 1) do
            temp1 := VStar[ii]:
            temp2 := VStar[ii + 1]:
            if (evalf(temp1)  + floaterror >= evalf(axd) and evalf(temp2) <= floaterror + 
                evalf(axc)) then
              h[ii] := h[ii] + f2: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(bxd) and evalf(temp2) <= floaterror + 
                evalf(bxc)) then
              h[ii] := h[ii] + f3: 
            fi: 
          od:
#  Scenario D, Case 3
        elif (evalf(axc) > evalf(bxd)) then
          # print(Case3):
          for ii from 1 to (nn - 1) do
            temp1 := VStar[ii]:
            temp2 := VStar[ii + 1]:
            if (evalf(temp1)  + floaterror >= evalf(axc) and evalf(temp2) <= floaterror +
                evalf(bxc)) then
              h[ii] := h[ii] + f3: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(bxd) and evalf(temp2) <= floaterror +
                evalf(axc)) then
              h[ii] := h[ii] + f1: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(axd) and evalf(temp2) <= floaterror +
                evalf(bxd)) then
              h[ii] := h[ii] + f2: 
            fi: 
          od: 
        fi: 
      fi: 
    
#
#  The two segments transform into the 4th Quadrant
#
    elif (evalf(a)  + floaterror >= 0 and evalf(c) < 0) then
      assume(vv < 0);
      # print(QuadFour):
      f1 := int(f[i](x) * g[j](vv / x) / x, x = a .. b):
      f1 := unapply(f1, vv);
      f1 := f1(v);
      if (evalf(d) < 0) then 
        f2 := int(f[i](x) * g[j](vv / x) / x, x = a .. (vv/d)):
        f2 := unapply(f2, vv);
        f2 := f2(v);
      fi:
      if (evalf(c) > -infinity) then 
        f3 := int(f[i](x) * g[j](vv / x) / x, x = (vv/c) .. b):
        f3 := unapply(f3, vv);
        f3 := f3(v);
      fi:
      if (evalf(c) > -infinity and evalf(d) < 0 and
          evalf(axc) > evalf(bxd)) then 
        f4 := int(f[i](x) * g[j](vv / x) / x, x = (vv/c) .. (vv/d)):
        f4 := unapply(f4, vv);
        f4 := f4(v);
      fi:
#
#  4th Quadrant, Scenario A
#
      if (is(c, infinity) and evalf(d) = 0) then
        # print(ScenarioA):
        for ii from 1 to (nn - 1) do
          temp1 := VStar[ii]:
          temp2 := VStar[ii + 1]: 
          if (evalf(temp2) <= floaterror + 0) then
            h[ii] := h[ii] + f1: 
          fi: 
        od:
#
#  4th Quadrant, Scenario B
#
      elif (is(c, infinity)and evalf(d) < 0) then
        # print(ScenarioB):
        for ii from 1 to (nn - 1) do
          temp1 := VStar[ii]:
          temp2 := VStar[ii + 1]: 
          if (evalf(temp1)  + floaterror >= -infinity and evalf(temp2) <= floaterror + 
              evalf(bxd)) then
            h[ii] := h[ii] + f1:  
          fi: 
          if (evalf(temp1)  + floaterror >= evalf(bxd) and  evalf(temp2) <= floaterror + 
              evalf(axd)) then
            h[ii] := h[ii] + f2: 
          fi: 
        od:
#
#  4th Quadrant, Scenario C
#
      elif (evalf(c) > -infinity and evalf(d) = 0) then
        # print(ScenarioC):
        for ii from 1 to (nn - 1) do
          temp1 := VStar[ii]:
          temp2 := VStar[ii + 1]: 
          if (evalf(temp1)  + floaterror >= evalf(axc) and evalf(temp2) <= floaterror + 0)
              then
            h[ii] := h[ii] + f1: 
          fi:
          if (evalf(temp1)  + floaterror >= evalf(bxc) and evalf(temp2) <= floaterror + 
              evalf(axc)) then
            h[ii] := h[ii] + f3: 
          fi: 
        od:
#
#  4th Quadant, Scenario D
#
        # print(ScenarioD):
      elif (evalf(c) > -infinity and evalf(d) < 0) then
#  Scenario D, Case 1
        if (evalf(axc) > evalf(bxd)) then
          # print(Case1):
          for ii from 1 to (nn - 1) do
            temp1 := VStar[ii]:
            temp2 := VStar[ii + 1]:
            if (evalf(temp1)  + floaterror >= evalf(bxc) and evalf(temp2) <= floaterror + 
                evalf(bxd))
                then
              h[ii] := h[ii] + f3: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(bxd) and evalf(temp2) <= floaterror +
                evalf(axc)) then
              h[ii] := h[ii] + f4: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(axc) and evalf(temp2) <= floaterror +
                evalf(axd)) then
              h[ii] := h[ii] + f2: 
            fi: 
          od:
#  Scenario D, Case 2
        elif (evalf(axd) = evalf(bxc)) then
          # print(Case2):
          for ii from 1 to (nn - 1) do
            temp1 := VStar[ii]:
            temp2 := VStar[ii + 1]: 
            if (evalf(temp1)  + floaterror >= evalf(bxc) and evalf(temp2) <= floaterror + 
                evalf(axc)) then
              h[ii] := h[ii] + f3: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(axc) and evalf(temp2) <= floaterror +
                evalf(axd)) then
              h[ii] := h[ii] + f2: 
            fi: 
          od:
#  Scenario D, Case 3
        elif (evalf(axc) < evalf(bxd)) then
          #print(Case3):
          for ii from 1 to (nn - 1) do
            temp1 := VStar[ii]:
            temp2 := VStar[ii + 1]: 
            if (evalf(temp1)  + floaterror >= evalf(bxc) and evalf(temp2) <= floaterror + 
                evalf(axc)) then
              h[ii] := h[ii] + f3: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(axc) and evalf(temp2) <= floaterror + 
                evalf(bxd)) then
              h[ii] := h[ii] + f1: 
            fi:
            if (evalf(temp1)  + floaterror >= evalf(bxd) and evalf(temp2) <= floaterror + 
                evalf(axd)) then
              h[ii] := h[ii] + f2: 
            fi: 
          od: 
        fi: 
      fi:
     
    fi: 
  od:
od: 
#
#  Make a new list of sublists for V
#
hh:= []:
for i from 1 to (nn - 1) do
  hh := [op(hh), unapply(simplify(h[i]), v)]:
od:
#
#  Reduce any unneeded duplication around zero in the piecewise PDF list 
#  of sublists
#
for i from 2 to (nn - 1) do 
  if ((hh[2][i] = 0) 
      and (limit(hh[1][i](pt), pt = 0) <> infinity)
      and (limit(hh[1][i](pt), pt = 0) <> -infinity) 
      and (hh[1][i - 1](0) = hh[1][i](0))) then  
    hh[1] := subsop(i = NULL, hh[1]):
    hh[2] := subsop(i = NULL, hh[2]): 
    # print(reducingsizeofhh):
    break:
  fi:
od:  
fV := [hh, VStar, ["Continuous", "PDF"]]:
# print(fV):
#fV := CleanUp(fV):
RETURN(fV):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: productdiscrete4.map
#
#  Procedure Name: ProductDiscrete(X, Y)
#
#  Other APPL Procedures Called: 
#
#  Date: January 15, 2001
#
#  Purpose: 
#
#  Arguments: X, Y
#
#  Algorithm:
ProductDiscrete := proc(X :: list(list), Y :: list(list)) 
global fX, fY, fXNeg, fXPos, fYNeg, fYPos:
local Lo, Hi, n, DotX, m, DotY, Temp, leftbound, i, flagx, upperbound,
    j, flagy, i1, j1, tempprod, tempprob, lengthposx, Temp1, Q4Prod,
    Q4Prob, Temp2, Q3Prod, Q3Prob, fYTemp, Q2Prod, Q2Prob, Q1Prod,
    Q1Prob, lengthposy, fXTemp, fXPosTemp, fYPosTemp, Q2Q4Prod,
    Q2Q4Prob, Q1Q3Prod, Q1Q3Prob, Prods, Probs, FinalSupport, FinalPDF,
    k, NumZeros, fZ:

fX := X:
fY := Y:
fX := Convert(fX):
if (fX = false) then
  print(`ERROR(Product): Discrete random variable X is NOT`):
  print(`in legal APPL form`):
  return:
fi:
fY := Convert(fY):
if (fY = false) then
  print(`ERROR(Product): Discrete random variable Y is NOT`):
  print(`in legal APPL form`):
  return:
fi:
#
#  Determine if the random variable X has a "dot" support format or a
#  "nodot" support format. Return an error message for a symbolic PDF 
#  in the "dot" format with symbolic support, such as:
#  X := [[x -> x / 6], [1 .. n], ["Discrete", "PDF"]];
#
if type(fX[2][1], range) then
  Lo := lhs(fX[2][1]):
  Hi := rhs(fX[2][1]):
  if type(Hi, symbol) and not(evalb(Hi = infinity)) then      
    print(`ERROR(Product): RV's support must be numeric`):
    return:
  elif type(Lo, symbol) or evalb(Lo = -infinity) then 
    print(`ERROR(Product): RV's lower support must be`):
    print(`a finite numerical value`):
    return:
#
#  Convert finite "dot" formats to "nodot" formats. For example, if
#  X := [[x -> x / 6], [1 .. 3], ["Discrete", "PDF"]], convert X to
#  X := [[1 / 6, 2 / 6, 3 / 6], [1, 2, 3], ["Discrete", "PDF]];
#
  elif type(Lo, numeric) and type(Hi, numeric) then
    fX := ConvertToNoDot(fX):
    n := nops(fX[2]):
    DotX := false:
  else
    DotX := true:
  fi:
#
#  The RV X has a "nodot" support format
#
else
  n := nops(fX[2]):
  DotX := false:
fi:
#
#  Determine if the random variable Y has a "dot" support format or a
#  "nodot" support format. Return an error message for a symbolic PDF 
#  in the "dot" format with symbolic support
#
if type(fY[2][1], range) then
  Lo := lhs(fY[2][1]):
  Hi := rhs(fY[2][1]):
  if type(Hi, symbol) and not(evalb(Hi = infinity)) then 
    print(`ERROR(Product): RV's support must be numeric`):
    return:
  elif type(Lo, symbol) or evalb(Lo = -infinity) then 
    print(`ERROR(Product): RV's lower support must be`):
    print(`a finite numerical value`):
    return:
#
#  Convert finite "dot" formats to "nodot" formats. 
#
  elif type(Lo, numeric) and type(Hi, numeric) then
    fY := ConvertToNoDot(fY):
    m := nops(fY[2]):
    DotY := false:
  else
    DotY := true:
  fi:
else
  m := nops(fY[2]):
  DotY := false:
fi:
#
#  RV has a "nodot" support format
#  Example:  X := [[1/6, 1/3, 1/2], [1, 2, 3], ["Discrete", "PDF"]];
#  DISCRETE, NODOT (FINITE)
#
if not(DotX) and not(DotY) then
#
#  Determine left boundardy of array A; this is where x's switch from
#  negative to positive
#
  if (n = 1) or (m = 1) then
    Temp := BruteForceProductMethod():
    return([Temp[2], Temp[1], ["Discrete", "PDF"]]):
  fi:
  if fX[2][1] >= 0 then
    leftbound := 1:
  elif fX[2][n] < 0 then
    leftbound := n + 1:
  else
    leftbound := n:
    i := 2:
    flagx := 0:
    while (i <= n and flagx = 0) do
      if (fX[2][i] >= 0) then
        leftbound := i:
        flagx := 1:
      fi:
      i := i + 1:
    od:
  fi:
  # print(`leftbound is`, leftbound):
#
#  Determine upper boundary of array A; this is where y's switch from
#  negative to positive
#
  if fY[2][1] >= 0 then
    upperbound := 1:
  elif fY[2][m] < 0 then
    upperbound := m + 1:
  else
    upperbound := m:
    j := 2:
    flagy := 0:
    while (j <= m and flagy = 0) do
      if (fY[2][j] >= 0) then
        upperbound := j:
        flagy := 1:
      fi:
      j := j + 1:     
    od:
  fi:

# *****************************************
#                 9 cases
# *****************************************

  # Quadrant 1 Only
  if (leftbound = 1 and upperbound = 1) then
    # print(`Q1`):
    Temp := MovingHeapProductMethod():
  # Quadrant 3 Only
  elif (leftbound = n + 1 and upperbound = m + 1) then
  # Reverse X and Y lists
    # print(`Q3`):
    for i1 from 1 to ceil(n / 2) do
      tempprod := fX[2][i1]:
      tempprob := fX[1][i1]:
      fX[2][i1] := fX[2][n - i1 + 1]:
      fX[1][i1] := fX[1][n - i1 + 1]:
      fX[2][n - i1 + 1] := tempprod:
      fX[1][n - i1 + 1] := tempprob:
    od:
    for j1 from 1 to ceil(m / 2) do
      tempprod := fY[2][j1]:
      tempprob := fY[1][j1]:
      fY[2][j1] := fY[2][m - j1 + 1]:
      fY[1][j1] := fY[1][m - j1 + 1]:
      fY[2][m - j1 + 1] := tempprod:
      fY[1][m - j1 + 1] := tempprob:
    od:
    Temp := MovingHeapProductMethod():
  # Quadrant 4 Only
  elif (leftbound = 1 and upperbound = m + 1) then     
    # print(`Q4`):
    for i1 from 1 to ceil(n / 2) do
      tempprod := fX[2][i1]:
      tempprob := fX[1][i1]:
      fX[2][i1] := fX[2][n - i1 + 1]:
      fX[1][i1] := fX[1][n - i1 + 1]:
      fX[2][n - i1 + 1] := tempprod:
      fX[1][n - i1 + 1] := tempprob:
    od:
    Temp := MovingHeapProductMethod():
  # Quadrant 2 Only
  elif (leftbound = n + 1 and upperbound = 1) then
    # print(`Q2`):
    for j1 from 1 to ceil(m / 2) do
      tempprod := fY[2][j1]:
      tempprob := fY[1][j1]:
      fY[2][j1] := fY[2][m - j1 + 1]:
      fY[1][j1] := fY[1][m - j1 + 1]:
      fY[2][m - j1 + 1] := tempprod:
      fY[1][m - j1 + 1] := tempprob:
    od:
    Temp := MovingHeapProductMethod():
  # Quadrant 4 -> Quadrant 3
  elif (upperbound = m + 1) then
    # print(`Q4 -> Q3`):
    fXNeg[2] := [seq(fX[2][k2], k2 = 1 .. leftbound - 1)]:
    fXNeg[1] := [seq(fX[1][k2], k2 = 1 .. leftbound - 1)]:
    fX[2] := [seq(fX[2][k1], k1 = leftbound .. n)]:
    fX[1] := [seq(fX[1][k1], k1 = leftbound .. n)]:
    lengthposx := n - leftbound + 1:
    for i1 from 1 to ceil(lengthposx / 2) do
      tempprod := fX[2][i1]:
      tempprob := fX[1][i1]:
      fX[2][i1] := fX[2][lengthposx - i1 + 1]:
      fX[1][i1] := fX[1][lengthposx - i1 + 1]:
      fX[2][lengthposx - i1 + 1] := tempprod:
      fX[1][lengthposx - i1 + 1] := tempprob:
    od:
    if (lengthposx = 1 or m = 1) then
      Temp1 := BruteForceProductMethod():
    else
      Temp1 := MovingHeapProductMethod():
    fi:
    Q4Prod := seq(Temp1[2][k], k = 1 .. lengthposx * m):
    Q4Prob := seq(Temp1[1][k], k = 1 .. lengthposx * m):
    fX[2] := fXNeg[2]:
    fX[1] := fXNeg[1]:
    for i1 from 1 to floor(leftbound / 2) do
      tempprod := fX[2][i1]:
      tempprob := fX[1][i1]:
      fX[2][i1] := fX[2][leftbound - i1]:
      fX[1][i1] := fX[1][leftbound - i1]:
      fX[2][leftbound - i1] := tempprod:
      fX[1][leftbound - i1] := tempprob:
    od:
    for j1 from 1 to ceil(m / 2) do
      tempprod := fY[2][j1]:
      tempprob := fY[1][j1]:
      fY[2][j1] := fY[2][m - j1 + 1]:
      fY[1][j1] := fY[1][m - j1 + 1]:
      fY[2][m - j1 + 1] := tempprod:
      fY[1][m - j1 + 1] := tempprob:
    od:
    if ((n - lengthposx) = 1 or m = 1) then
      Temp2 := BruteForceProductMethod():
    else
      Temp2 := MovingHeapProductMethod():
    fi:
    Q3Prod := seq(Temp2[2][k], k = 1 .. (n - lengthposx) * m):
    Q3Prob := seq(Temp2[1][k], k = 1 .. (n - lengthposx) * m):
    Temp := [Q4Prob, Q3Prob], [Q4Prod, Q3Prod]:
  # Quadrant 2 -> Quadrant 1
  elif (upperbound = 1) then
    # print(`Q2 -> Q1`):
    fXPos[2] := [seq(fX[2][k1], k1 = leftbound .. n)]:
    fXPos[1] := [seq(fX[1][k1], k1 = leftbound .. n)]:
    fX[2] := [seq(fX[2][k2], k2 = 1 .. leftbound - 1)]:
    fX[1] := [seq(fX[1][k2], k2 = 1 .. leftbound - 1)]:
    lengthposx := n - leftbound + 1:
    fYTemp := fY:
    for j1 from 1 to ceil(m / 2) do
      tempprod := fY[2][j1]:
      tempprob := fY[1][j1]:
      fY[2][j1] := fY[2][m - j1 + 1]:
      fY[1][j1] := fY[1][m - j1 + 1]:
      fY[2][m - j1 + 1] := tempprod:
      fY[1][m - j1 + 1] := tempprob:
    od:
    if ((n - lengthposx) = 1 or m = 1) then
      Temp1 := BruteForceProductMethod():
    else
      Temp1 := MovingHeapProductMethod():
    fi:
    Q2Prod := seq(Temp1[2][k], k = 1 .. (n - lengthposx) * m):
    Q2Prob := seq(Temp1[1][k], k = 1 .. (n - lengthposx) * m):
    fX[2] := fXPos[2]:
    fX[1] := fXPos[1]:
    fY := fYTemp:
    if (lengthposx = 1 or m = 1) then
      Temp2 := BruteForceProductMethod():
    else
      Temp2 := MovingHeapProductMethod():
    fi:
    Q1Prod := seq(Temp2[2][k], k = 1 .. lengthposx * m):
    Q1Prob := seq(Temp2[1][k], k = 1 .. lengthposx * m):
    Temp := [Q2Prob, Q1Prob], [Q2Prod, Q1Prod]:
  # Quadrant 2 -> Quadrant 3
  elif (leftbound = n + 1) then
    # print(`Q2 -> Q3`):
    fYNeg[2] := [seq(fY[2][k2], k2 = 1 .. upperbound - 1)]:
    fYNeg[1] := [seq(fY[1][k2], k2 = 1 .. upperbound - 1)]:
    fY[2] := [seq(fY[2][k1], k1 = upperbound .. m)]:
    fY[1] := [seq(fY[1][k1], k1 = upperbound .. m)]:
    lengthposy := m - upperbound + 1:
    for j1 from 1 to ceil(lengthposy / 2) do
      tempprod := fY[2][j1]:
      tempprob := fY[1][j1]:
      fY[2][j1] := fY[2][lengthposy - j1 + 1]:
      fY[1][j1] := fY[1][lengthposy - j1 + 1]:
      fY[2][lengthposy - j1 + 1] := tempprod:
      fY[1][lengthposy - j1 + 1] := tempprob:
    od:
    if (n = 1 or lengthposy = 1) then
      Temp1 := BruteForceProductMethod():
    else
      Temp1 := MovingHeapProductMethod():
    fi:
    Q2Prod := seq(Temp1[2][k], k = 1 .. n * lengthposy):
    Q2Prob := seq(Temp1[1][k], k = 1 .. n * lengthposy):
    fY[2] := fYNeg[2]:
    fY[1] := fYNeg[1]:
    for i1 from 1 to ceil(n / 2) do
      tempprod := fX[2][i1]:
      tempprob := fX[1][i1]:
      fX[2][i1] := fX[2][n - i1 + 1]:
      fX[1][i1] := fX[1][n - i1 + 1]:
      fX[2][n - i1 + 1] := tempprod:
      fX[1][n - i1 + 1] := tempprob:
    od:
    # print(`fXNeg is`, fX): 
    for j1 from 1 to floor(upperbound / 2) do
      tempprod := fY[2][j1]:
      tempprob := fY[1][j1]:
      fY[2][j1] := fY[2][upperbound - j1]:
      fY[1][j1] := fY[1][upperbound - j1]:
      fY[2][upperbound - j1] := tempprod:
      fY[1][upperbound - j1] := tempprob:
    od:
    # print(`fYneg is `, fY):
    if (n = 1 or (m - lengthposy) = 1) then
      Temp2 := BruteForceProductMethod():
    else
      Temp2 := MovingHeapProductMethod():
    fi:
    Q3Prod := seq(Temp2[2][k], k = 1 .. n * (m - lengthposy)):
    Q3Prob := seq(Temp2[1][k], k = 1 .. n * (m - lengthposy)):
    Temp := [Q2Prob, Q3Prob], [Q2Prod, Q3Prod]:
  # Quadrant 4 -> Quadrant 1
  elif (leftbound = 1) then
    # print(`Q4 -> Q1`):
    fYPos[2] := [seq(fY[2][k1], k1 = upperbound .. m)]:
    fYPos[1] := [seq(fY[1][k1], k1 = upperbound .. m)]:
    fY[2] := [seq(fY[2][k2], k2 = 1 .. upperbound - 1)]:
    fY[1] := [seq(fY[1][k2], k2 = 1 .. upperbound - 1)]:
    lengthposy := m - upperbound + 1:
    fXTemp := fX:
    for i1 from 1 to ceil(n / 2) do
      tempprod := fX[2][i1]:
      tempprob := fX[1][i1]:
      fX[2][i1] := fX[2][n - i1 + 1]:
      fX[1][i1] := fX[1][n - i1 + 1]:
      fX[2][n - i1 + 1] := tempprod:
      fX[1][n - i1 + 1] := tempprob:
    od:
    if (n = 1 or (m - lengthposy) = 1) then
      Temp1 := BruteForceProductMethod():
    else
      Temp1 := MovingHeapProductMethod():
    fi:
    Q4Prod := seq(Temp1[2][k], k = 1 .. n * (m - lengthposy)):
    Q4Prob := seq(Temp1[1][k], k = 1 .. n * (m - lengthposy)):
    fY[2] := fYPos[2]:
    fY[1] := fYPos[1]:
    fX := fXTemp:
    if (n = 1 or lengthposy = 1) then
      Temp2 := BruteForceProductMethod():
    else
      Temp2 := MovingHeapProductMethod():
    fi:
    Q1Prod := seq(Temp2[2][k], k = 1 .. n * lengthposy):
    Q1Prob := seq(Temp2[1][k], k = 1 .. n * lengthposy):
    Temp := [Q4Prob, Q1Prob], [Q4Prod, Q1Prod]:
  # Quadrant 4 -> Quadrant 1, Quadrant 2 -> Quadrant 3
  else
    # print(`Q2, Q4 -> Q1, Q3`):
    fXNeg[2] := [seq(fX[2][k2], k2 = 1 .. leftbound - 1)]:
    fXNeg[1] := [seq(fX[1][k2], k2 = 1 .. leftbound - 1)]:
    fXPos[2] := [seq(fX[2][k1], k1 = leftbound .. n)]:
    fXPos[1] := [seq(fX[1][k1], k1 = leftbound .. n)]:
    fXPosTemp[2] := fXPos[2]:
    fXPosTemp[1] := fXPos[1]:
    fYNeg[2] := [seq(fY[2][k2], k2 = 1 .. upperbound - 1)]:
    fYNeg[1] := [seq(fY[1][k2], k2 = 1 .. upperbound - 1)]:
    fYPos[2] := [seq(fY[2][k1], k1 = upperbound .. m)]:
    fYPos[1] := [seq(fY[1][k1], k1 = upperbound .. m)]:
    fYPosTemp[2] := fYPos[2]:
    fYPosTemp[1] := fYPos[1]:
    # Reverse positive x's
    lengthposx := n - leftbound + 1:
    for i1 from 1 to ceil(lengthposx / 2) do
      tempprod := fXPos[2][i1]:
      tempprob := fXPos[1][i1]:
      fXPos[2][i1] := fXPos[2][lengthposx - i1 + 1]:
      fXPos[1][i1] := fXPos[1][lengthposx - i1 + 1]:
      fXPos[2][lengthposx - i1 + 1] := tempprod:
      fXPos[1][lengthposx - i1 + 1] := tempprob:
    od:
    # Reverse positive y's
    lengthposy := m - upperbound + 1:
    for j1 from 1 to ceil(lengthposy / 2) do
      tempprod := fYPos[2][j1]:
      tempprob := fYPos[1][j1]:
      fYPos[2][j1] := fYPos[2][lengthposy - j1 + 1]:
      fYPos[1][j1] := fYPos[1][lengthposy - j1 + 1]:
      fYPos[2][lengthposy - j1 + 1] := tempprod:
      fYPos[1][lengthposy - j1 + 1] := tempprob:
    od:
    # print(`fXNeg is`, fXNeg[2], fXNeg[1]):
    # print(`fXPos is`, fXPos[2], fXPos[1]):
    # print(`fYNeg is`, fYNeg[2], fYNeg[1]):
    # print(`fYPos is`, fYPos[2], fYPos[1]):
    if (lengthposx = 1 or (m - lengthposy) = 1) or 
       ((n - lengthposx) = 1 or lengthposy = 1) then
      Temp1 := BruteForceProductQ2Q4():
    else
      Temp1 := MovingHeapProductQ2Q4():
    fi:
    # print(`Temp1 is`, Temp1):
    Q2Q4Prod := seq(Temp1[2][k], k = 1 .. (n - lengthposx) * 
        lengthposy + lengthposx * (m - lengthposy)):
    Q2Q4Prob := seq(Temp1[1][k], k = 1 .. (n - lengthposx) * 
        lengthposy + lengthposx * (m - lengthposy)):
    fXPos[2] := fXPosTemp[2]:
    fXPos[1] := fXPosTemp[1]:
    fYPos[2] := fYPosTemp[2]:
    fYPos[1] := fYPosTemp[1]:
    for i1 from 1 to floor(leftbound / 2) do
      tempprod := fXNeg[2][i1]:
      tempprob := fXNeg[1][i1]:
      fXNeg[2][i1] := fXNeg[2][leftbound - i1]:
      fXNeg[1][i1] := fXNeg[1][leftbound - i1]:
      fXNeg[2][leftbound - i1] := tempprod:
      fXNeg[1][leftbound - i1] := tempprob:
    od:
    for j1 from 1 to floor(upperbound / 2) do
      tempprod := fYNeg[2][j1]:
      tempprob := fYNeg[1][j1]:
      fYNeg[2][j1] := fYNeg[2][upperbound - j1]:
      fYNeg[1][j1] := fYNeg[1][upperbound - j1]:
      fYNeg[2][upperbound - j1] := tempprod:
      fYNeg[1][upperbound - j1] := tempprob:
    od:
    # print(`fXNeg is`, fXNeg[2], fXNeg[1]):
    # print(`fXPos is`, fXPos[2], fXPos[1]):
    # print(`fYNeg is`, fYNeg[2], fYNeg[1]):
    # print(`fYPos is`, fYPos[2], fYPos[1]):
    if (lengthposx = 1 or lengthposy = 1) or
       ((n - lengthposx) = 1 or (m - lengthposy) = 1) then
      Temp2 := BruteForceProductQ1Q3():
    else
      # print(`MovingHeap`):
      Temp2 := MovingHeapProductQ1Q3():
    fi:
    # print(`Temp2 is`, Temp2):
    Q1Q3Prod := seq(Temp2[2][k], k = 1 .. ((n - lengthposx) * (m  -
        lengthposy)) + (lengthposx * lengthposy)):
    Q1Q3Prob := seq(Temp2[1][k], k = 1 .. ((n - lengthposx) * (m  -
        lengthposy)) + (lengthposx * lengthposy)):
    Temp := [Q2Q4Prob, Q1Q3Prob], [Q2Q4Prod, Q1Q3Prod]:
    print(`Temp is`, Temp):
  fi:
  Prods := Temp[1]:
  Probs := Temp[2]:
#
#  Remove redundancies from probability list
#
  FinalSupport := array(sparse, 1 .. n * m, []):
#
#  Since first element is not unique (as in the convolution code) place
#  only the first product element in the final support
#
  FinalSupport[1] := Prods[1]:
  FinalPDF := array(sparse, 1 .. n * m, []):
  FinalPDF[1] := 0:
  k := 1:
  j := 1:
  while (k < n * m) do
    FinalPDF[j] := FinalPDF[j] + Probs[k]:
    if evalf(Prods[k]) <> evalf(Prods[k + 1]) then
      j := j + 1:
      FinalSupport[j] := Prods[k + 1]:
    fi:
    k := k + 1:
  od:
  FinalPDF[j] := FinalPDF[j] + Probs[k]:
#
#  Remove extraneous zeros from FinalPDF and FinalSupport. We know the
#  zeros (if any) at the end of the FinalPDF array are not probability
#  values.  They exist because of the redundant values in Prods.  Use
#  FinalPDF to determine how many extraneous zeros exist, and 
#  reconstruct FinalPDF and FinalSupport so the extra zeros are not
#  included as part of the arrays.
#
  NumZeros := 0:
  for i from (n * m) by -1 to 1 while FinalPDF[i] = 0 do
    NumZeros := NumZeros + 1:
  od:
  FinalSupport := array(1 .. n * m - NumZeros, [seq(FinalSupport[i],
      i = 1 .. n * m - NumZeros)]):
  FinalPDF := array(1 .. n * m - NumZeros, [seq(FinalPDF[i],
      i = 1 .. n * m - NumZeros)]):
  FinalSupport := convert(FinalSupport, list):
  FinalPDF := convert(FinalPDF, list):
  fZ := [FinalPDF, eval(FinalSupport), ["Discrete", "PDF"]]:
#
#  At least one RV has infinite support
#
else # if DotX or DotY
  print(`Unable to compute the product of these random variables`):
  return:
fi:
return(fZ):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777  
#  Filename: qqplot1.map
#
#  Procedure name: QQPlot(X, Sample, Parameters)
#
#  Other APPL Procedures Called: IDF
#
#  Date: June 26, 2000
#
#  Purpose: Plots the q_i quantile of a fitted distribution function X 
#           versus the q_i quantile of the Sample distribution
#
#  Arguments: X: Random variable
#             Sample: List of sample data points
#             Parameters
#  
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Check that the RV X is in a list-of-lists format
#    3.  Check that X is in its PDF, CDF, SF, HF, CHF, or IDF format
#
QQPlot := proc(X :: list(list), Sample :: list, Parameters)
local NumLists, n, q, SortedSample, i, Fitted, ParFitted, DataPoints, 
    Hi:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 3) then
  print(`ERROR(QQPlot): This procedure requires 3 arguments`):
  RETURN():
fi:
#
#  Check that the RV X is in a list-of-lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(QQPlot): The RV X must be in a`): 
  print(`list of 3 lists format`):
  RETURN(): 
fi:
#
#  Check that X is in its PDF, CDF, SF, HF, CHF, or IDF format
#
if not((X[3][2] = "PDF") or
       (X[3][2] = "CDF") or
       (X[3][2] = "SF") or
       (X[3][2] = "HF") or
       (X[3][2] = "CHF") or
       (X[3][2] = "IDF")) then
  print(`ERROR(QQPlot): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  RETURN():
fi:

with(plots):
n := nops(Sample):
q := [seq((i - (1 / 2)) / n, i = 1 .. n)]:
# print(`q is`, q):
SortedSample := sort(Sample):
Fitted := []:
for i from 1 to n do
  Fitted := [op(Fitted), IDF(X, q[i])]:
od:
ParFitted := subs({op(Parameters)}, Fitted):
# print(`Parfitted is`, ParFitted):
DataPoints := []:
for i from 1 to n do
  DataPoints := [op(DataPoints), [SortedSample[i], ParFitted[i]]]:
od:
# print(DataPoints):
# Lo := min(Parfitted[1], SortedSample[1]):
Hi := max(ParFitted[n], SortedSample[n]):
pointplot(DataPoints, view = [0 .. Hi + 10, 0 .. Hi + 10], labels = ["sample",
    "model"], scaling = constrained, title = "Q-Q Plot"):

end:


#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: rangestat7.map  
#  Assuming incremented by 1 in without replacement case
#  Paul Stockmeyer formula for with replacement case
#  rangestat7.map: adding continuous capability
#
#  Procedure Name: RangeStat(X, n, ["wo"])
#
#  Other APPL Procedures Called: Convert
#
#  Date: May 10, 2001
#
#  Purpose: RangeStat is a procedure that returns the PDF of the range
#           X_(n) - X_(1), of a population when n items are sampled 
#
#  Arguments: X: A random variable,
#             n: The number of items drawn randomly from the population
#                with PDF fX(x), 
#             "wo" (optional): A variable that indicates if the items 
#                drawn from the population are done so without (wo)
#                replacement (for discrete distributions only)
#
#  Algorithm:
#    1. Check for the appropriate number of arguments
#    2. Check that the RV X is a list of 3 sublists
#    3. Check that n >= 2, if not return an error message stating that
#       there is no range since only 1 item is sampled from the
#       population
#    4. Convert X to PDF form if not already in that form
#    5. Call the procedure Convert(X) to convert the discrete random
#       variable's support to a standard APPL discrete random variable
#       support format: 
#           standard "dot" support format:
#       [anything .. anything, incremented by k, transformed by g(x)]
#           standard "no dot" support format:        
#       [x1, x2, x3, ... , xN]
#    6. Determine if the random variable X has a "dot" support format
#       (which indicates a formulaic PDF) or a "nodot" support format
#       (which indicates a numeric PDF). Return an error message for
#       formulaic PDFs with non-numeric support values, such as:
#       X := [[x -> x/6], [1 .. n], ["Discrete", "PDF"]];
#    7. Check that N >= 2, if not return an error message stating that 
#       the population consists of only 1 element and so thhere is no
#       range
#    8. If only 2 arguments are given, by default items are sampled
#       with replacement  
#    9. If X has a numeric PDF, then calculate the PDF of the range by
#       formula from Paul Stockmeyer.
#   10. If X has a formulaic PDF, then calculate the PDF of the range ..
#       by obtaining a general expression for the PDF with the
#       same formula used in the numeric case. 
#   11. If 3 arguments are provided, check if the third argument is
#       the string "wo." If it is, then items are drawn from the RV's
#       population without replacement 
#   12. Determine if the random variable X has a formulaic PDF. If it
#       does and also has finite support, then call the procedure
#       ConvertToNumeric to convert its PDF and support to the standard
#       APPL numeric list format. The conversion is necessary in order
#       to have list inputs for the procedures NextPermutation and
#       NextCombination.
#   15. If X has finite support and if n = N, then the PDF of the range
#       is 1 for x = n, and 0 otherwise.
#   16. If n = 2, 3, ... N - 1, create an array of size N - n to store
#       the range values x from 1 to N - n + 1. Initialize the array to
#       contain all zeros.
#   17. Create the first lexicographical combination of n items. 
#   18. Assign perm as the current combination. For each combination,
#       the algorithm finds every possible permutation of that
#       combination.
#   19. For each permutation, compute the probability of obtaining that
#       given permutation.
#   20. Find the maximum and minimum elements of the permutation and
#       then determine their diference, the range. Store the 
#       permutation's probability in the appropriate position in the
#       array.
#   21. Find the next lexicographical combination, and repeat steps 18 
#       - 20.
#   22. If X has infinite support, then at present, RangeStat is unable
#       to compute the range for infinite support without replacement
#       cases. This is an open area for future work. 
#   23. If 3 arguments are provided and the third one is not the
#       string "wo", then return an error message
#   24. Return the PDF of the range in the list of sublists format
#
RangeStat := proc(X :: list(list), n :: {posint, symbol}, indicator ::
    string)
local NumLists, fX, FX, nsegs, fXRange, ffX, Lo, Hi, formulaic, N, s, p,
    k, uppers, rs, rp,
    i, j, sortedr, sortedrs, sortedrp, frs, frp, nz, Finite,
    combo, perm, PermProb, cumsum, m, HiVal, LoVal, Range, flag,
    fXRangeNoZeros, index:
#
#  Check for the appropriate number of arguments
#
if ((nargs <> 2) and (nargs <> 3)) then
  print(`ERROR(RangeStat): This procedure requires 2 or 3 arguments:`):
  print(`A random variable X,`):
  print(`the number of random items sampled from the population n,`):
  print(`an optional argument wo, which indicates sampling *without*`): 
  print(`replacement for discrete random variables`):
  return:
fi:
#
#  Check that the RV X is a list of 3 sublists
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(RangeStat): The RV X must be a list of 3 lists`):
  return:
fi:
#
#  Check that n >= 2, if not return a message stating that there is no
#  range 
#
if not(type(n, symbol)) and (n < 2) then
  print(`ERROR(RangeStat): Only 1 item sampled from the population`):
  print(`There is no range`):
  return:
fi:
#  Convert X to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
  fX := X:
elif ((X[3][2] = "CDF") or
      (X[3][2] = "SF") or
      (X[3][2] = "HF") or
      (X[3][2] = "CHF") or
      (X[3][2] = "IDF")) then
  fX := PDF(X):
else
  print(`ERROR(RangeStat): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
#
#  If the RV X is continuous and it CDF is tractable, find the PDF of
#  the range statistic
#
if (fX[3][1] = "Continuous") then
  FX := CDF(X):
  # print(FX):
  nsegs := nops(fX[1]):
  fXRange := []:
  for i from 1 to nsegs do
    ffX := unapply(int(n * (n - 1) * 
        (FX[1][i](z) - FX[1][i](z - x)) ^ (n - 2) * fX[1][i](z - x)
        * fX[1][i](z), z = x .. fX[2][2]), x): 
    fXRange := [op(fXRange), op(ffX)]: 
  od:
#
#  Call the procedure Convert(X) to convert the discrete random
#  variable's support to a standard APPL discrete RV support format. 
#
elif (fX[3][1] = "Discrete") then
  fX := Convert(fX):
  if (fX = false) then
    print(`ERROR(RangeStat): Discrete RV X is NOT in legal APPL form`):
    return:
  fi:
  FX := CDF(fX):
#
#  Determine if the random variable X has a "dot" support format (which
#  indicates a formulaic PDF) or a "nodot" support format (which 
#  indicates a numeric PDF). Return an error message for formulaic PDFs
#  with non-numeric support values (in the "dot" format), such as:
#  X := [[x -> x/6], [1 .. n], ["Discrete", "PDF"]];
#
  if type(fX[2][1], range) then
    Lo := lhs(fX[2][1]):
    Hi := rhs(fX[2][1]):
    if type(Hi, symbol) and not(evalb(Hi = infinity)) then 
      print(`ERROR(RangeStat): RV's support must be numeric`):
      return:
    elif type(Lo, symbol) and not(evalb(Lo = infinity)) then 
      print(`ERROR(RangeStat): RV's support must be numeric`):
      return:
    else
      formulaic := true:
    fi:
  else
    N := nops(fX[2]):
    formulaic := false:
#
#  Check that N >= 2, if not return a message stating that there is no
#  range 
#
    if (N < 2) then
      print(`ERROR(RangeStat): The population consists of 1 element`):
      print(`There is no range`):
      return:
    fi:
  fi:
#
#  If only 3 arguments are given, by default items are sampled with
#  replacement  
# 
  if (nargs = 2) then
#
#  RV has numeric PDF
#  Example:  X := [[1/6, 1/3, 1/2], [1, 2, 3], ["Discrete", "PDF"]];
#
#  DISCRETE/WITH REPLACEMENT/NUMERIC PDF
#
# 
    if not(formulaic) then
# assign s as the support of the random variable X
# s[1], s[2], s[3], ..., s[N] are sorted distinct support values, i.e.,
# s[1] < s[2] < ... < s[N]
      s := fX[2]:
      # print(s):
# assign p as the probability mass function of the random variable X
# p[1], p[2], ..., p[N] are the probability mass values that correspond
# to the support values s[1], s[2], ..., s[N], respectively
      p := fX[1]:
      # print(p):
# k is a counter
      k := 1:
# rs is an array that holds the range support values--initialize it to
# contain all 0's (sparse)
# rp is an array that holds the range probability mass values--
# initialize it to contain all 0's (sparse)
#
# LARRY: An array must be constructed before it can be used--that's why
# I'm building rs and rp now.  There are only 1 + 2 + 3 + ... + N
# range support values possible if the support is of size N.
#
      uppers := add(m, m = 1 .. N):
      rs := array(1 .. uppers, sparse, []):
      rp := array(1 .. uppers, sparse, []):
      # print(rs):
      # print(rp):
      # print(N):
      for i from 1 to N do
        for j from i to N do
          # print(s[j]):
          # print(s[i]):
          rs[k] := s[j] - s[i]:
          # print(rs[k]):
          # print(rs):
          rp[k] := add(p[m], m = i .. j) ^ n - 
                   add(p[m], m = i + 1 .. j) ^ n -
                   add(p[m], m = i .. j - 1) ^ n +
                   add(p[m], m = i + 1 .. j - 1) ^ n:
          k := k + 1:
          # print(add(p[m], m = i .. j) ^ n):
          # print(add(p[m], m = i + 1 .. j) ^ n):
          # print(add(p[m], m = i .. j - 1) ^ n):
          # print(`lower add bd`, i + 1): print(`upper add bd`, j - 1):
          # print(add(p[m], m = i + 1 .. j - 1) ^ n):
        od:
      od:
      # print(rs):
      # print(rp):
      rs := convert(rs, list):
      rp := convert(rp, list):
      sortedr := InsertionSort(rs, rp):
      # print(sortedr):
      sortedrs := sortedr[1]:
      sortedrp := sortedr[2]:
      # print(sortedrs):
      # print(sortedrp):
# Build final range support (frs) and final range probability values
# (frp)--initialize them to contain all zeroes
      frs := array(sparse, 1 .. uppers, sparse, []):
      frp := array(sparse, 1 .. uppers, sparse, []):
# Remove redundancies from support probability list
# Place the first range support and range probability values in the
# first position in the frs and frp arrays
      frs[1] := sortedrs[1]:
      frp[1] := sortedrp[1]:
      k := 2:
      j := 1:
      while (k <= uppers) do
        if evalf(sortedrs[k]) <> evalf(sortedrs[k - 1]) then
          j := j + 1:
          frs[j] := sortedrs[k]:
        fi:
          frp[j] := frp[j] + sortedrp[k]:
        k := k + 1:
      od:
      # print(frs): # print(frp):
#
# Remove extraneous zeros from frs and frp. We know the zeros (if any)
# at the end of the frp array are not probability values.  They exist
# because of the redundant values in s.  Use frp to determine how many
# extraneous zeros exist, and reconstruct frp and frs so the extra zeros
# are not included as part of the arrays.
#
      nz := 0:
      for i from (uppers) by -1 to 1 while frp[i] = 0 do
        nz := nz + 1:
      od:
      frs := array(1 .. uppers - nz, [seq(frs[i], 
          i = 1 .. uppers - nz)]):
      frp := array(1 .. uppers - nz, [seq(frp[i], 
          i = 1 .. uppers - nz)]):
      fX[2] := convert(frs, list):
      fXRange := convert(frp, list):
      # print(fX[2]): # print(fXRange):
#
# PREVIOUS CODE FOR RANGE STAT WITH SUPPORT 1, 2, 3, ..., N
# FinalPDF[j] := FinalPDF[j] + Probs[k]:
# fX[2] := [seq(supp, supp = 0 .. N - 1)]:
# fXRange := array(1 .. N):
# fXRange[1] := sum((fX[1][j]) ^ n, j = 1 .. N):
# for w from 2 to N do
# fXRange[w] := (FX[1][w]) ^ n - 
# (FX[1][w] - FX[1][1]) ^ n -         
# (FX[1][w - 1]) ^ n  + 
# (FX[1][w - 1] - FX[1][1]) ^ n +  
# sum((FX[1][w + k] - FX[1][k]) ^ n - 
# (FX[1][w + k] - FX[1][k + 1]) ^ n -
# (FX[1][w + k - 1] - FX[1][k]) ^ n  + 
# (FX[1][w + k - 1] - FX[1][k + 1]) ^ n, 
# k = 1 .. N - w): 
# od:   
#
#  RV has formulaic PDF
#  Example:  X := [[x -> x/6], [1 .. 3], ["Discrete", "PDF"]];
#
#  DISCRETE/WITH REPLACEMENT/formulaic PDF
#
    else
      print(`Have not done range for w/ replacement, formulaic PDF`):
      return:
# Substitute Lo in fX, Lo + 1 in SX, and assign FX = 1
# fXOS1 := sum(binomial(n, w) * 1 * 
# ((subs(x = Lo, op(unapply(fX[1](x))(x)))) ^ (n - w))
# * (subs(x = Lo + 1, op(unapply(SX[1](x))(x))) ^ w), 
# w = 0 .. (n - r)): 
# fXOS1 := simplify(fXOS1):
# Substitute k - 1 in FX, k in fX, and k + 1 in SX
# fXOS2 := sum(sum(multinomial(n, u, n - u - w, w) * 
# (subs(x = k - 1, op(unapply(FX[1](x))(x))) ^ u) * 
# ((subs(x = k, op(unapply(fX[1](x))(x)))) ^ (n - u - w)) *
# (subs(x = k + 1, op(unapply(SX[1](x))(x))) ^ w), 
# w = 0 .. (n - r)), u = 0 .. r - 1):
# fXOS2 := simplify(fXOS2):
# Write the PDF in terms of x, instead of k
# fXOS2 := subs(k = x, fXOS2):
# Special fix for Possion RV
# if has(denom(fXOS2), GAMMA(x)) then
# fXOS2 := convert(fXOS2, factorial):
# fi:
# RealValue := subs(x = Lo, fXOS2):
# If fXOS1 is the same value as fXOS2 evaluated at x = Lo, then
# then combine fXOS1 and fXOS2 into one formula
# if ((evalb(evalf(RealValue, Digits + 2) = 
# evalf(fXOS1, Digits + 2))) or 
# evalb(simplify(RealValue) = fXOS1)) then
# fXOS := [unapply(fXOS2, x)]:
# fX[2]:= [Lo .. Hi]:
# else
# fXOS := [fXOS1, unapply(fXOS2, x)]: 
# fX[2] := [Lo, Lo + 1 .. Hi]:
# fi:
    fi:
#
#  If 3 arguments are provided and the 3rd argument is the string "wo",
#  then items are sampled *without replacement*
#
  elif ((nargs = 3) and is(indicator = "wo")) then
    Finite := true:
#
#  Determine if the random variable X has a formulaic PDF.  If it does 
#  and also has finite support, then call the procedure ConvertToNumeric
#  to convert its PDF and support to the standard APPL numeric list
#  format.  The conversion is necessary in order to have list inputs for
#  the procedures NextPermutation and NextCombination.
#
    if (formulaic) then
      if (is(Lo, infinity) or is(Hi, infinity)) then 
        Finite := false:
      else
        fX := ConvertToNumeric(fX):
        N := nops(fX[2]):
      fi:
    fi:
#
#  The random variable X has finite support
#
    if (Finite) then
      fX[2] := [seq(supp, supp = n - 1 .. N - 1)]:
#
#  Check that the sample size n is not greater than the population
#  size N. If it is, return an error message.
#
      if (n > N) then
        print(`ERROR(RangeStat): If sampling *without* replacement,`):
        print(`n CANNOT be larger than the population size`, N):
        return:
      fi:
#
#  Check that N >= 2, if not return a message stating that there is no
#  range 
#
      if (N < 2) then
        print(`ERROR(RangeStat): Population consists of 1 element`):
        print(`There is no range`):
        return:       
      fi:
#
#  Find the PDF of the range given that the support is finite and n = N 
#
      if is(n = N) then
        fXRange := array(1 .. 1):
        fXRange[1] := 1:
        fX[2] := [N - 1]:
#
#  If n = 2, 3, ... N - 1, create an array of size N - n to store the
#  range values x from 1 to N - n + 1. Initialize the array to contain
#  all zeros.
#
      else
        fXRange := array(1 .. N - 1):
        for j from 1 to N - 1 do
          fXRange[j] := 0:
        od:
        # Create the first lexicographical combination of n items
        combo := [seq(i, i = 1 .. n)]:
        for i from 1 to binomial(N, n) do
          # Assign perm as the current combo
          perm := combo:
#
#  Compute the probability of obtaining the given permutation, perm
#
          for j from 1 to n! do
            PermProb := fX[1][perm[1]]:
            cumsum := fX[1][perm[1]]:
            for m from 2 to n do
              PermProb := PermProb * fX[1][perm[m]] / (1 - cumsum):
              cumsum := cumsum + fX[1][perm[m]]:
            od:
#
#  Find the maximum and minimum elements of the permutation and then
#  determine their diference, the range. Store the permutation's
#  probability in the appropriate position in the range array.
#
            HiVal := max(op(perm)):
            LoVal := min(op(perm)):
            Range := HiVal - LoVal:
            flag := true:
            for k from 1 to N - 1 do
              if (Range = k) then
                fXRange[k] := PermProb + fXRange[k]:
              fi:
            od:
            # Find the next lexicographical permutation
            perm := NextPermutation(perm):
          od:
          # Find the next lexicographical combination
          combo := NextCombination(combo, N):
        od:
        fXRangeNoZeros := array(1 .. N - n + 1):
        index := 1:
        for k from 1 to N - 1 do
          if (fXRange[k] <> 0) then
            fXRangeNoZeros[index] := fXRange[k]:
            index := index + 1:
          fi:
        od:
        fXRange := fXRangeNoZeros:
      fi:
#
#  If X has infinite support, then at present, RangeStat is unable to
#  compute the range for infinite support without replacement cases. 
#
#  DISCRETE/INFINITE SUPPORT/WITHOUT REPLACEMENT
#
    else
      print(`ERROR(RangeStat): At present, RangeStat cannot`):
      print(`compute the range for this infinite support RV`):
      print(`in the without replacement case`):
      return:
    fi:
#
#  If 3 arguments are provided and the third one is not the string
#  "wo", then return an error message
#
  else
    print(`ERROR(RangeStat): The 3rd argument must be the string`):
    print(`*wo* to indicate items are drawn *without* replacement`):
    return:
  fi:
  fXRange := convert(fXRange, list):
fi:
#
#  Return the PDF of the rth order statistic in the list of sublists 
#  format
#
return([fXRange, fX[2], fX[3]]): 
end:

#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: rebuildheap1.map
#  
#  Procedure Name: RebuildHeap()
#
#  Other APPL Procedures Called: 
#
#  Date: September 17, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
RebuildHeap := proc(Root, size) 
global H, Mimic:
local RootValue, RootValueProb, RootValuePosition, Child:
# local size, RootItem:
# local NewH, Temp, NewArray, NewHeap:

#
#  If there are no elements in the heap except the sentinel 
#  (-1 * 10 ^ 6), then return the heap H as is, since it doesn't need
#  rebuilt
#
if (size = 1) then
  return:
fi:
# print(`Root is`, Root):
# print(`H is`, H):
# size := nops(convert(H, list)):
# print(`size is`, size):
RootValue := H[Root][1]:
RootValueProb := H[Root][2]:
RootValuePosition := Mimic[Root]:
#
#  Check that root is not a leaf 
#
if (2 * Root - 1 > size) then
  # print(`there are no children`):
  return:
#
#  Root must have a left child
#
else
  Child := 2 * Root - 1:
#
#  If there are 2 children and the right child's value is greater than
#  the left child's value, then update Child to be the right child
#
  if ((Child <> size) and (H[Child + 1][1] < H[Child][1])) then
    Child := Child + 1:
  else
    # print(`either no right child or right child not larger`):
  fi:
  if H[Child][1] < RootValue then
    H[Root] := H[Child]:
    Mimic[Root] := Mimic[Child]:
    H[Child][1] := RootValue:
    H[Child][2] := RootValueProb:
    Mimic[Child] := RootValuePosition:
    RebuildHeap(Child, size):
  fi:
fi:
return:

end:

#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: rebuildheapq11.map
#  
#  Procedure Name: RebuildHeapQ1()
#
#  Other APPL Procedures Called: 
#
#  Date: January 11, 2001
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
RebuildHeapQ1 := proc(Root, size) 
global Q1H, Q1Mimic:
local RootValue, RootValueProb, RootValuePosition, Child:

#
#  If there are no elements in the heap except the sentinel 
#  (-1 * 10 ^ 6), then return the heap Q1H as is, since it doesn't need
#  rebuilt
#
if (size = 1) then
  return:
fi:
RootValue := Q1H[Root][1]:
RootValueProb := Q1H[Root][2]:
RootValuePosition := Q1Mimic[Root]:
#
#  Check that root is not a leaf 
#
if (2 * Root - 1 > size) then
  return:
#
#  Root must have a left child
#
else
  Child := 2 * Root - 1:
#
#  If there are 2 children and the right child's value is greater than
#  the left child's value, then update Child to be the right child
#
  if ((Child <> size) and (Q1H[Child + 1][1] < Q1H[Child][1])) then
    Child := Child + 1:
  else
    # print(`either no right child or right child not larger`):
  fi:
  if Q1H[Child][1] < RootValue then
    Q1H[Root] := Q1H[Child]:
    Q1Mimic[Root] := Q1Mimic[Child]:
    Q1H[Child][1] := RootValue:
    Q1H[Child][2] := RootValueProb:
    Q1Mimic[Child] := RootValuePosition:
    RebuildHeapQ1(Child, size):
  fi:
fi:
return:

end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: rebuildheapq21.map
#  
#  Procedure Name: RebuildHeapQ2()
#
#  Other APPL Procedures Called: 
#
#  Date: January 11, 2001
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
RebuildHeapQ2 := proc(Root, size) 
global Q2H, Q2Mimic:
local RootValue, RootValueProb, RootValuePosition, Child:

#
#  If there are no elements in the heap except the sentinel 
#  (-1 * 10 ^ 6), then return the heap Q2H as is, since it doesn't need
#  rebuilt
#
if (size = 1) then
  return:
fi:
RootValue := Q2H[Root][1]:
RootValueProb := Q2H[Root][2]:
RootValuePosition := Q2Mimic[Root]:
#
#  Check that root is not a leaf 
#
if (2 * Root - 1 > size) then
  return:
#
#  Root must have a left child
#
else
  Child := 2 * Root - 1:
#
#  If there are 2 children and the right child's value is greater than
#  the left child's value, then update Child to be the right child
#
  if ((Child <> size) and (Q2H[Child + 1][1] < Q2H[Child][1])) then
    Child := Child + 1:
  else
    # print(`either no right child or right child not larger`):
  fi:
  if Q2H[Child][1] < RootValue then
    Q2H[Root] := Q2H[Child]:
    Q2Mimic[Root] := Q2Mimic[Child]:
    Q2H[Child][1] := RootValue:
    Q2H[Child][2] := RootValueProb:
    Q2Mimic[Child] := RootValuePosition:
    RebuildHeapQ2(Child, size):
  fi:
fi:
return:

end:#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: rebuildheapq31.map
#  
#  Procedure Name: RebuildHeapQ3()
#
#  Other APPL Procedures Called: 
#
#  Date: September 17, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
RebuildHeapQ3 := proc(Root, size) 
global Q3H, Q3Mimic:
local RootValue, RootValueProb, RootValuePosition, Child:
# local size, RootItem:
# local NewH, Temp, NewArray, NewHeap:

#
#  If there are no elements in the heap except the sentinel 
#  (-1 * 10 ^ 6), then return the heap Q3H as is, since it doesn't need
#  rebuilt
#
if (size = 1) then
  return:
fi:
# print(`Root is`, Root):
# print(`Q3H is`, Q3H):
# size := nops(convert(Q3H, list)):
# print(`size is`, size):
RootValue := Q3H[Root][1]:
RootValueProb := Q3H[Root][2]:
RootValuePosition := Q3Mimic[Root]:
#
#  Check that root is not a leaf 
#
if (2 * Root - 1 > size) then
  # print(`there are no children`):
  return:
#
#  Root must have a left child
#
else
  Child := 2 * Root - 1:
#
#  If there are 2 children and the right child's value is greater than
#  the left child's value, then update Child to be the right child
#
  if ((Child <> size) and (Q3H[Child + 1][1] < Q3H[Child][1])) then
    Child := Child + 1:
  else
    # print(`either no right child or right child not larger`):
  fi:
  if Q3H[Child][1] < RootValue then
    Q3H[Root] := Q3H[Child]:
    Q3Mimic[Root] := Q3Mimic[Child]:
    Q3H[Child][1] := RootValue:
    Q3H[Child][2] := RootValueProb:
    Q3Mimic[Child] := RootValuePosition:
    RebuildHeapQ3(Child, size):
  fi:
fi:
return:

end:

#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: rebuildheapq41.map
#  
#  Procedure Name: RebuildHeapQ4()
#
#  Other APPL Procedures Called: 
#
#  Date: September 17, 2000
#
#  Purpose: 
#
#  Arguments: 
#
#  Algorithm:
RebuildHeapQ4 := proc(Root, size) 
global Q4H, Q4Mimic:
local RootValue, RootValueProb, RootValuePosition, Child:
# local size, RootItem:
# local NewH, Temp, NewArray, NewHeap:

#
#  If there are no elements in the heap except the sentinel 
#  (-1 * 10 ^ 6), then return the heap Q4H as is, since it doesn't need
#  rebuilt
#
if (size = 1) then
  return:
fi:
# print(`Root is`, Root):
# print(`Q4H is`, Q4H):
# size := nops(convert(Q4H, list)):
# print(`size is`, size):
RootValue := Q4H[Root][1]:
RootValueProb := Q4H[Root][2]:
RootValuePosition := Q4Mimic[Root]:
#
#  Check that root is not a leaf 
#
if (2 * Root - 1 > size) then
  # print(`there are no children`):
  return:
#
#  Root must have a left child
#
else
  Child := 2 * Root - 1:
#
#  If there are 2 children and the right child's value is greater than
#  the left child's value, then update Child to be the right child
#
  if ((Child <> size) and (Q4H[Child + 1][1] < Q4H[Child][1])) then
    Child := Child + 1:
  else
    # print(`either no right child or right child not larger`):
  fi:
  if Q4H[Child][1] < RootValue then
    Q4H[Root] := Q4H[Child]:
    Q4Mimic[Root] := Q4Mimic[Child]:
    Q4H[Child][1] := RootValue:
    Q4H[Child][2] := RootValueProb:
    Q4Mimic[Child] := RootValuePosition:
    RebuildHeapQ4(Child, size):
  fi:
fi:
return:

end:

#1111111111222222222233333333334444444444555555555566666666667777777777
#
# ReduceList is a procedure that eliminates floating point redundancies
# (e.g., 3 vs. 3.0) from a sorted Maple list.
#
ReduceList := proc(LST :: list)
local i, size, delt, deltamin, ListIn:
deltamin := 0.0000001:
ListIn := LST:
size := nops(ListIn):
for i from (size - 1) by -1 to 1 do
  if (ListIn[i] <> -infinity and ListIn[i + 1] <> infinity) then
    delt := evalf(ListIn[i + 1]) - evalf(ListIn[i]):
    if (delt < deltamin) then
      if (whattype(ListIn[i]) <> float) then
        ListIn := subsop((i + 1) = NULL, ListIn):
      else
        ListIn := subsop(i = NULL, ListIn):
      fi:
    fi:
  fi:
od:
RETURN(ListIn):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: sf6.map
#
#  Procedure Name: SF(X, [x])
#
#  Other APPL Procedures Called: CDF, CHF, Convert, PDF, HF
#
#  Date: March 20, 2001
#
#  Purpose: SF is a procedure that: 
#           (1) Returns the survivor function of a random variable X in
#               the APPL list of 3 lists format if the only argument 
#               given is X, or
#           (2) Returns the value Pr(X > x) if it is given the optional
#               argument x in addition to the RV X
#
#  Arguments: X: A continuous or discrete random variable; 
#             x (optional argument): A numeric value entered when
#                trying to determine Pr(X > x)
#
#  Algorithm: 1. Perform error checking on user entered arguments
#             2. The SF of X is determined by sending it to its 
#                appropriate category, which is based on whether:
#                A. X is continuous or discrete
#                B. X is entered in its PDF, CDF, SF, HF, CHF, or IDF
#                   format 
#             3. If only 1 argument (the random variable X) is entered
#                by the user, return the survivor function of X in
#                the APPL list of 3 lists format 
#             4. If 2 arguments are provided, return the value Pr(X > x)
#
#  CAUTION: Made "x" local because assumption made on x in the discrete
#  dot HF case
#
SF := proc(X :: list(list), st)
local numlists, nsegments, SX, supp, FX, SSX, CHX, i, prob, Y, Range,
    lo, hi, incr, transf, fX, x, hf, chf, sf, idf, pieces, numops,
    noceil, ceilpiece, solns, nsolns, cdf, val, invfound, j, idfval,
    pdf, losupp, hisupp, sublist1, n, hX, notfound, count, k:
#
#  Check for the appropriate number of arguments
#
if ((nargs <> 1) and (nargs <> 2)) then
  print(`ERROR(SF): This procedure requires 1 or 2 arguments:`):
  print(`A random variable X and an optional argument x for`):
  print(`computing Pr(X > x)`):
  return:
fi:
#
#  Check that the RV X is in the list of 3 lists format
#
numlists := nops(X):
if (numlists <> 3) then
  print(`ERROR(SF): The RV X must be a list of 3 lists`):
  return:
fi:
#
#  Make sure X is given as a PDF, CDF, SF, HF, CHF, or IDF
#
if not(member(X[3][2], {"PDF", "CDF", "SF", "HF", "CHF", "IDF"})) then
  print(`ERROR(SF): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  return:
fi:
#
#  If the RV X is continuous, find and return the SF of X
#
if (X[3][1] = "Continuous") then
  nsegments := nops(X[1]):
  SX := []:
  supp := X[2]:
#
#  The RV X is given in its PDF, CDF, or IDF form
#
  if (X[3][2] = "PDF" or X[3][2] = "CDF" or X[3][2] = "IDF") then 
    if X[3][2] = "CDF" then
      FX := X:
    else
      FX := CDF(X):
      # IDF will change its support from X[2] to FX[2]
      supp := FX[2]:
    fi:
    for i from nsegments by -1 to 1 do
      SSX := unapply(1 - FX[1][i](x), x):
      # SX := [op(SX), unapply(simplify(SSX(x)), x)]:
      SX := [unapply(simplify(SSX(x)), x), op(SX)]:
    od:
#
#  The RV X is given in its SF form. Nothing needs to be done to X.
#
  elif X[3][2] = "SF" then
    SX := X[1]:
    supp := X[2]:
#
#  The RV X is given in its HF form
#
  elif (X[3][2] = "HF" or X[3][2] = "CHF") then
    if X[3][2] = "HF" then
      CHX := CHF(X):
    else
      CHX := X:
    fi:
    for i from 1 to nsegments do 
      SSX := unapply(exp(-CHX[1][i](s)), s):
      SX := [op(SX), unapply(simplify(SSX(x)), x)]: 
    od:
  fi:
#
#  Only 1 argument, X, given for the procedure
#
  if (nargs = 1) then
    return([SX, supp, ["Continuous", "SF"]]):
#
#  Two arguments, X and x, provided for the procedure
#
  elif (nargs = 2) then
    if not(type(evalf(st), {numeric, infinity})) then
      if nsegments = 1 then
        prob := SX[1](st):
        return(prob):
      else
        print(`ERROR(SF): Symbolic second arguments with a piecewise`):
        print(`SF are not allowable in APPL at this time`):
        return:
      fi:    
    fi:
    if (st <= evalf(supp[1])) then return(1):
    elif (st > evalf(supp[nsegments + 1])) then return(0): fi:
    for i from 1 to nsegments do 
      if ((evalf(st) > evalf(supp[i])) and (evalf(st) <= evalf(supp[i +
          1]))) then
        break:
      fi:
    od: 
    prob := SX[i](st):
    return(prob):
  fi:
#
#  If the RV X is discrete, find and return the SF of X
#
elif (X[3][1] = "Discrete") then
#
#  If the RV X is discrete, then call the procedure Convert(X) to
#  convert the discrete random variable's support to a standard APPL
#  discrete RV support format. Assign the converted random variable
#  to the Maple variable Y.
#
  Y := Convert(X):
  SX[1] := Y[1]:
  SX[2] := Y[2]:
#
# X has dot support
#
  if type(Y[2][1], range) then
    Range := Y[2][1]:
    lo := lhs(Y[2][1]):
    hi := rhs(Y[2][1]):
    if member(Y[3][2], {"PDF", "CDF", "SF", "HF", "CHF"}) then
      incr := Y[2][2]:
      transf := Y[2][3]:
#
#  Report the support of new random variable back to the user in its
#  simplest form
#
      if (incr = 1 and unapply(transf(x))(x) = x) then
        SX[2] := [Range]:
#
#  APPL is not programmed to convert to a PDF format when the increment
#  is not 1 and/or the transformation is not x -> x
#
      elif not(incr = 1 or unapply(transf(x))(x) = x) then
        print(`ERROR(SF): APPL is currently unable to evaluate`):
        print(`this RV`):
        return:
      fi:
    fi:
#
#  If X is given in its PDF form
#
    if (Y[3][2] = "PDF") then
      # fX := PDF(X):
      # SX[1] := [unapply(1 - sum(op(unapply(fX[1](w))(w)), w = lo .. 
      # x - 1), x)]:
      # print(`old way`, SX[1]):
      SX[1] := [unapply(sum(op(unapply(Y[1](w))(w)), w = x .. hi), x)]:
#
# If X is given in its CDF form
#
    elif (Y[3][2] = "CDF") then
      SX[1] := [unapply(1 - (op(unapply(Y[1](x))(x))), x)]:
#
#  The RV X is given in its SF form, then nothing needs to be done to X.
#
    elif (Y[3][2] = "SF") then 
#
#  The RV X is given in its HF form
#
    elif (Y[3][2] = "HF") then
      hf := unapply(op(Y[1])(w))(w):
      # The following assumption is made since the following product
      # may return an expression containing the GAMMA function, and we
      # want Maple to simplify the expression knowing the conditions
      # on the support of the random variable
      # SX[1] := [unapply(simplify(product(1 - hf, 
      #    w = lo .. (x - 1))), x)]:
      # print(`before assumption`):
      # print(SX[1]):
      # assume(x < hi):
      SX[1] := [unapply(simplify(product(1 - hf, 
          w = lo .. (x - 1))), x)]:
#
#  If X is given in its CHF form
#
    elif (Y[3][2] = "CHF") then
      chf := unapply(op(Y[1])(x))(x):
      sf := exp(-chf):
      SX[1] := [unapply(sf, x)]:
#
#  If X is given in its IDF form
#
    elif (Y[3][2] = "IDF") then
      # need to look for a ceil function here!
      idf := unapply(op(Y[1])(y))(y):
      # print(`idf is`, idf):
      # print(`[op(idf)] is`, [op(idf)]):
      pieces := [op(idf)]:
      numops := nops(pieces):
      # print(numops):
      noceil := true:
      for i from 1 to numops while noceil do
        if has(pieces, ceil) then
          # print(`has ceil`):
          noceil := false:
          ceilpiece := i:
        fi:
      od:
      if not(noceil) then
        # print(pieces[ceilpiece]):
        pieces[ceilpiece] := op(pieces[ceilpiece]):
        idf := sum(pieces[k], k = 1 .. numops):
      fi:
      solns := [solve(idf = x, y)]:
      # print(solns):
      nsolns := nops(solns):
      # Find the correct inverse
      if (nsolns = 1) then 
        # If there is only one inverse, assign it to cdf.
        cdf := solns[1]:
      else
        if lo = -infinity then
          if hi = infinity then
            val := 0:
          else 
            val := hi:
          fi: 
        else
          val := lo:  
        fi:   
        # print(`val is`, val):
        invfound := false:
        for j from 1 to nsolns do 
          # Evaluate each inverse of the IDF at the value "val" assigned
          # above. If CDF(IDF(val)) = val, then assign idf equal to that
          # inverse. 
          idfval := subs(x = val, idf):
          if evalf(subs(x = idfval, solns[j])) = evalf(val) then
            cdf := solns[j]:
            invfound := true:
            break:
          fi: 
        od:
        if not(invfound) then       
          print(`ERROR(SF): Could not find the appropriate inverse`):
        fi:  
      fi:
      pdf := simplify(subs(x = w, cdf) - subs(x = w - 1, cdf)):
      SX[1] := [unapply(1 - sum(pdf, w = lo .. x - 1), x)]:
#  CAUTION: losupp is incorrect in some cases -- currently don't know
#  how to fix this, need to be able to retrieve the first cdf value and
#  sub it into idf as lo
      losupp := evalf(subs(y = lo, idf)):
      hisupp := evalf(subs(y = hi, idf)): 
      SX[2] := [losupp .. hisupp]:
    fi:
#
#  X has no dot support
#
  else
    sublist1 := SX[1]:
    n := nops(sublist1):
#
#  If X is given in its PDF form, 
#
    if (Y[3][2] = "PDF") then
      n := nops(SX[2]):
      FX := CDF(Y):
      SX[1][1] := 1:
      for i from 2 to n do 
        SX[1][i] :=  1 - FX[1][i - 1]:
      od:
#
#  If X is given in its CDF form,
#
    elif (Y[3][2] = "CDF") then
      SX[1][1] := 1:
      for i from 2 to n do
        SX[1][i] := 1 - sublist1[i - 1]:
      od:
#
#  If X is given in its SF form, then nothing needs to be done to X.
#
    elif (Y[3][2] = "SF") then 
#
#  If X is given in its HF form
#
    elif member(Y[3][2], {"HF", "CHF"}) then
      SX[1][1] := 1:
      hX := HF(Y):
      for i from 2 to n do
        SX[1][i] := SX[1][i - 1] * (1 - hX[1][i - 1]):
      od:
#
#  If X is given in its IDF form
#
    elif (Y[3][2] = "IDF") then
      FX := CDF(Y):
      sublist1 := FX[1]:
      SX[2] := FX[2]:
      SX[1][1] := 1:
      for i from 2 to n do
        SX[1][i] := 1 - sublist1[i - 1]:
      od:
    fi:
  fi:
#
#  Only 1 argument, X, given for the procedure
#
  if (nargs = 1) then
    return([SX[1], SX[2], ["Discrete", "SF"]]):
#
#  Two arguments, X and x, provided for the procedure
#
  elif (nargs = 2) then
    if type(Y[2][1], range) then
      prob := op(SX[1](st)): 
    else
      prob := 0:
      notfound := true:
      count := 1:
      for k from 1 to n while notfound do
        if evalf(SX[2][k]) = evalf(st) then
          notfound := false:
          prob := SX[1][count]: 
        fi:
        count := count + 1:
      od:
    fi:
    return(prob):
  fi:
#
#  X is neither continuous nor discrete
else
  print(`ERROR(SF): The random variable X must be continuous or`):
  print(`discrete`):
fi:
end:#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: skewness2.map
#  Rewriting E[((X - mu) / sigma) ^ 3]
#
#  Procedure Name: Skewness(X)
#
#  Other APPL Procedures Called: 
#
#  Updated: June 30, 2000
#
#  Purpose: Returns the skewness
#
#  Arguments: X: Random Variable
# 
#  Algorithm:
Skewness := proc(X :: list(list))
local mu, sigma, Term1, Term2, Term3, skew:

mu := Mean(X):
sigma := sqrt(Variance(X)):
Term1 := ExpectedValue(X, x -> x ^ 3):
Term2 := 3 * mu * ExpectedValue(X, x -> x ^ 2):
Term3 := 2 * mu ^ 3:
skew := (Term1 - Term2 + Term3) / sigma ^ 3:
RETURN(skew):
end:
#11111111112222222222333333333344444444445555555555666666666677777777778888888888#
#  Filename: stealth1.map
#  
#  Procedure Name: Stealth
#
#  Other APPL Procedures Called: ExpectedValue, NormalRV, UniformRV, Variance 
#
#  Date:  June 7, 1999
#
#  Purpose: Stealth for E(X, g), N(mu, sigma), U(a, b), V(X)
#
E := proc(X, g)
local mean:

mean := ExpectedValue(X, g):
RETURN(mean):
end:

N := proc(mu, sigma)
local ListOfLists:

ListOfLists := NormalRV(mu, sigma):
RETURN(ListOfLists):
end:

U := proc(a, b)
local ListOfLists:

ListOfLists := UniformRV(a, b):
RETURN(ListOfLists):
end:

V := proc(X)
local variance:

variance := Variance(X):
RETURN(variance):
end:

#11111111112222222222333333333344444444445555555555666666666677777777778888888888#
# ReduceList is a procedure that eliminates floating point redundancies
# (e.g., 3 vs. 3.0) from a sorted Maple list.
#
ReduceList := proc(LST)
local i, size, delt, deltamin, ListIn:
deltamin := 0.0000001:

ListIn := LST:
size := nops(ListIn):
for i from (size - 1) by -1 to 1 do
  if (ListIn[i] <> -infinity and ListIn[i + 1] <> infinity) then
    delt := evalf(ListIn[i + 1]) - evalf(ListIn[i]):
    if (delt < deltamin) then
      if (whattype(ListIn[i]) <> float) then
        ListIn := subsop((i + 1) = NULL, ListIn):
      else
        ListIn := subsop(i = NULL, ListIn):
      fi:
    fi:
  fi:
od:
return(ListIn):
end:
#
#11111111112222222222333333333344444444445555555555666666666677777777778888888888#3:06 PM 3/11/2008
# Procedure Transform finds the pdf of Y = g(X), where X and Y are
# random variables.  The arguments are f(x), the pdf of X, and g(X), the
# transformation.  The arguments of Transform and the returned value are
# in the list-of-sublists format.
#
Transform := proc(X, gX)
local nx, XStarSet, ng, XStarList, n, FF, i, k, c, fXc, BEGIN, END, gndx, j, mn, Mx, a,
      b, YStarSet, YStarList, m,  ffY, y, h, ntmp, temp, gtemp, ii, t, itp, ginv, fY:

if (X[3][1] = "Discrete") then
  return(TransformDiscrete(X, gX)):
else

assume(y, real):
fXc := PDF(X):
nx := nops(fXc[2]):
XStarSet := {op(fXc[2])}:

ng := nops(gX[2]):
for i from 1 to ng do
  if (evalf(gX[2][i]) > evalf(fXc[2][1]) and evalf(gX[2][i]) < evalf(fXc[2][nx]))
      then
    XStarSet := XStarSet union {gX[2][i]}
  fi:
od:

XStarList := sort([op(XStarSet)], (x, y) -> evalb(evalf(x) < evalf(y))):
XStarList := ReduceList(XStarList):
n := nops(XStarList) - 1:
 #print(`XStartList is`, XStarList): #####

FF := array(1 .. n):

# Find the appropriate index k of fXc[1][k] for each x interval.
for i from 1 to n do
  for k from 1 to nx do
    if (evalf(XStarList[i]) >= evalf(fXc[2][k])) then
      FF[i] := k:
    fi:
  od:
od:
 #print(`FF is`, FF): ######

c := array(1 .. n):

if (XStarList[1] = -infinity and XStarList[2] = infinity) then
  c[1] := 0
else
  BEGIN := 1:
  END := n:
  if (XStarList[1] = -infinity) then
    c[1] := XStarList[2] - 1:
    BEGIN := 2:
  fi:
  if (XStarList[n + 1] = infinity) then
    c[n] := XStarList[n] + 1:
    END := n - 1:
  fi:
  for i from BEGIN to END do
    c[i] := (XStarList[i] + XStarList[i + 1]) / 2:
  od:
fi:
 #print(`c is`, c): ####

ng := nops(gX[1]):
gndx := array(1 .. n):

# Find the appropriate index j of gX[1][j] for each x interval.
for i from 1 to n do
  for j from 1 to ng do
    if (evalf(XStarList[i]) >= evalf(gX[2][j]) and evalf(XStarList[i]) < 
        evalf(gX[2][j + 1])) then
      gndx[i] := j:
      break:
    fi:
  od:
od:
 #print(`gndx is`, gndx):  ####

mn := array(1 .. n):
Mx := array(1 .. n):
for i from 1 to n do
  a := limit(gX[1][gndx[i]](x), x = XStarList[i], right):
  b := limit(gX[1][gndx[i]](x), x = XStarList[i + 1], left):
  mn[i] := min(a, b):
  Mx[i] := max(a, b):
od:
 #print(`mn is`, mn): ####
 #print(`Mx is`, Mx): ####
YStarSet := {seq(mn[i], i = 1 .. n), seq(Mx[i], i = 1 .. n)}:
YStarList := sort([op(YStarSet)], (x, y) -> evalb(evalf(x) < evalf(y))):
YStarList := ReduceList(YStarList):
m := nops(YStarList) - 1:
 #print(`YStarList is`, YStarList):  ####

ffY := []:
for j from 1 to m do
  h := 0:
  for i from 1 to n do
# If working with a relevant transformation segment, adjust the pdf.
    if (evalf(mn[i]) <= evalf(YStarList[j]) and evalf(YStarList[j + 1]) <= 
        evalf(Mx[i])) then
      temp := [solve(gX[1][gndx[i]](t2) = y, t2)]:
       #print(`temp is`, temp): #####
      ntmp := nops(temp):
      gtemp := array(1 .. ntmp):
       #print(`gtemp is`, gtemp): #####
      for ii from 1 to ntmp do
        gtemp[ii] := unapply(temp[ii], y):
      od:
       #print(`numtemp is`, ntmp): #####
      if (ntmp = 1) then
        # If there is only one inverse, assign it to ginv.
        ginv := gtemp[1](y):
      else
        # If there is more than one inverse, find the appropriate one.
        for t from 1 to ntmp do
          # Evaluate each inverse of the transformation at the midpoint of the
          # subinterval.  Set ginv to that inverse for which gtemp(g(x)) = x.
          itp := evalf(gtemp[t](gX[1][gndx[i]](evalf(c[i])))):
          if (itp > evalf(XStarList[i]) and itp < evalf(XStarList[i + 1])) then
            ginv := gtemp[t](y):
            break:
          else
            ginv := notfound:
          fi:
        od:
        if (ginv = notfound) then
           print(`ERROR, GINVERSE not found`):
        fi:
      fi:

      # For the case of an increasing transformation segment, add the change.
      if (evalf(limit(gX[1][gndx[i]](xx), xx = XStarList[i], right)) 
            < evalf(limit(gX[1][gndx[i]](xx), xx = XStarList[i + 1], left))) then
        # print(`increasing transformation segment`):
        h := h + fXc[1][FF[i]](ginv) * diff(ginv, y):
      # For the case of a decreasing transformation segment, subtract the change.
      else
        h := h - fXc[1][FF[i]](ginv) * diff(ginv, y):
        # print(`decreasing transformation segment`):
      fi:
      # print(`h is`, h):
    fi:
  od:
  ffY := [op(ffY), op([unapply(simplify(h), y)])]:
od: 
RETURN([ffY, [op(YStarList)], ["Continuous", "PDF"]]):
fi:
end:

#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: transformdiscrete1.map
#
#  Procedure Name: TransformDiscrete(X, gX)
#
#  Other APPL Procedures Called: 
#
#  Date: June 7, 2001
#
#  Purpose: TransformDiscrete finds the PDF of Y = g(X), where X and Y
#           are discrete random variables.  The arguments are X, a 
#           discrete random variable, and g(X), the transformation.
#
#  Arguments: X, gX
#
#  Algorithm:
#
TransformDiscrete := proc(X, gX)
local fX, formulaic, lo, hi, incr, transf, N, nx, XStarSet, ng, i,
    XStarList, n, gndx, j, gx, pdfsupp, sortedf, fY, ysupp, k, nz, c,
    BEGIN, END, mn, Mx, a, b, YStarSet, YStarList, m, h, temp, ntmp,
    gtemp, t, ii, ginv, itp:

# Convert X to its PDF representation
fX := PDF(X):
# Convert fX to its standard APPL discrete list-of-sublists format
fX := Convert(fX):
if (fX = false) then
  print(`ERROR(Transform): Discrete RV X is NOT in legal APPL form`):
  return:
fi:
# fX has a standard discrete Dot format
if type(fX[2][1], range) then
  formulaic := true:
  lo := lhs(fX[2][1]):
  hi := rhs(fX[2][1]):
  XStarSet := {lo, hi}:
  incr := fX[2][2]:
  transf := fX[2][3]:
  if type(hi, symbol) then
    if not(evalb(hi = infinity)) then
      print(`ERROR(Transform): RV's support must be numeric`):
      return:
    fi:
    if type(lo, symbol) or evalb(lo = -infinity) then 
      print(`ERROR(Transform): RV's lower support must be`):
      print(`a finite numerical value.`): 
      return:
    fi:
  fi:
else
  # print(`NoDot format`):
  N := nops(fX[2]):
  lo := fX[2][1]:
  hi := fX[2][N]:
  XStarSet := {op(fX[2])}:
  formulaic := false:
fi:
ng := nops(gX[2]):
# print(ng):


# print(`fX is`, fX):
# ASSUME (FOR NOW) THAT ALL DISCRETE PDFs ARE IN ONE PIECE
# FF := array(1 .. n):
# Find the appropriate index k of fX[1][k] for each x interval.
# for i from 1 to n do
#   for k from 1 to nx do
#     if (evalf(XStarList[i]) >= evalf(fX[2][k])) then
#       FF[i] := k:
#     fi:
#   od:
# od:

# fX is in the standard discrete NoDot format
if not(formulaic) then
  # print(`made it`):
  for i from 1 to ng do
    # print(`made it inside for loop -- what's happening`):
    # print(gX[2][i]):
    # print(fX[2][1]): 
    # print(fX[2][N]):
    if (evalf(gX[2][i]) > evalf(fX[2][1]) and 
        evalf(gX[2][i]) < evalf(fX[2][N])) then
      XStarSet := XStarSet union {gX[2][i]}:
    fi:
  od:
  # print(`made it`):
  XStarList := sort([op(XStarSet)], (x, y) -> evalb(evalf(x) < 
      evalf(y))):
  # print(`where's the problem?`):
  XStarList := ReduceList(XStarList):
  n := nops(XStarList):
  # print(`XStartList is`, XStarList):
  ng := nops(gX[1]):
  gndx := array(1 .. n):
  # Find the appropriate transformation function for each support value
  # of the PDF
  for i from 1 to n do
    for j from 1 to ng do
      if (evalf(XStarList[i]) > evalf(gX[2][j]) and 
          evalf(XStarList[i]) <= evalf(gX[2][j + 1])) then
        gndx[i] := j:
        break:
      fi:
    od:
  od:
  # print(`gndx is`, gndx):
  gx := []:
  for i from 1 to ng do
    gx := [op(gx), unapply(gX[1][i](x))(x)]:
  od:
  # print(`gx is`, gx):
  # Substitute each support value into the correct transformation
  # function (as determined above)
  # print(`fX before transforming`, fX):
  pdfsupp := array(1 .. N):
  for i from 1 to N do
    pdfsupp[i] := simplify(subs(x = fX[2][i], gx[gndx[i]])):
    # fX[2][i] := simplify(subs(x = fX[2][i], gx[gndx[i]])):
  od:
  # print(`pdfsupp after transforming`, pdfsupp):
  fX[2] := convert(pdfsupp, list):
  sortedf := InsertionSort(fX[2], fX[1]):
  # print(`sorted f is`, sortedf):
  fX[2] := sortedf[1]:
  fX[1] := sortedf[2]:
  # print(`fx[1] is`, fX[1]):
  # print(`fx[2] is`, fX[2]):
# Build final transform support (fY) and final transform probability 
# values (ysupp)--initialize them to contain all zeroes
  fY := array(sparse, 1 .. N, sparse, []):
  ysupp := array(sparse, 1 .. N, sparse, []):
# Remove redundancies from transform support list.  Place the first
# transform support and probability values in the first position in the
# fY and ysupp arrays
  ysupp[1] := fX[2][1]:
  fY[1] := fX[1][1]:
  k := 2:
  j := 1:
  while (k <= N) do
    if evalf(fX[2][k]) <> evalf(fX[2][k - 1]) then
      j := j + 1:
      ysupp[j] := fX[2][k]:
    fi:
    fY[j] := fY[j] + fX[1][k]:
    k := k + 1:
  od:
# print(ysupp): # print(fY):
#
# Remove extraneous zeros from fY and ysupp. We know the zeros (if any)
# at the end of the fY array are not probability values.  They exist
# because of the identical values in fX[2].  Use fY to determine how
# many extraneous zeros exist, and reconstruct ysupp and fY so the extra
# zeros are not included as part of the arrays.
#
  nz := 0:
  for i from N by -1 to 1 while fY[i] = 0 do
    nz := nz + 1:
  od:
  ysupp := array(1 .. N - nz, [seq(ysupp[i], i = 1 .. N - nz)]):
  fY := array(1 .. N - nz, [seq(fY[i], i = 1 .. N - nz)]):
  ysupp := convert(ysupp, list):
  fY := convert(fY, list):
  # print(ysupp): # print(fY):
# fX is in the standard discrete Dot format
else
#  For $Dot$ case, c not
#  needed for *every* subinterval
#  ... check the endpoints -- think about this after
#  finding g or ginv (?)
  # print(`lo is`, lo):
  # print(`hi is`, hi):
  # print(`incr is`, incr):
  # print(`transf is`, transf):
  # APPL can only transform this discrete random variable if transf is
  # x -> x and incr is 1
  if is(unapply(transf(x))(x) = x) and is(incr = 1) then
    fY := []:
    for i from 1 to ng do
      if (evalf(gX[2][i]) > evalf(lo) and 
          evalf(gX[2][i]) < evalf(hi)) then
        XStarSet := XStarSet union {gX[2][i]}
      fi:
    od:
    XStarList := sort([op(XStarSet)], (x, y) -> evalb(evalf(x) < 
        evalf(y))):
    XStarList := ReduceList(XStarList):
    n := nops(XStarList) - 1:
    # print(`XStartList is`, XStarList):
    # Determining c to use later to check for the appropriate inverse
    c := array(1 .. n):
    if (XStarList[1] = -infinity and XStarList[2] = infinity) then
      c[1] := 0
    else
      BEGIN := 1:
      END := n:
      if (XStarList[1] = -infinity) then
        c[1] := XStarList[2] - 1:
        BEGIN := 2:
      fi:
      if (XStarList[n + 1] = infinity) then
        c[n] := XStarList[n] + 1:
        END := n - 1:
      fi:
      for i from BEGIN to END do
        c[i] := (XStarList[i] + XStarList[i + 1]) / 2:
      od:
    fi:
    # print(`c is`, c):
    ng := nops(gX[1]):
    gndx := array(1 .. n):
    # Find the appropriate transformation function for each support
    # value of the PDF
    for i from 1 to n do
      for j from 1 to ng do
        if (evalf(XStarList[i]) >= evalf(gX[2][j]) and 
            evalf(XStarList[i]) < evalf(gX[2][j + 1])) then
          gndx[i] := j:
          break:
        fi:
      od:
    od:
    # print(`gndx is`, gndx):
    gx := []:
    for i from 1 to ng do
      gx := [op(gx), unapply(gX[1][i](x))(x)]:
    od:
    # print(`gx is`, gx):

    ysupp := []:
    for i from 1 to n do
      ysupp := [op(ysupp), XStarList[i] .. XStarList[i + 1], 
          unapply(gx[gndx[i]], x)]:
    od:

    mn := array(1 .. n):
    Mx := array(1 .. n):
    for i from 1 to n do
      a := limit(gX[1][gndx[i]](x), x = XStarList[i], right):
      b := limit(gX[1][gndx[i]](x), x = XStarList[i + 1], left):
      mn[i] := min(a, b):
      Mx[i] := max(a, b):
    od:
    # print(mn):
    # print(Mx):
    YStarSet := {seq(mn[i], i = 1 .. n), seq(Mx[i], i = 1 .. n)}:
    YStarList := sort([op(YStarSet)], (x, y) -> evalb(evalf(x) < 
        evalf(y))):
    YStarList := ReduceList(YStarList):
    m := nops(YStarList) - 1:
    # print(`Let's see if YStar list helps us`):
    # print(`YStarList is`, YStarList):
    # print(`m is`, m):
    for j from 1 to m do
      h := 0:
      # assume(y, real):
      # print(`n is`, n):
      for i from 1 to n do
      # If we are working with a relevant transformation segment, 
      # adjust the pdf -- WHAT DOES THIS MEAN?
        if (evalf(mn[i]) <= evalf(YStarList[j]) and 
            evalf(YStarList[j + 1]) <= evalf(Mx[i])) then
          # print(`i is`, i):
          # print(`j is`, j):
          temp := [solve(gX[1][gndx[i]](t2) = y, t2)]:
          temp := subs(y = x, temp):
          # print(`temp is`, temp):
          ntmp := nops(temp):
          # print(`ntmp is`, ntmp):
          gtemp := array(1 .. ntmp):
          # print(`gtemp is`, gtemp):
          for ii from 1 to ntmp do
            gtemp[ii] := unapply(temp[ii], x):
          od:
          # print(`gtemp is`, gtemp):
          # If there is only one inverse, assign it to ginv.
          if (ntmp = 1) then
            ginv := gtemp[1](x):
            # print(`only one inverse`):
            # print(`ginv is`, ginv):
            # If there is more than one inverse, find the appropriate
            # one.
          else
            for t from 1 to ntmp do
              # Evaluate each inverse of the transformation at the
              # midpoint of the subinterval.  Set ginv to that inverse
              # for which gtemp(g(c)) = c.
              itp := evalf(gtemp[t](gX[1][gndx[i]](evalf(c[i])))):
              if (itp > evalf(XStarList[i]) and 
                itp < evalf(XStarList[i + 1])) then
                ginv := gtemp[t](x):
                break:
              else
                ginv := notfound:
              fi:
            od:
            if (ginv = notfound) then
              print(`ERROR, GINVERSE not found`):
            fi:
          fi:
          # print(`ginv is`, ginv):
          # print(fX[1](ginv)):
          # ffY := unapply(op(fX[1](ginv)), y):
          # print(ffY):
# For the case of an increasing transformation segment, add
# the change. (FREUND, page 245)
# if (evalf(limit(gX[1][gndx[i]](xx), xx = XStarList[i], right)) 
# < evalf(limit(gX[1][gndx[i]](xx), xx = XStarList[i + 1],
# left))) then
# print(`increasing transformation segment`):
# h := h + fX[1](ginv) * diff(ginv, y):
# For the case of a decreasing transformation segment,
# subtract the change.  (FREUND, page 245)
# else
# print(`decreasing transformation segment`):
# h := h - fX[1](ginv) * diff(ginv, y):
# fi:
# print(`h is`, h):

        fi:
        fY := [op(fY), unapply(op(fX[1](ginv)), x)]:
      od:
    od: 
    # print(`fY is`, fY):
    # If transf is not x -> x or incr is not 1, then APPL cannot do this
    # type of problem at this time
  else
    print(`ERROR(Transform): APPL is unable to perform the`):
    print(`transformation on this type of RV at this time`):
    return:  
  fi:
fi:
return([fY, ysupp, ["Discrete", "PDF"]]):
end:

#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: truncate13.map
#
#  Procedure Name: Truncate(X, a, b)
#
#  Other APPL Procedures Called: PDF, CDF 
#
#  Date: March 16, 1999
#
#  Purpose: Truncates a random variable X on the left by a and on the   
#           right by b. 
#
#  Arguments: X: Random Variable 
#             a, b: Truncation Points
# 
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Check that the RV X is in the list of 3 lists format
#    3.  Convert X to PDF form if not already in that form
#    4.  Check that the truncation pts are numeric
#    5.  Check that the RV supports are numeric
#    6.  Check that lower truncation pt 'a' is less than upper 
#        truncation pt 'b'
#    7.  Check that lower truncation pt 'a' is less than upper 
#        support of RV X
#    8.  If 'a' is less than the min value of support, reset 
#        lower truncation pt 'a' to minimum value of support 
#    9.  If 'b' is greater than the max value of support, reset 
#        upper truncation pt 'b' to maximum value of support 
#    10. Find out which segments of the PDF contain the 
#        truncation pts a and b
#    11. Compute CDF(b) - CDF(a)
#    12. Check for CDF(b) - CDF(a)= 0: if so, treat as a 
#        special case
#    13. Compute and return the truncated RV's support list
#    14. Compute and return the truncated PDF in the list of 
#        3 lists format
#                                                                             
Truncate := proc(X :: list(list), a :: {numeric, infinity}, 
            b :: {numeric, infinity})
local NumLists, fX, nsegments, beginseg, Digittemp, endingseg, 
i, low, high, FXlow, FXhigh, area, newnsegments, newsuppset, 
newsupplist, piecefX, fXnew:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 3) then
  print(`ERROR(Truncate): This procedure requires 3 arguments:`):
  print(`A random variable, lower truncation pt, and upper truncation pt`):
  RETURN():
fi:
#
#  Check that the RV X is in a list-of-lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(Truncate): The RV X must be in a list of 3 lists format`):
  RETURN():
fi:
#
#  Convert X to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
    fX := X:
elif ((X[3][2] = "CDF") or
      (X[3][2] = "CHF") or
      (X[3][2] = "HF") or
      (X[3][2] = "IDF") or
      (X[3][2] = "SF")) then
    fX := PDF(X):
else
  print(`ERROR(Truncate): RV must be given as`):
  print(`CDF, CHF, HF, IDF, PDF, or SF`):
  RETURN():
fi:
#
#  Check that the truncation pts are numeric
#
if ((type(a, symbol) and not(type(a, infinity))) or
    (type(b, symbol) and not(type(b, infinity)))) then
  print(`ERROR(Truncate): Must specify numeric values for the truncation pts`):
  RETURN():
fi:
#
#  Check that the RV supports are numeric
#
nsegments := nops(fX[1]):
beginseg := 1:
endingseg := nsegments:
for i from beginseg to (endingseg + 1) do
  if (type(evalf(fX[2][i]), symbol) and not(type(evalf(fX[2][i]), infinity))) then
    print(`ERROR(Truncate):  Must specify numeric values for supports of RV X`):
    RETURN():
  fi:
od:
#
#  Check that lower truncation pt 'a' is less than upper truncation pt 'b'
#
if (evalf(b) <= evalf(a)) then
  print(`ERROR(Truncate): Illegal truncation points`):
  print(`Lower truncation pt a must be less than upper truncation pt b`):
  RETURN():
fi:
#
#  Check that lower truncation pt 'a' is less than upper support of RV X
#
if (evalf(a) >= evalf(fX[2][nsegments + 1])) then
  print(`ERROR(Truncate): Illegal truncation points`):
  print(`Lower truncation pt a must be less than upper support of RV X`):
  RETURN():
fi:
#
#  If 'a' is less than the min value of support, reset lower 
#  truncation pt 'a' to minimum value of support 
#
low := a:
high := b:
if (evalf(low) < evalf(fX[2][1])) then
  print(`WARNING(Truncate): Lower truncation pt less than lower support of RV`):
  print(`Resetting lower truncation point to minimum value of support`):
  low := fX[2][1]:
fi:
#
#  If 'b' is greater than the max value of support, reset upper 
#  truncation pt 'b' to maximum value of support 
#
if (evalf(high) > evalf(fX[2][nsegments + 1])) then
  print(`WARNING(Truncate): Upper trunc pt greater than upper support of RV`):
  print(`Resetting upper truncation point to maximum value of support`):
  high := fX[2][nsegments + 1]:
fi:
#
#  Find out which segments of the PDF contain the truncation pts a and b
#
for i from 1 to nsegments do 
  if ((evalf(low) >= evalf(fX[2][i])) and (evalf(low) < evalf(fX[2][i + 1]))) then
    beginseg := i:
    break:
  fi:
od:
for i from 1 to nsegments do 
  if ((evalf(high) > evalf(fX[2][i])) and (evalf(high) <= evalf(fX[2][i + 1])))    
    then
    endingseg := i:
    break:
  fi:
od:
#
#  Compute CDF(b) - CDF(a)
#
#print(`digits are currently`, Digits);
Digittemp:=Digits;
Digits:=40;
#print(`digits are changed to`,Digits);

FXlow := CDF(fX, low):
FXhigh := CDF(fX, high):
area := simplify(FXhigh - FXlow):
#
#  Check for CDF(b) - CDF(a)= 0: if so, treat as a special case
#
if is(area = 0) then
  if is(beginseg = endingseg) then
    print(`ERROR(Truncate): The pdf on this truncated interval is 0`):
    print(`Truncation points `, low, ` and `, high, ` do not work`):
    RETURN():
  else
    area := FXlow:
  fi:
fi:   
Digits:=Digittemp;
#print(`Digits are now`, Digits);
#
#  Compute the truncated RV's support list; newsuppset was added to truncate13.map
#  because Maple "sort" command does NOT order a list with infinity in it properly
#  Ex.  > sort([-3, 2, -10, 1/2, infinity, 2.5]) 
#                            yields --> [infinity, -10, 2, -3, 2.5, 1/2];
#       > sort([-3, 2, -10, 1/2, 2.5]) yields --> [-10, -3, 1/2, 2, 2.5]
#  Also, "sort" works with lists, not sets; but "minus" works on sets
#
newnsegments := endingseg - beginseg + 1:
newsuppset := {low, high}:
for i from beginseg to (endingseg - 1) do
  newsuppset := {op(newsuppset), fX[2][i + 1]}:
od:
if member(infinity, newsuppset) then
  newsuppset := newsuppset minus {infinity}:
  newsupplist := [op(sort([op(newsuppset)])), infinity]:
else
  newsupplist := sort([op(newsuppset)]):
fi:
#
#  Compute and return the truncated PDF in the list of 3 lists format
#
fXnew[1] := []:
for i from beginseg to endingseg do
  piecefX := unapply(simplify(fX[1][i](x) / area), x): 
  fXnew[1] := [op(fXnew[1]), op([unapply(piecefX(x), x)])]:
od:
# fXnew[2] := [low, high]:
fXnew[3] := ["Continuous", "PDF"]:
RETURN([[op(fXnew[1])], newsupplist, fXnew[3]]):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777#  
#  Filename: uniformvariate1.map
#
#  Procedure name: UniformVariate()
#
#  Other APPL Procedures Called: None
#             
#  Date Revised: August 29, 1999
#
#  Purpose: UniformVariate generates a standard uniform variate 
#
#  Arguments: None
#
#  Note: With no arguments, the call rand() returns a 12 digit non-negative random
#        integer. 
# 
UniformVariate := proc()
local Variate:

Variate := evalf(rand()/10 ^ 12):
RETURN(Variate):

end:
#11111111112222222222333333333344444444445555555555666666666677777777778888888888#
#  Filename: valid2.map
#
#  NOTES:  
#  Discrete Cases:
#  (I)  dotdot cases
#       (a) incremented by 1
#       (b) transformed by g(x)
#           (i)  incremented by k
#           (ii) incremented by 1
#       (c) incremented by k
#  (II) no dotdot cases
#       (a) arrow case
#       (b) no arrow case
#
#  standard "dotdot" support format: 
#       [anything .. anything, incremented by k, transformed by g(x)]
#  
#  standard "no dotdot" pdf and support format:
#       [frac1, frac2, frac3, ... , fracN], [a1, a2, a3, ... , aN]
#       Example: [0.1, 0.3, 0.2, 0.4], [1, 4, 11, 34/3]
#
#  Procedure name: Valid(X) 
#  can strictly be used in calls by other procedures for valid pdf checks --
#  just to send back true or false
#
#  Date: June 8, 1999
#
#  Purpose: This procedure is called by other APPL procedures to determine the
#           "validity" of a given random variable and its APPL format. More
#           specifically, it checks that the:
#           (a) appropriate number of arguments is given
#           (b) RV X is in the list of 3 lists format
#           (c) pdf of X sums to 1 and pdf values are nonnegative for discrete RV's
#           (d) discrete support values for the pdf of X are valid
#           (e) area under the pdf of X is 1 for continuous RV's
#
#  Argument: The random variable of interest X in the list-of-lists format: 
#            [[f(x)], [support], ["Continuous" or "Discrete", "XXX"]],
#            where XXX is CDF, CHF, HF, IDF, PDF, or SF 
#
#  Algorithm
#    1.  Check that the RV X is in the list of 3 lists format
#    2.  Convert X to PDF form if not already in that form 
#    3.  Check to see whether the RV X is continuous or discrete
#    4.  If the RV X is continuous, calculate the integral(f(x)dx) from 0 to +inf
#        and the integral(abs(f(x))dx) from 0 to +inf. If int(f(x)) = 1 and 
#        int(abs(f(x))) = 1, then f(x) >= 0. Otherwise, f(x) is negative for some
#        value x in its support and is NOT a valid pdf
#    5.  If the RV X is discrete, determine if it is in the "dotdot" case.  In
#        probproc.map, dotdot is a defined structure type for discrete RV's:
#        `type/dotdot` := {constant .. constant, symbol .. constant, constant .. 
#         symbol, symbol .. symbol}:     
#    6.  If X is in the "dotdot" case, then first convert the support of X to the 
#        standard "dotdot" form: 
#        [anything .. anything, incremented by k, transformed by g(x)]
#    7.  Transform the pdf f(x) by g(x)
#    8.  Check that transformed pdf is >= 0 for all x in its support
#    9.  Check that the transformed pdf sums to 1 over its support
#    10. If X is in the "no dotdot" case, convert the support of X to the 
#        standard "no dotdot" form: [[fraction1, fraction2, fraction3, ... ,
#        fractionN], [a1, a2, a3, ... , aN], ["Discrete", "PDF"]]
#    11. Check that f(x) >= 0 for all x in its support
#    12. Sum f(x) over all x in its support
#    13. If X is continuous and the area under its pdf is is 1, then report to the 
#        user that X is a valid RV.  Similarly, if X is discrete and its pdf is
#        nonnegative for all values in its support and sums to 1 over its support,
#        then also report to the user that X is a valid RV.
#    
Valid := proc(X :: list(list))
local NumLists, fX, area, AbsArea, fXsum, nsegments, i, SubList1, SubList2, IllPDF, 
    Support, Lo, Hi, ExtendedSubList2, m, IncrBy, Transformation, 
    TransfPDF, PDFValues, n, IllSupp:
#
#  Check that the RV X is in the list of 3 lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR: The RV X must be in a list of 3 lists format`):
  RETURN(false):
fi:
#
#  Convert X to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
  fX := X:
elif ((X[3][2] = "CDF") or
      (X[3][2] = "CHF") or
      (X[3][2] = "HF") or
      (X[3][2] = "IDF") or
      (X[3][2] = "SF")) then
  fX := PDF(X):
else
  print(`ERROR: RV must be given as`):
  print(`CDF, CHF, HF, IDF, PDF, or SF`):
  RETURN():
fi:
#
#  Check to see whether the random variable X is continuous; if it is, find the
#  area under the pdf f(x) and abs(f(x)) over its support 
#
area := 0:
AbsArea := 0:
fXsum := 0: 
if (fX[3][1] = "Continuous") then
  nsegments := nops(X[1]):
  for i from 1 to nsegments do
    area := area + evalf(int(fX[1][i](x), x = fX[2][i] .. fX[2][i + 1])):
    AbsArea := AbsArea + evalf(int(abs(fX[1][i](x)), x = fX[2][i]..fX[2][i + 1])):
  od:
#
#  If int(f(x)) = 1 and int(abs(f(x))) = 1, then f(x) >= 0. Otherwise, f(x) is
#  negative for some value x in its support and is NOT a valid pdf
#
  if (AbsArea > 0.9999999 and AbsArea < 1.0000001) then
    print(`The area under f(x) is: `, area):
  else
    print(`ERROR(NewVerifyPDF): f(x) is negative for some value x in its support`):
    print(`The pdf of the given random variable is NOT valid`):
    RETURN():
  fi:
#
#  Check to see whether the random variable X is discrete
#
elif (fX[3][1] = "Discrete") then
  SubList1 := fX[1]:
  SubList2 := fX[2]:
  IllPDF := false:
#
#  If the random variable X is in the discrete "dotdot" case, first call procedure
#  Convert(X) to convert its support to the *standard dotdot* support format: 
#  [anything .. anything, incremented by k, transformed by g(x)]
#
  if type(SubList2[1], dotdot) then
    fX := Convert(fX):
    if (fX = false) then
      print(`ERROR: Discrete RV X is NOT in a legal APPL form`):
      RETURN(false):
    fi:
    SubList2 := fX[2]:
    Support := SubList2[1]:
    Lo := lhs(Support):
    Hi := rhs(Support): 
    IncrBy := SubList2[-2]:
#
#  Transform the pdf f(x) by g(x)
#
    Transformation := unapply(SubList2[-1](x))(x):
    TransfPDF := subs(x = Transformation, unapply(SubList1(x))(x)):
# 
#  Check that transformed pdf is >= 0 for all x in its support
#
    if (not(type(Lo, symbol)) and not(type(Hi, symbol))) then
      i := Lo:
      while (i <> Hi) do
        if (type(subs(x = i, op(TransfPDF)), negative)) then
          IllPDF := true:
          break:
        fi:
        i := i + IncrBy:
      od:
    fi:
#
#  Sum the transformed pdf over all x in its support
#  Deal w/ support [a .. b, 1, x -> x] as a special case
#        
    if not(IllPDF) then
      if ((IncrBy = 1) and (ispoly(Transformation, linear, x, 'a0', 'a1')) and
          (a0 = 0) and (a1 = 1)) then
        fXsum := simplify(evalf(sum(op(SubList1(x)), x = Lo .. Hi))):
      else
        for i from Lo by IncrBy to Hi do
          PDFValues := subs(x = i, op(TransfPDF)):
          fXsum := simplify(fXsum + PDFValues):
        od:
      fi:
    else
      print(`ERROR: PDF values must be positive`):
      RETURN(false):
    fi:
#
#  If the random variable X is in the discrete "no dotdot" case, first call 
#  procedure Convert(X) to convert its support to the *standard no dotdot* 
#  pdf/support format:        
#  [frac1, frac2, frac3, ... , fracN], [a1, a2, a3, ... , aN]
#
  else
    fX := Convert(fX):
    if (fX = false) then
      print(`ERROR: Discrete RV X is NOT in a legal APPL form`):
      RETURN(false):
    fi:

    SubList1 := fX[1]:
# 
#  Check that f(x) >= 0 for all x in its support
#
    n := nops(SubList2):
    for i from 1 to n do
      if (type(SubList1[i], negative)) then
        IllPDF := true:
        break:
      fi:
    od:
#
#  Sum f(x) over all x in its support
#      
    if not(IllPDF) then      
      fXsum := add(SubList1[i], i = 1 .. n):
    else
      print(`ERROR: PDF values must be positive`):
      RETURN(false):
    fi:
  fi:
#
#  ERROR: RV is neither continuous or discrete
#
else
  print(`ERROR: Procedure requires continuous or discrete RV`):
  RETURN():
fi:
#
#  If X is continuous and the area under its pdf is is 1, then report to the user
#  that X is a valid RV.  Similarly, if X is discrete and its pdf is nonnegative
#  for all values in its support and sums to 1 over its support, then also report
#  to the user that X is a valid RV
#
if ((area > 0.9999999 and area < 1.0000001) or 
    (fXsum > 0.9999999 and fXsum < 1.0000001)) then
  RETURN(true):
else
  RETURN(false):
fi:

end:
#1111111111222222222233333333334444444444555555555566666666667777777777#
#  Filename: variance1.map
#
#  Procedure Name: Variance(X)
#
#  Other APPL Procedures Called: PDF, Mean, ExpectedValue
#
#  Date: April 14, 1999
#
#  Purpose: Returns the variance of a distribution. 
#
#  Arguments: X: Random Variable
# 
#  Algorithm:
#    1.  Check for the appropriate number of arguments
#    2.  Check that the RV X is in a list-of-lists format
#    3.  Convert X to PDF form if not already in that form
#    4.  Compute and return the Variance of the RV X
#
#    NOTE:  Has NOT been updated since a discrete data structure has
#           been developed ... will need to redo the discrete portion of
#           the code
#
Variance := proc(X :: list(list))
local NumLists, fX, Mu, ExpValueXSqrd:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 1) then
  print(`ERROR(Variance): This procedure requires 1 argument:`):
  print(`A random variable`):
  RETURN():
fi:
#
#  Check that the RV X is in a list-of-lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(Variance): X must be in a list of 3 lists format`):
  RETURN():
fi:
#
#  Convert X to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
    fX := X:
elif ((X[3][2] = "CDF") or
      (X[3][2] = "CHF") or
      (X[3][2] = "HF") or
      (X[3][2] = "IDF") or
      (X[3][2] = "SF")) then
    fX := PDF(X):
else
    print(`ERROR(Variance): RV must be given as`):
    print(`PDF, CDF, SF, HF, CHF, or IDF`):
    RETURN():
fi:

Mu := Mean(fX):
ExpValueXSqrd := ExpectedValue(fX, x -> x^2):
RETURN(simplify(ExpValueXSqrd - Mu ^ 2)):
end:
#1111111111222222222233333333334444444444555555555566666666667777777777
#  Filename: verify21.map
#
#  NOTES:  
#  Discrete Cases:
#  (I)  dot cases
#       (a) incremented by 1
#       (b) transformed by g(x)
#           (i)  incremented by k
#           (ii) incremented by 1
#       (c) incremented by k
#  (II) no dot cases
#       (a) arrow case
#       (b) no arrow case
#
#  standard "dot" support format: 
#       [anything .. anything, incremented by k, transformed by g(x)]
#  
#  standard "no dot" pdf and support format:
#       [frac1, frac2, frac3, ... , fracN], [a1, a2, a3, ... , aN]
#       Example: [0.1, 0.3, 0.2, 0.4], [1, 4, 11, 34 / 3]
#
#  Procedure name: VerifyPDF(X) 
#
#  Other APPL Procedures Called: PDF, Convert
#
#  Date: August 27, 2000
#
#  Purpose:  For a continuous random variable X, verify that:
#            (1)  integral(f(x)dx) from 0 to +inf = 1, and
#            (2)  f(x) >= 0 for all x >= 0.  
#  * New Conjecture: If int(f(x)) = 1 and int(abs(f(x))) = 1, then 
#    f(x) >= 0
#             
#            For a discrete random variable X, verify that:
#            (1)  f(x) sums to 1 over its support, and
#            (2)  f(x) >= 0 for all x >= 0.  
#
#  Argument: The random variable of interest X in the list-of-sublists
#            format: 
#            [[f(x)], [support], ["Continuous" or "Discrete", "XXX"]],
#            where XXX is PDF, CDF, IDF, SF, HF, or CHF 
#
#  Algorithm
#    1.  Check for the appropriate number of arguments
#    2.  Check that the RV X is in the list of 3 sublists format
#    3.  Convert X to PDF form if not already in that form 
#    4.  Check to see whether the RV X is continuous or discrete
#    5.  If the RV X is continuous, calculate the integral(f(x)dx) from
#        0 to +inf and the integral(abs(f(x))dx) from 0 to +inf. If 
#        int(f(x)) = 1 and int(abs(f(x))) = 1, then f(x) >= 0.
#        Otherwise, f(x) is negative for some value x in its support
#        and is NOT a valid pdf
#    6.  If the RV X is discrete, determine if it is in the "dot" or
#        "no dot" case.  In startup.map, dot is a defined structure
#        type for discrete random variables:
#        `type/dot` := {constant .. constant, symbol .. constant,
#                       constant .. symbol, symbol .. symbol}:     
#    7.  Convert the support of X to its standard "dot" or "no dot" 
#        form:
#        (a) standard "dot" form: 
#        [anything .. anything, incremented by k, transformed by g(x)]
#        (b) standarc "no dot" form:
#        [[fraction1, fraction2, fraction3, ... , fractionN], 
#         [a1, a2, a3, ... , aN], ["Discrete", "PDF"]]
#    8.  If X has the "dot" form, transform the pdf f(x) by g(x) if 
#        f(x)'s support is NOT of the form: 
#        [a .. b, 1, x -> x]
#    9.  Check that transformed pdf is >= 0 for all x in its support
#    10. Check that the transformed pdf sums to 1 over its support
#    11. If X is in the "no dot" case, check that f(x) >= 0 for all x
#        in its support
#    12. Sum f(x) over all x in its support
#    13. If X is continuous and the area under its PDF is is 1, then
#        report to the user that X is a valid RV.  Similarly, if X is
#        discrete and its PDF is nonnegative for all values in its
#        support and sums to 1 over its support, then also report to
#        the user that X is a valid RV.
#    
VerifyPDF := proc(X :: list(list))
local NumLists, fX, area, AbsArea, fXsum, nsegments, numericcheck, i,
    SubList1, SubList2, Support, Lo, Hi, IncrBy, Transformation,
    TransfPDF, PDFVal, n:
#
#  Check for the appropriate number of arguments
#
if (nargs <> 1) then
  print(`ERROR(VerifyPDF): This procedure requires 1 argument:`):
  print(`A random variable`):
  RETURN():
fi:
#
#  Check that the RV X is in the list of 3 lists format
#
NumLists := nops(X):
if (NumLists <> 3) then
  print(`ERROR(VerifyPDF): The RV X must be a list of 3 sublists`): 
  RETURN():
fi:
#
#  Convert X to PDF form if not already in that form
#
if (X[3][2] = "PDF") then
  fX := X:
elif member(X[3][2], {"CDF", "SF", "HF", "CHF", "IDF"}) then
  fX := PDF(X):
else
  print(`ERROR(VerifyPDF): RV must be given as`):
  print(`PDF, CDF, SF, HF, CHF, or IDF`):
  RETURN():
fi:
#
#  Check to see whether the random variable X is continuous
#
area := 0:
AbsArea := 0:
fXsum := 0: 
if (fX[3][1] = "Continuous") then
  nsegments := nops(X[1]):
  # numericcheck := Mean(X):
  # print(`Mean is`, numericcheck):
  # print(whattype(numericcheck)):
  # print(fX[1]):
  # if type(numericheck, function) then
  # print(`mean is a function`):
  for i from 1 to nsegments do
    area := area + evalf(int(fX[1][i](y), y = fX[2][i] .. 
        fX[2][i + 1])):
     print(`area is`, area):
    AbsArea := AbsArea + int(abs(fX[1][i](x)), x = fX[2][i] .. 
        fX[2][i + 1]):
  od:
  # elif not(type(evalf(numericcheck), numeric)) then
  #  print(`not numeric mean`):
  #  for i from 1 to nsegments do
  #    area := area + evalf(int(fX[1][i](y), 
  #        y = fX[2][i] .. fX[2][i + 1])):
  #  od:
  #  area := simplify(area):
  #  AbsArea := 1:
  #else
  #  print(`nonnumeric mean`):
  #  for i from 1 to nsegments do
  #    area := area + evalf(int(fX[1][i](y), y = fX[2][i] .. 
  #        fX[2][i + 1])):
  #    print(`area is`, area):
  #    AbsArea := AbsArea + evalf(int(abs(fX[1][i](x)), x = fX[2][i] .. 
  #        fX[2][i + 1])):
  #  od:
  #fi:
#
#  If int(f(x)) = 1 and int(abs(f(x))) = 1, then f(x) >= 0. Otherwise,
#  f(x) is negative for some value x in its support and is NOT a valid
#  PDF
#
# SHOULDN'T BE RETURNING ERROR MESSAGES ... JUST STATEMENTS!
print(`The area under f(x) is: `, area): print(`now checking for Absolute value.`);
  if (evalf(area) > 0.9999999 and evalf(area) < 1.0000001) then
    if (AbsArea < 0.9999999 or AbsArea > 1.0000001) then
      print(`ERROR(VerifyPDF): The PDF of the given random variable`):
      print(`is NOT valid because f(x) is negative for some value x`):
      print(`in its support`):
      RETURN():
    fi:
  # situation where area = -1 and absarea = 1
  elif evalf(area) < 0.9999999 or evalf(area) > 1.0000001 then
    if (AbsArea > 0.9999999 and AbsArea < 1.0000001) then
      print(`ERROR(VerifyPDF): The PDF of the given random variable`):
      print(`is NOT valid because f(x) is negative for some value x`):
      print(`in its support`):
      RETURN():
    fi:
  fi:
  print(`The area under f(x) is: `, area):
  print(`f(x) is nonnegative`):
#
#  Check to see whether the random variable X is discrete
#
elif (fX[3][1] = "Discrete") then
  fX := Convert(fX):
  if (fX = false) then
    print(`ERROR(VerifyPDF): Discrete random variable X is`):
    print(`NOT in a legal APPL form`):
    RETURN():
  fi:
  SubList1 := fX[1]:
  SubList2 := fX[2]:
#
#  Check to see whether the random variable X is in the discrete "dot"
#  case
#
  if type(SubList2[1], dot) then
    Support := SubList2[1]:
    Lo := lhs(Support):
    Hi := rhs(Support): 
    IncrBy := SubList2[-2]:
    Transformation := unapply(SubList2[-1](x))(x):
    TransfPDF := subs(x = Transformation, unapply(SubList1(x))(x)):
# 
#  Check that transformed pdf is >= 0 for all x in its support
#
    if (not(type(Lo, symbol)) and not(type(Hi, symbol))) then
      i := Lo:
      while (i <> Hi) do
        if (type(subs(x = i, op(TransfPDF)), negative)) then
          print(`ERROR(VerifyPDF): PDF values must be positive`):
          RETURN():
        fi:
        i := i + IncrBy:
      od:
    fi:
#
#  Sum the transformed pdf over all x in its support
#  Deal w/ support [a .. b, 1, x -> x] as a special case
#        
    if (IncrBy = 1) and ispoly(Transformation, linear, x, 'a0', 'a1')
        and (a0 = 0) and (a1 = 1) then
# June 1, 2000: Took out: and type(Lo, integer) and type(Hi, integer)) 
# PROBLEM ... fXsum only computes correctly if Lo and Hi are integers
# See example C3a_N1 in VerAug2000 (needed further conditions in above
# if statement -- added type(Lo, integer) and type(Hi, integer)
      fXsum := simplify(evalf(sum(op(SubList1(x)), x = Lo .. Hi))):
    else
      print(`incrby is`, IncrBy):
      for i from Lo by IncrBy to Hi do
        PDFVal := subs(x = i, op(TransfPDF)):
        # print(`PDFVal is`, PDFVal):
        # PDFValues := simplify(subs(x = vals, op(SubList1(x)))): 
        # fXsum := simplify(fXsum + PDFValues):
        fXsum := simplify(fXsum + PDFVal):
        # print(`fxsum is`, fXsum):
      od:
    fi:
#
#  The random variable X is in the discrete "no dot" case
#
  else
# 
#  Check that f(x) >= 0 for all x in its support
#
    n := nops(SubList2):
    for i from 1 to n do
      if (type(SubList1[i], negative)) then
        print(`ERROR(VerifyPDF): PDF values must be positive`):
        RETURN():
      fi:
    od:
#
#  Check that symbols or infinity are not support values
#
    for i from 1 to n do
      if (type(SubList2[i], symbol)) then
        print(`ERROR(VerifyPDF): PDF values must be numeric`):
        RETURN():
      fi:
    od:
#
#  Sum f(x) over all x in its support
#      
    fXsum := add(SubList1[i], i = 1 .. n):
  fi:
  print(`The PDF sums to: `, fXsum):
#
#  ERROR: RV is neither continuous or discrete
#
else
  print(`ERROR(VerifyPDF): Procedure requires a`):
  print(`Continuous or Discrete RV`):
  RETURN():
fi:
#
#  If X is continuous and the area under its PDF is is 1 and f(x) >= 0
#  for all x in its support, then report to the user that X is a valid
#  RV. Similarly, if X is discrete and its PDF is nonnegative
#  for all values in its support and sums to 1 over its support, then 
#  report to the user that X is a valid RV.
#
if ((area > 0.9999999 and area < 1.0000001) or 
    (fXsum > 0.9999999 and fXsum < 1.0000001)) then
  print(`The PDF of the given random variable`, X):
  print(`is valid`):
  RETURN():
else
  print(`The PDF of the given random variable is NOT valid`):
  RETURN():
fi:

end:
#1111111111222222222233333333334444444444555555555566666666667777777777#  
#  Filename: weibullvariate1.map
#
#  Procedure name: WeibullVariate(lambda, kappa, m)
#
#  Other APPL Procedures Called: UniformVariate
#             
#  Date Revised: September 3, 1999
#
#  Purpose: Given the parameters lambda and kappa for the Weibull distribution,
#           WeibullVariate returns n Weibull variates and the mean and variance
#           values of these variates  
#
#  Arguments: lambda: nonnegative shape parameter,
#             kappa: nonnegative scale parameter, and
#             m: integer indicating the number of Weibull variates to generate
# 
WeibullVariate := proc(lambda :: nonneg, kappa :: nonneg, m :: integer)
local VariateList, i, U, NewVariate, Mean, Variance:

VariateList := []:
for i from 1 to n do
  U := UniformVariate():
  NewVariate := kappa * (log((1 - U) ^ (-1))) ^ (1 / lambda):
  VariateList := [op(VariateList), NewVariate]:
od:
# print(`The`, n, ` Weibull variates are:`):
# print(VariateList):
Mean := sum(VariateList[j] , j = 1 .. n) / n:
Variance := sum((VariateList[j] - Mean) ^ 2, j = 1 .. 1000) / (n - 1):
print(`The mean of the Weibull variates is`, Mean):
print(`The variance of the Weibull variates is`, Variance):

end: