From VisualWorks® NonCommercial, 7.2 of November 3, 2003 on May 29, 2005 at 8:29:38 pm (Dialog confirm: 'You are filing-in a Parcel source file!\\While this is possible it will not have\the same effect as loading the parcel.\None of the Parcel''s prerequisites will\be loaded and none of its load actions\will be performed.\\Are you sure you want to file-in?' withCRs) ifFalse: [self error: 'Parcel file-in abandoned. Choose terminate or close.'] FrequencyTableTest Smalltalk XProgramming.SUnit.TestCase false none testTable testTable2 testTableEmpty values Fnordistan (none) FrequencyTableTest SUnit tests for FrequencyTable. Instance Variables: testTable <FrequencyTable> description of testTable values <Array> description of values BellCurve Core Core.Object false none permutationsArray exactProbabilityArray ascendingProbabilityArray descendingProbabilityArray trials rangeMin rangeMax Fnordistan (none) Core.BellCurve A BellCurve shows ranges of probabilities given a set number of trials, each one consisting of a random number within a certain range. It can be thought of as a dice simulation, with each trial representing one "die" and the rangeMin and rangeMax indicating the lowest and highest values on the dice. (An actual BellCurve can have ranges that are negative numbers or otherwise cannot really be reflected on a polyhedral die.) Instance Variables: ascendingProbabilityArray <Array> description of ascendingProbabilityArray descendingProbabilityArray <Array> description of descendingProbabilityArray exactProbabilityArray <Array> description of exactProbabilityArray permutationsArray <Array> description of permutationsArray rangeMax <Integer> description of rangeMax rangeMin <Integer> description of rangeMin trials <Integer> number of trials for this BellCurve FrequencyTable Smalltalk Core.OrderedCollection false objects distributionVectors Fnordistan (none) FrequencyTable A FrequencyTable is an OrderedCollection that can arrange itself in histograph format. By default, an empty initialized FrequencyTable will return nil for range and frequency boundaries, and 1 distributionVector. A FrequencyTable initialized with a number will be assigned that many distribution vectors. Otherwise, you should set the distribution vectors yourself, according to how many "columns" you want in your frequency table. Instance Variables: distributionVectors <Number> The number of 'classes' that the data is distributed into. StatisticTest Smalltalk XProgramming.SUnit.TestCase false none testStat stat1 stat2 valueArray valueHash Fnordistan (none) Statistic Smalltalk Core.Collection false none Values Fnordistan (none) Statistic A Statistic is a Collection of numbers that can answer a variety of statistical calculations about itself. Treat a Statistic object as an array of values that can tell you its median, mean, etc. Internally, Statistic stores an OrderedCollection, and most Collection methods are invoked on this internal Collection. Alternatively, use any of Statistic's Class methods to answer with values about an external Collection. Instance Variables: Values <SortedCollection> an internal list of values stored in this Statistic object. FrequencyTableTest initialize-release initialize "Initialize a newly created instance. This method must answer the receiver." ^self FrequencyTableTest testing setUp values := #(4 5 12 3 15 7 -2 8). testTableEmpty := FrequencyTable new. testTable := FrequencyTable new: (values size). testTable2 := FrequencyTable new: (values size) with: (values size). testTable addAll: values. testTable2 addAll: values. testClasses "Make sure tables return expected ranges" " values := #(4 5 12 3 15 7 -2 8)." self assert: (testTableEmpty rangeStart = nil). self assert: (testTableEmpty rangeEnd = nil). self assert: (testTable rangeStart = -2). self assert: (testTable rangeEnd = 15). self assert: (testTable2 rangeStart = -2). self assert: (testTable2 rangeEnd = 15). testClassWidth "Make sure ClassWidths have expected sizes" self assert: (testTableEmpty classWidth = 0). self assert: (testTable classWidth = 17). self assert: (testTable2 classWidth = (17/8)). testDistributionVectors "Make sure tables return expected ranges" " values := #(4 5 12 3 15 7 -2 8)." self assert: (testTableEmpty distributionVectors = 1). self assert: (testTable distributionVectors = 1). self assert: (testTable2 distributionVectors = (testTable2 size)). testInstantiation "Make sure constructors work" self assert: (testTableEmpty class = FrequencyTable). self assert: (testTable class = FrequencyTable). self assert: (testTable2 class = FrequencyTable). testRange "Make sure tables return expected ranges" " values := #(4 5 12 3 15 7 -2 8)." self assert: (testTableEmpty rangeStart = nil). self assert: (testTableEmpty rangeEnd = nil). self assert: (testTable rangeStart = -2). self assert: (testTable rangeEnd = 15). self assert: (testTable2 rangeStart = -2). self assert: (testTable2 rangeEnd = 15). "and we can add and change those values" testTable add: 400. testTable add: -10. testTable2 add: 400. testTable2 add: -10. self assert: (testTable rangeStart = -10). self assert: (testTable rangeEnd = 400). self assert: (testTable2 rangeStart = -10). self assert: (testTable2 rangeEnd = 400). testSize "Make sure tables have expected sizes" self assert: (testTableEmpty size = 0). self assert: (testTable size = (values size)). self assert: (testTable2 size = (values size)). "and we can add and change those values" testTable add: 400. testTable add: -10. testTable2 add: 400. testTable2 add: -10. testTableEmpty add: 400. testTableEmpty add: -10. self assert: (testTableEmpty size = 2). self assert: (testTable size = ((values size) + 2)). self assert: (testTable2 size = ((values size) + 2)). testSortedData "Make sure tables have expected sortedData sets." | emptyData data data2 | emptyData := testTableEmpty sortedData. data := testTable sortedData. data2 := testTable2 sortedData. self assert: (emptyData = nil). FrequencyTableTest class instance creation new "Answer a newly created and initialized instance." ^super new initialize Core.BellCurve initialize-release initialize: numberOfTrials range: min to: max "Initialize probability arrays" self trials: numberOfTrials. self range: min to: max. permutationsArray := BellCurve createPermutationsArray: numberOfTrials range: min to: max. exactProbabilityArray := BellCurve createExactProbabilityArray: permutationsArray with: (self range raisedTo: trials). ascendingProbabilityArray := BellCurve createAscendingProbabilityArray: exactProbabilityArray. descendingProbabilityArray := BellCurve createDescendingProbabilityArray: exactProbabilityArray. ^self Core.BellCurve printing printPermutations "Answers the permutationsArray as a comma-delimited values string." | displayString | displayString := 'Permutations: '. permutationsArray do: [:p | displayString := displayString , p printString , ',']. ^displayString printString "Standard object message answering a descriptive string." ^'a BellCurve for ' , trials printString , ' trials of ' , rangeMin printString , ' to ' , rangeMax printString Core.BellCurve accessing ascendingProbabilityArray "Answers an array of probabilities ascending cumulatively with the sum of all preceding values." ^ascendingProbabilityArray descendingProbabilityArray "Answers an array of probabilities descending cumulatively from the sum of all following values." ^descendingProbabilityArray exactProbabilityArray "Answers the array of exact probabilities for each position on the BellCurve." ^exactProbabilityArray permutationsArray "Answers the array of total possible permutations possible for each value on the BellCurve" ^permutationsArray range "Answers the range min-max, giving the length of the probability arrays" ^rangeMax - rangeMin + 1 range: min to: max "Set the min to max range for each trial. min and max must both be integers and max must be greater than or equal to min" (min isInteger and: [max isInteger]) ifTrue: [ max < min ifTrue: [self error: 'range maximum cannot be less than the minimum: ' , max printString] ifFalse: [ rangeMin := min. rangeMax := max]] ifFalse: [self error: 'range parameters must be integers: ' , min printString , ', ' , max printString]. rangeMax ^rangeMax rangeMin ^rangeMin trials "Answers numberof trials in this BellCurve" ^trials trials: numberOfTrials "Sets the number of trials for this BellCurve. numberOfTrials must be an Integer > 0" (numberOfTrials isInteger and: [numberOfTrials > 0]) ifTrue: [trials := numberOfTrials] ifFalse: [self error: 'trials must be an integer > 0: ' , numberOfTrials printString]. Core.BellCurve class instance creation new "Default one-element BellCurve." ^super new initialize: 1 range: 1 to: 1 new: numberOfDice "Creates a BellCurve for a specified number of standard 6-sided dice." ^super new initialize: numberOfDice range: 1 to: 6 new: numberOfDice max: numberOfSides "Create a BellCurve for a given number of dice that range from 1 to an upper bound" ^super new initialize: numberOfDice range: 1 to: numberOfSides new: numberOfDice min: lowerBound max: numberOfSides "Create a BellCurve based on a given number of dice ranging from a lower bound to an upper bound." ^super new initialize: numberOfDice range: lowerBound to: numberOfSides Core.BellCurve class creating probability arrays createAscendingProbabilityArray: exactProbs "Answers an array of probabilities that are cumulative totals from the index backward (<=)" | probArray | probArray := exactProbs copyFrom: 1 to: exactProbs size. (Interval from: 2 to: probArray size) do: [:i | probArray at: i put: (probArray at: i) + (probArray at: i - 1)]. ^probArray createDescendingProbabilityArray: exactProbs "Answers an array of probabilities that are cumulative totals from the index forward (>=)" | probArray | probArray := exactProbs copyFrom: 1 to: exactProbs size. (Interval from: probArray size - 1 to: 1 by: -1) do: [:i | probArray at: i put: (probArray at: i) + (probArray at: i + 1)]. ^probArray createExactProbabilityArray: permutations with: range "Answers the array of the exact probability of generating a result at a particular point on the BellCurve" "permutations must be an Array with the number of possible permutations for each position in the array, wirh range being the total number of permutations possible." | probArray index end | probArray := Array new: permutations size. index := 1. end := permutations size. [index <= end] whileTrue: [ | val | val := permutations at: index. probArray at: index put: val / range. index := index + 1]. ^probArray createPermutationsArray: trials range: min to: max "This answers an Array filled with raw probabilities given a number of #trials with equal probability of any integer from #min to #max. This should only be invoked from the initialize method, or from itself, which is assumed to have already validated our input values. trials, min, and max can also be seen as dice, i.e. trials=3, min=1, max=6 is equivalent to 3D6, or rolling 3 six-sided dice. The elements of the returned array contain the total number of permutations which can result in the sum corresponding to the given index. E.g., a 1-6 array will return #(1, 1, 1, 1, 1, 1,) because there is exactly one possible result for each value from 1-6. A 2 x 1-6 array will return #(1 2 3 4 5 6 5 4 3 2 1); there is one result that can return a 2, two that can return a 3, three that can return a 4, etc. Note that the array begins at 1; you must make sure you handle the adjustment so the index values actually correspond to die rolls (i.e. mapping a 2-12 roll to a 1-11 array." | baseArray arraySize arrayAdjust baseRange| arraySize := ((trials * max) - (trials * min)) +1. baseArray := Array new: arraySize. baseRange := (max - min) + 1. arrayAdjust := (trials * baseRange) - arraySize. "This is used so we can store correct values in an array without zero-filling the unused numbers from 1 to min. (e.g. a '2-12' array is actually 1-11)" "Zero-initialize the array" (Interval from: 1 to: arraySize) do: [:index | baseArray at: index put: 0]. "Now we iterate through our initial range and recursively add the range from the previous array to it." trials = 1 "If dice is 1, this is the base case; all values have an equal probability." ifTrue: [ (Interval from: 1 to: arraySize) do: [:index | baseArray at: index put: 1]] ifFalse: [ "Recursively fetch the array from 1 fewer dice" |previousArray| previousArray := self createPermutationsArray: (trials-1) range: min to: max. (Interval from: 1 to: previousArray size) do: [:previndex | "Iterate through the baseArray recursively adding 1 to the total in each position with each iteration" (Interval from: 1 to: baseRange) do: [:dieval | |prevArrayValue index oldVal| prevArrayValue := previousArray at: previndex. index := (previndex + trials-2) + dieval - arrayAdjust. oldVal := baseArray at: index. baseArray at: index put: (oldVal + prevArrayValue)]]]. ^baseArray FrequencyTable accessing classWidth "Returns the width of each data class, determined by distributing the range of data equally between the number of data classes." |min max| self isEmpty ifTrue: [^0]. min := self rangeStart. max := self rangeEnd. ^(max - min)/(self distributionVectors) distributionVectors "Return the number of classes into which our data is distributed" ^distributionVectors distributionVectors: anInteger "Set the number of classes to distribute our data into, and automatically orders our data accordingly." (anInteger isInteger and: [anInteger > 0]) ifFalse: [self error: 'numberOfClasses must be an Integer > 0']. distributionVectors := anInteger. rangeEnd "Find the largest value in our data" | max | self isEmpty ifTrue: [^nil]. max := self at: 1. (self size) > 1 ifTrue: [2 to: (self size) do: [ :index | (self at: index) > max ifTrue: [max := self at: index]]]. ^max rangeStart "Find the smallest value in our data" | min | self isEmpty ifTrue: [^nil]. min := self at: 1. (self size) > 1 ifTrue: [2 to: (self size) do: [ :index | (self at: index) < min ifTrue: [min := self at: index]]]. ^min sortedData "Returns an Array of Bags consisting of all the data sorted into classes according to our numberOfClasses. nil if empty" | width dataSort | self isEmpty ifTrue: [^nil]. dataSort := Array new: distributionVectors. 1 to: distributionVectors do: [:i | dataSort at: i put: Bag new]. width := self classWidth. 1 to: (self size) do: [:n | | index | index := (n // width) asInteger. Transcript show: 'INDEX : ', index printString, ' for ', n printString,' // ', width printString;cr. (dataSort at: index) add: n. ]. ^dataSort FrequencyTable initialize-release initialize "Initialize a newly created instance. This method must answer the receiver." ^(self initialize: 1) initialize: anInteger "Initialize a newly created instance. This method must answer the receiver." (anInteger isInteger and: [anInteger > 0]) ifFalse: [self error: 'Initial distribution vectors must be an Integer > 0']. self distributionVectors: anInteger. ^self FrequencyTable class instance creation new "Answer a newly created and initialized instance." ^super new initialize new: anInteger "Answer a newly created and initialized instance with a set size." ^(super new: anInteger) initialize new: anInteger with: startingVectors "Answer a newly created and initialized instance with a set size and number of starting distributionVectors." ^(super new: anInteger) initialize: startingVectors StatisticTest testing setUp "Create the text fixture" valueArray := #(4 12 7 18 14 3 29 25 1 11 7 16 8 31 2). valueHash := Dictionary new. valueHash at: 'size' put: 15. valueHash at: 'mean' put: (188/15). valueHash at: 'median' put: 11. valueHash at: 'stdev' put: 9.650067851. valueHash at: 'popstdev' put: 9.322851257. stat1 := Statistic new. stat2 := Statistic new. stat2 addAll: valueArray. testInstantiation "Test that we can create a Statistic object" self assert: (stat1 class = Statistic). self assert: (stat2 class = Statistic). testMean "test the mean method" | values upperLimit expectedMean | upperLimit := 1. expectedMean := 1. values := Bag new. self should: [Statistic mean: values] raise: Exception. values add: upperLimit. self assert: ((Statistic mean: values) = expectedMean). upperLimit := upperLimit + 1. values add: upperLimit. expectedMean := 1.5. self assert: ((Statistic mean: values) = expectedMean). 100 timesRepeat: [ upperLimit := upperLimit + 1. values add: upperLimit. expectedMean := expectedMean + 0.5. self assert: ((Statistic mean: values) = expectedMean). ]. " Test our Statistic collections." self should: [stat1 mean] raise: Exception. self assert: (stat2 mean asFloat = (valueHash at: 'mean')). testMedian "test the median method" | values upperLimit expectedMedian | upperLimit := 1. expectedMedian := 1. values := Bag new. self should: [Statistic median: values ] raise: Exception. [upperLimit < 100] whileTrue: [ values add: upperLimit. (values size) > 1 ifTrue: [self assert: ((Statistic median: values) = expectedMedian)] ifFalse: [self should: [Statistic median: values ] raise: Exception]. expectedMedian := expectedMedian + 0.5. upperLimit := upperLimit + 1]. " Test our Statistic collections." self should: [stat1 median] raise: Exception. self assert: (stat2 median == (valueHash at: 'median')). Statistic initialize-release initialize "Initialize a newly created instance. This method must answer the receiver." Values := SortedCollection new. ^self Statistic adding add: newObject "add a new value to our Values." Values add: newObject. Statistic enumerating do: aBlock "Perform the Block operation on our values." Values do: aBlock. Statistic removing remove: oldObject ifAbsent: anExceptionBlock "Removes a value from our internal values array." Values remove: oldObject. Statistic statistical calculations mean "Answers the mean of this Statistic" ^(Statistic mean: Values) median "Answers the median of this Statistic" ^(Statistic median: Values) Statistic class probability distributions binomialDistribution: p trials: n successes: r "Get the probability of scoring EXACTLY r successes out of n trials given a base probability of p" (r isInteger and: [r >= 0]) ifFalse: [self error: 'successes must be an Integer >= 0']. (n isInteger and: [n >= r]) ifFalse: [self error: 'trials must be an Integer >= number of successes']. (p >= 0 and: [p <= 1]) ifFalse: [self error: 'probability must be integer 0 <=> 1']. ^(Statistic combination: n select: r) * (p raisedTo: r) * ((1 - p) raisedTo: (n - r)) binomialDistributionCumulative: p trials: n successes: r "Recursively get cumulative probability for scoring at least r successes" | P r0 | "Cumulative probability" P := 0. "Probability of exactly r-1 successes" r0 := r - 1. "Recursive loop" [r0 >= 0] whileTrue: [ P := P + (Statistic binomialDistribution: p trials: n successes: r0). r0 := r0 - 1]. "Now we have the cumulative odds of scoring r-1 or fewer successes. Subtract from 1 for odds of more than r successes" P := 1 - P. ^P Statistic class permutations combination: size select: choices " ***This is decompiled code.*** The source was unavailable because the source pointer appears to point to an incorrect position in the file. The file may have been modified after this method was updated." | t3 t4 comb t6 t7 | (size isInteger and: [choices isInteger]) ifFalse: [self error: 'size and choices must both be integers']. (choices < 0 or: [size < 0]) ifTrue: [self error: 'both values must be at least 0']. size >= choices ifFalse: [self error: 'size must be greater than or equal to choices']. choices = 0 ifTrue: [comb := 1] ifFalse: [t3 := size. t6 := size - 1. t7 := size - choices + 1. [t6 >= t7] whileTrue: [t3 := t3 * t6. t6 := t6 - 1]. t4 := choices factorial. comb := t3 / t4]. ^comb Statistic class range values mean: aCollection "Answers the mean of a Collection (assuming all values are numbers)" | sum | aCollection isEmpty ifTrue: [self error: 'cannot calculate median for an empty set']. sum := 0. aCollection do: [:n | sum := sum + n]. ^(sum/(aCollection size)) "Imported Classes:" self error: 'Attempting to file-in parcel imports. Choose terminate or close' Object Core false none Kernel-Objects Kernel-Objects Collection Core Core.Object false none Collections-Abstract Collections-Abstract OrderedCollection Core Core.SequenceableCollection false objects firstIndex lastIndex Collections-Sequenceable Collections-Sequenceable TestCase XProgramming.SUnit Core.Object false none testSelector SUnit SUnit