From: Farrel Lifson Date: 2005-07-04T07:41:32+09:00 Subject: [ANN] Precedence 0.8 I've just released Precedence 0.8. This is a combined release with 0.7 (last release was 0.6). This is not backward compatiable with 0.6 so if you're using it you might have to do some refactoring. Here's the README and CHANGELOG. ------------------------------------------------------------------------------------------------------------------------------- = Precedence Precedence is a library that allows for the creation, manipulation and analysis of precedence networks. == Download and Install Available as a RubyGem from Rubyforge. To install $ gem install precedence will fetch the latest gem from Rubyforge and install it. Source can also be downloaded from http://rubyforge.org/projects/precedence. == Example Usage require('precedence') # Set up network net = Precedence::Network.new net.new_activity('act-1-1') do |act| act.expected_duration = 3 act.description = 'System specification' end net.new_activity('act-1-2' do |act| act.expected_duration = 2 act.description = 'Review' end net.new_activity('act-1-3') do |act| act.expected_duration = 2 act.description = 'System re-specification' end net.new_activity('act-2-1') do |act| act.expected_duration = 3 act.description = 'Test tool design' end net.new_activity('act-2-2') do |act| act.expected_duration = 5 act.description = 'Test tool implementation' end net.new_activity('act-3-1') act.expected_duration = 3 act.description = 'System design' end net.new_activity('act-3-2') do |act| act.expected_duration = 12 act.description = 'System implementation' end net.new_activity('act-2-3') do |act| act.expected_duration = 10 act.description = 'System testing' end net.connect('act-1-1','act-1-2') net.connect('act-1-2','act-1-3') net.connect('act-1-3','act-3-1') net.connect('act-1-2','act-2-1') net.connect('act-2-1','act-2-2') net.connect('act-2-2','act-3-2') net.connect('act-3-1','act-3-2') net.connect('act-3-2','act-2-3') net.fix_connections! # Generate a diagram File.open('network.dot',File::CREAT|File::TRUNC|File::WRONLY) do |file| file.puts(net.to_dot) end system("dot","-Tpng","-onetwork.png","network.dot") # Perform some analysis of the activities activity = net.activities['act-1-2'] activity.on_critical_path? # => true activity.earliest_start # => 3.0 activity.latest_finish # => 5.0 activity.total_float # => 0 - activities on the critical path have no float # Save the network to a YAML file File.open('network.yaml',File::CREAT|File::TRUNC|File::WRONLY do |file| file.puts(net.to_yaml) end # Read the network from a YAML file newNet = Precedence::Network.from_yaml(File.new('network.yaml',File::RDONLY)) == Documentation The Precedence API online documentation is available at http://precedence.rubyforge.org. Refer to the CHANGELOG and TODO files for past changes and upcoming plans. == Credits Farrel Lifson == License This software is made available under the BSD license. = ChangeLog = 0.8 * Added multiple durations. An activity has the following durations associated activity = Precedence::Activity.new('activity1') do |act| act.expected_duration = 2 # This is what would've been act.duration act.minimum_duration = 1 # The minimum time the activity could need act.maximum_duration = 4 # The maximum time the activity should need end From this the following may be determined: activity.mean_duration activity.standard_deviation activity.variance A Beta distribution is assumed to be used for the probability density function and if certain assumptions are made the following hold - The mean_duration is calculated as: (4*expected_duration + minimum_duration + maximum_duration)/6 - The standard deviations is: (maximum_duration - minimum_duration)/6 - The variance is the standard deviation squared. The activity.duration attribute is still present and it is configurable to allow the differing duration types. The duration to be used is set using the Activity.duration_type attribute. For instance assuming we have the following two activities set up: act1 = Precedence::Activity.new('a1') do |activity| activity.expected_duration = 2 activity.minimum_duration = 1 activity.maximum_duration = 3 end act2 = Precedence::Activity.new('a2') do |activity| activity.expected_duration = 3 activity.minimum_duration = 1 activity.maximum_duration = 5 end act1.add_post_activities(act2) # Duration type is initially set to the expected duration act2.earliest_finish # => 5 # Change duration type to the maximum duration act2.duration_type = Activity::MAXIMUM_DURATION act2.earliest_finish # => 7 The allowed duration types are : EXPECTED_DURATION, MEAN_DURATION, MINIMUM_DURATION and MAXIMUM_DURATION * Moved the ActivityHash and ResourceHash into the Precedence::Utilities module. * Added Activity.active_at?(time) which returns true if the activity is active at time. * Added Network.activities_at_time(time) which returns an array of activities active at that time. * Added Activity.active_during?(range) which returns true if the activity is active during the time range given. * Added Network.activities_during_time(range) which returns an array of activities active during the range given. * Added Network.each_time_period(tick,&block) which iterates over the duration of the project in time steps of the tick parameter, yielding an array of activities active at each time to the block. * Removed the StartActivity and FinishActivity of the network from the Network.activities hash. They are still avaialable in the hash if needed precNetwork.activities['start'] precNetwork.activities['finish'] will return the StartActivity/FinishActivity however precNetwork.activities.each will not include them. I am still thinking of a way to get rid of them altogether. * Added Network.reference_exists? which will return true if the reference is in the network. = 0.7 * Added ability to load from and save networks to YAML files. * Split StartFinishActivity into seperate StartActivity and FinishActivity classes. * Added StartActivity::REFERENCE and Network::START as well as FinishActivity::REFERENCE and Network::FINISH as constants to hold the reserved references for the start and finish activities in a network. * Totally changed the way activities are created in both the Activity and Network classes. Activity.new(reference,duration,description,post_activities,pre_activities) is now Activity.new(reference) do |activity| activity.duration = duration activity.description = description activity.add_post_activities(post_activities) activity.add_pre_activities(pre_activities) end The same applies to the Network.new_activity method Network.new_activity(reference,duration,description,post_activities,pre_activities) has become network.new_activity(reference) do |activity| activity.duration = duration activity.description = description activity.add_pre_activities(pre_activities) end network.connect(reference,post_activities) pre_activities.each do |pre_act_ref| network.connect(pre_act_ref,reference) end In fact the block from his method is passed directly to the Activity.new method. While you could use add_post_activities and add_pre_activities in this block it is better to use Network.connect when dealing with the Network class. * Added resources to activities. They can be set via the activity.resources hash