>
> import SequenceUtilities(pam, reps, rightJustify)
> import IOutilities(spaces)
> import NumericUtilities(digitize)
--------------- Project 4A: Ecology Equations -----------------
rabbit population update function (simplified Lotka-Volterra model)
> nextRabbitPopulation :: RealFrac num => [num] -> [num] -> num
> nextRabbitPopulation
> [rabbitIncreaseWithoutWolves, coyoteDecreaseWithoutRabbits,
> chanceThatCoyoteAEatsRabbitX, coyoteIncreaseByEatingRabbit]
> [currentRabbitPopulation, currentCoyotePopulation]
> =
> (1 + rabbitIncreaseWithoutWolves)*currentRabbitPopulation -
> (chanceThatCoyoteAEatsRabbitX*currentCoyotePopulation)*
> currentRabbitPopulation
coyote population update function (simplified Lotka-Volterra model)
> nextCoyotePopulation :: RealFrac num => [num] -> [num] -> num
> nextCoyotePopulation
> [rabbitIncreaseWithoutWolves, coyoteDecreaseWithoutRabbits,
> chanceThatCoyoteAEatsRabbitX, coyoteIncreaseByEatingRabbit]
> [currentRabbitPopulation, currentCoyotePopulation]
> =
> (1 - coyoteDecreaseWithoutRabbits)*currentCoyotePopulation +
> (chanceThatCoyoteAEatsRabbitX*currentRabbitPopulation*
> coyoteIncreaseByEatingRabbit) * currentCoyotePopulation
delivers rabbit/coyote population trajectory via
simplified Lotka-Volterra model
> rabbitCoyotePopulationTrajectory ::
> RealFrac num => [num] -> [num] -> [[num]]
> rabbitCoyotePopulationTrajectory populationChangeCoefficients
> initialRabbitCoyotePopulations =
> populationTrajectory
> (rabbitCoyoteUpdateFunctions populationChangeCoefficients)
> initialRabbitCoyotePopulations
update functions, packaged for populationTrajectory function
> rabbitCoyoteUpdateFunctions::RealFrac num => [num] -> [[num]->num]
> rabbitCoyoteUpdateFunctions populationChangeCoefficients =
> [nextRabbitPopulation populationChangeCoefficients,
> nextCoyotePopulation populationChangeCoefficients ]
deliver time-sequence of population figures given
population update functions and initial populations
Note: can handle any number of species
> populationTrajectory ::
> [[population] -> population] -> [population] -> [[population]]
> populationTrajectory updateFunctions = iterate(pam updateFunctions)
------------------ Project 4B: makeChart ----------------
deliver picture and associated scale figures
given character to use to mark points, picture dimensions, and points
> makeChart ::
> RealFrac num => Char -> Int -> Int -> [[num]] -> ([num], [String])
> makeChart dot width height points =
> ([minHorizontal,maxHorizontal,minVertical,maxVertical], picture)
> where
> minHorizontal = minimum[x | [x, y] <- points]
> maxHorizontal = maximum[x | [x, y] <- points]
> minVertical = minimum[y | [x, y] <- points]
> maxVertical = maximum[y | [x, y] <- points]
> picture = sequenceOfUpdates (blankPicture width height)
> sequenceOfUpdates =
> foldr (.) id [updatePicture dot digitalPoint |
> digitalPoint <- digitalPoints]
> digitalPoints =
> [[digitize width minHorizontal maxHorizontal x,
> digitize height minVertical maxVertical y] | [x, y] <- points]
make blank picture
> blankPicture :: Int -> Int -> [String]
> blankPicture width height = reps height (spaces width)
--------------- Project 4C: updatePicture -----------------
function: updatePicture
inserts a dot in a picture at a specified point;
a point's position in the picture is represented by
a sequence of two integers [i, j], where i is the
distance from the left edge and j is the distance
from the top;
a picture is represented as a sequence of strings,
each of which has the same length; the top of the
picture is the first string and the left edge is
the first character of each string; indexing starts
at zero in both cases
> updatePicture :: Char -> [Int] -> [String] -> [String]
> updatePicture dot [distanceFromLeft, distanceFromTop] =
> update (update dotSetter distanceFromLeft) distanceFromTop
> where
> dotSetter anything = dot
function: update
uses a function supplied as an argument to make a change
in an element of a sequence; the element to be changed
is specified in the second argument as a zero-based index
> update :: (a -> a) -> Int -> [a] -> [a]
> update modifier zeroBasedIndex xs =
> before ++ [modifier x] ++ after
> where
> (before, atAndBeyond) = splitAt zeroBasedIndex xs
> x = head atAndBeyond
> after = tail atAndBeyond
------------------ Project 4D: displayChart ----------------
convert chart (from makeChart function) to displayable string
> displayChart ::
> RealFrac num => [String] -> ([num], [String]) -> String
> displayChart
> [horizontalAxisName, verticalAxisName]
> ([minHorizontal,maxHorizontal,minVertical,maxVertical], picture)=
> unlines(
> [topBorder] ++
> [addSideBorders verticalBarOnLeft row | row <- chartAbove] ++
> [addSideBorders barWithAxisName row | row <- chartAtAxisName]++
> [addSideBorders verticalBarOnLeft row | row <- chartBelow] ++
> [bottomBorder] ++
> [horizontalLabels])
> where
> topBorder = maxVerticalLabelPadded ++ horizontalBorder
> bottomBorder = minVerticalLabelPadded ++ horizontalBorder
> maxVerticalLabel = show maxVertical
> minVerticalLabel = show minVertical
> maxHorizontalLabel = show maxHorizontal
> minHorizontalLabel = show minHorizontal
> pictureWithMaxAtTop = reverse picture
> (chartAbove, chartAtAndBelow) =
> splitAt (pictureHeight `div` 2) pictureWithMaxAtTop
> (chartAtAxisName, chartBelow) = splitAt 1 chartAtAndBelow
> verticalBarOnLeft = rightJustify verticalLabelWidth ' ' "|"
> barWithAxisName =
> rightJustify verticalLabelWidth ' ' (verticalAxisName ++ "|")
> verticalLabelWidth =
> 1 + maximum[length label | label <- verticalAxisLabels]
> verticalAxisLabels =
> [maxVerticalLabel, minVerticalLabel, verticalAxisName]
> maxVerticalLabelPadded =
> rightJustify verticalLabelWidth ' ' (maxVerticalLabel ++ "|")
> minVerticalLabelPadded =
> rightJustify verticalLabelWidth ' ' (minVerticalLabel ++ "|")
> horizontalBorder = reps pictureWidth '-' ++ "|"
> addSideBorders label row = label ++ row ++ "|"
> horizontalLabels =
> verticalBarOnLeft ++ minHorizontalLabel ++
> spaces before ++ horizontalAxisName ++ spaces after ++ "|" ++
> maxHorizontalLabel
> spaceRemaining =
> max 0 (pictureWidth -
> (length minHorizontalLabel + length horizontalAxisName))
> before = spaceRemaining `div` 2
> after = spaceRemaining - before
> pictureWidth = (length . head) picture
> pictureHeight = length picture
----------- unit testing ----------------
For ecology equations:
> coeffs, inits :: [Float]
> coeffs = [0.04, 0.1, 0.002, 0.03]
> inits = [1000, 10]
> period :: Int
> period = 120
> tst1 =
> (take period .
> populationTrajectory(rabbitCoyoteUpdateFunctions coeffs)) inits
For drawing utilities:
> blankPic = blankPicture 5 5
> xPosn, yPosn :: Int
> xPosn = 2
> yPosn = 2
> dot = '*'
> tst2 = unlines(updatePicture dot [xPosn, yPosn] blankPic)
For overall computation:
> width, height :: Int
> width = 30
> height = 20
> tst3 = makeChart dot width height tst1
> tst4 = (putStr . unlines . snd) tst3
> tst5 = (putStr . displayChart["Rabbits", "Coyotes"] .
> makeChart dot width height) tst1
Last Modified: