Class: Precedence::Activity

Inherits:
Object
  • Object
show all
Defined in:
lib/precedence/activity.rb

Overview

A representation of an activity in a precedence network. Each activity has a user specified reference, description and duration. When activities are connected (via the add_post/pre_activities functions) then various other properties of the activity can be determined such as it’s earliest finish time, float and so on.

The activity also has a probabilistic component.

Direct Known Subclasses

FinishActivity, StartActivity

Constant Summary collapse

MEAN_DURATION =
:mean_duration
EXPECTED_DURATION =
:expected_duration
MINIMUM_DURATION =
:minimum_duration
MAXIMUM_DURATION =
:maximum_duration
EARLIEST_START =
:earliest_start
LATEST_START =
:latest_start
DROP_START =
:drop_start

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(reference, &block) ⇒ Activity

Creates a new activity. The only required field is the reference. The description, duration can be set in the block, which will have as a parameter the newly created activity. If they are not set in the block they will have as values “” and 0 respectively. Post- and pre-activities can also be set in the block by using the Activity.add_post_activities and Activity.add_pre_activities methods.

Note: When assigning a reference for an activity StartActivity::REFERENCE and FinishActivity::REFERENCE are reserved for internal usage.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/precedence/activity.rb', line 73

def initialize(reference, &block)
	reference.respond_to?(:to_s) ? nil : raise("Parameter reference"+
		"must respond to 'to_s'.")
	reference = reference.to_s
	if ((reference != Precedence::StartActivity::REFERENCE) && 
		(reference != Precedence::FinishActivity::REFERENCE))
		@reference = reference.to_s
	else
		raise "Activity reference '#{reference}' is reserved."
	end
	
	@description = ""
	@post_activities = []
	@pre_activities = []
	@resources = Precedence::Utilities::ResourceHash.new
	@expected_duration = 0
	@minimum_duration = 0
	@maximum_duration = 0
	@duration_type = EXPECTED_DURATION
	@start_type = EARLIEST_START
	
	# Call the block if it is present
	block ? block.call(self) : nil			
				
	# Type conversion
	@expected_duration = @expected_duration.to_f
	@minimum_duration = @minimum_duration.to_f
	@maximum_duration = @maximum_duration.to_f
end

Instance Attribute Details

#descriptionObject

A textual description of the activity.



28
29
30
# File 'lib/precedence/activity.rb', line 28

def description
  @description
end

#duration_typeObject

Sets what the duration method should return. Can be set to one of:

  • EXPECTED_DURATION

  • MAXIMUM_DURATION

  • MINIMUM_DURATION

  • MEAN_DURATION

Initially set to the expected duration



55
56
57
# File 'lib/precedence/activity.rb', line 55

def duration_type
  @duration_type
end

#expected_durationObject

The expected duration of the activity



30
31
32
# File 'lib/precedence/activity.rb', line 30

def expected_duration
  @expected_duration
end

#maximum_durationObject

The maximum duration of the activity



34
35
36
# File 'lib/precedence/activity.rb', line 34

def maximum_duration
  @maximum_duration
end

#minimum_durationObject

The minimum duration of the activity



32
33
34
# File 'lib/precedence/activity.rb', line 32

def minimum_duration
  @minimum_duration
end

#post_activitiesObject (readonly)

The collection of activites that are dependent on the completion of this activity.



39
40
41
# File 'lib/precedence/activity.rb', line 39

def post_activities
  @post_activities
end

#pre_activitiesObject (readonly)

The collection of activities that this activity depends on before it can begin executing.



42
43
44
# File 'lib/precedence/activity.rb', line 42

def pre_activities
  @pre_activities
end

#referenceObject (readonly)

A unique reference for this activity.



36
37
38
# File 'lib/precedence/activity.rb', line 36

def reference
  @reference
end

#resourcesObject (readonly)

A collection of resources that are used by this activitity. Stating that

activity.resources['concrete'] = 5

indicates that the activity will use 5 units of concrete per time period.



48
49
50
# File 'lib/precedence/activity.rb', line 48

def resources
  @resources
end

#start_typeObject

Sets what the start attribute should return can be set to one of:

  • EARLIEST_START

  • LATEST_START

  • DROP_START

Initially set to the earliest start



61
62
63
# File 'lib/precedence/activity.rb', line 61

def start_type
  @start_type
end

Class Method Details

.from_yaml(yaml) ⇒ Object

Returns an Activity object that is represented by a YAML document.

Note: This method will only restore the reference, various durations, description and resource parameters. Post-/pre-activities are not restored (they are restored when using Precedence::Network.from_yaml).



482
483
484
# File 'lib/precedence/activity.rb', line 482

def self.from_yaml(yaml)
	return self.from_yaml_object(YAML::load(yaml))
end

.from_yaml_object(yamlObject) ⇒ Object

Returns an Activity object that is represented by the YAML object. A YAML object is the object returned from a YAML::load or YAML::load_documents method. This method will automatically load a Start/FinishActivity if such a yamlObject is given.

Note: This method will only restore the reference, varios durations, description and resource parameters. Post-/pre-activities are not restored (they are restored when using Precedence::Network.from_yaml).



456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
# File 'lib/precedence/activity.rb', line 456

def self.from_yaml_object(yamlObject) #:nodoc:
	reference,activity = yamlObject.to_a[0]
	if (reference.to_s == StartActivity::REFERENCE) 
		return StartActivity.from_yaml_object(yamlObject)
	elsif (reference.to_s == FinishActivity::REFERENCE)
		return FinishActivity.from_yaml_object(yamlObject)
	else
		return Precedence::Activity.new(reference.to_s) do |act|
			act.expected_duration = activity['expected duration'].to_f
			act.minimum_duration = activity['minimum duration'].to_f
			act.maximum_duration = activity['maximum duration'].to_f
			act.description = activity['description'].to_s
			if activity['resources']
				activity['resources'].each do |resource,value|
					act.resources[resource] = value
				end
			end
		end				
	end
end

Instance Method Details

#active_during?(range) ⇒ Boolean

Returns true if the activity is active during the range given.

Note: If a range given includes the last element (range.include_end? == true) it is treated as a range that does not include the last element

Returns:

  • (Boolean)


342
343
344
345
346
347
348
349
350
351
# File 'lib/precedence/activity.rb', line 342

def active_during?(range)
	unless range.exclude_end?
		range = Range.new(range.begin,range.end,true)
	end
	
	return (range === start) || 
			((finish > range.begin) && (finish < range.end)) ||
			((start < range.begin) && (finish > range.begin))
				
end

#active_on?(time) ⇒ Boolean

Returns true if the activity is active during the time given.

Note: If an activity has a start of x and a finish of y, then

activity.active_on?(x)

will return true, while

activity.active_on?(y)

will return false.

Returns:

  • (Boolean)


333
334
335
# File 'lib/precedence/activity.rb', line 333

def active_on?(time)
	return duration_range === time
end

#add_post_activities(*post_acts) ⇒ Object

Network.connect than Activity.add_pre_activities or Activity.add_post_activities directly.



110
111
112
113
114
115
116
117
# File 'lib/precedence/activity.rb', line 110

def add_post_activities(*post_acts) #:nodoc:
	post_acts.flatten!
	post_acts.each do |activity|
		activity.register_pre_activity(self)
		register_post_activity(activity)
	end
	return post_acts
end

#add_pre_activities(*pre_acts) ⇒ Object

Adds the activities in the parameter list to the pre_activities collection of this activity and also adds this activity to the post_activities collection of each of the activities.

Note: When using the Network class it is better to use Network.connect than Activity.add_pre_activities or Activity.add_post_activities directly.



126
127
128
129
130
131
132
133
# File 'lib/precedence/activity.rb', line 126

def add_pre_activities(*pre_acts) #:nodoc:
	pre_acts.flatten!
	pre_acts.each do |activity|
		activity.register_post_activity(self)
		register_pre_activity(activity)
	end
	return pre_acts		
end

#durationObject

Returns the duration of the activity dependent on what the



378
379
380
381
382
383
384
385
386
387
388
389
390
391
# File 'lib/precedence/activity.rb', line 378

def duration
	case(duration_type)
		when MEAN_DURATION
			return mean_duration
		when EXPECTED_DURATION
			return expected_duration
		when MINIMUM_DURATION
			return minimum_duration
		when MAXIMUM_DURATION
			return maximum_duration
		else
			raise "Duration type '#{type}' is unknown."
	end
end

#duration_rangeObject

Returns a range object representing the duration of the activity. The range object return will have range.exclude_end? set to true.

Example usage:

activity.duration_range


358
359
360
# File 'lib/precedence/activity.rb', line 358

def duration_range
	return Range.new(start,finish,true)
end

#earliest_finishObject

The earliest possible time this activity can finish.



158
159
160
# File 'lib/precedence/activity.rb', line 158

def earliest_finish
	return earliest_start + duration
end

#earliest_startObject

The earliest possible time this activity can start.



163
164
165
166
167
168
169
170
171
# File 'lib/precedence/activity.rb', line 163

def earliest_start
	unless self.pre_activities.empty?
		return (pre_activities.max do |a,b|
			a.earliest_finish <=> b.earliest_finish
		end).earliest_finish
	else
		return 0.0
	end			                           		
end

#early_floatObject

The amount of float this activity has if all preceding and succeeding activities start as early as possible.

Note: In almost all practical cases this is the same as if all preceding and successing activities start as lates as possible and so no late_float method is defined.



235
236
237
238
# File 'lib/precedence/activity.rb', line 235

def early_float
	return post_activities_min_earliest_start - 
		pre_activities_max_earliest_finish	- duration	
end

#eql?(other) ⇒ Boolean Also known as: ==

Returns true if two activity objects have the same duration and reference, false otherwise.

Returns:

  • (Boolean)


316
317
318
319
320
321
322
# File 'lib/precedence/activity.rb', line 316

def eql?(other)
	if (self.reference == other.reference) and
		(self.duration == other.duration)
		return true
	end
	return false
end

#finishObject

Returns the finish time of the activity dependent on what the start_type and duration_type have been set to. This is equivalent to calling

activity.start + activity.duration


444
445
446
# File 'lib/precedence/activity.rb', line 444

def finish
	start + duration
end

#inspectObject

Redefines the inspect method.



282
283
284
# File 'lib/precedence/activity.rb', line 282

def inspect #:nodoc:
	"#{reference}(#{duration})"
end

#latest_finishObject

The latest possible time this activity can finish so as not to delay any dependent activities.



181
182
183
184
185
186
187
188
189
# File 'lib/precedence/activity.rb', line 181

def latest_finish
	unless post_activities.empty?
		return (post_activities.min do |a,b|
			a.latest_start <=> b.latest_start
		end).latest_start
	else
		return earliest_finish
	end
end

#latest_startObject

The latest possible time this activity can start so as not to delay any dependent activities.



175
176
177
# File 'lib/precedence/activity.rb', line 175

def latest_start
	return latest_finish - duration
end

#mean_durationObject

Returns the mean duration which is defined as

(4*expected_duration + minimum_duration + maximum_duration)/6


395
396
397
# File 'lib/precedence/activity.rb', line 395

def mean_duration
	return ((4*expected_duration)+minimum_duration+maximum_duration)/6.0 
end

#on_critical_path?Boolean

If the activity is on the critical path returns true, returns false otherwise.

Returns:

  • (Boolean)


215
216
217
218
219
220
221
# File 'lib/precedence/activity.rb', line 215

def on_critical_path?
	if earliest_finish == latest_finish
		return true
	else
		return false
	end
end

#remove_post_activities(*post_acts) ⇒ Object

Removes the list of activities from the post_activities collection of the activity.



137
138
139
140
141
142
143
144
# File 'lib/precedence/activity.rb', line 137

def remove_post_activities(*post_acts) #:nodoc:
	post_acts.flatten!
	post_acts.each do |activity|
		activity.deregister_pre_activity(self)
		deregister_post_activity(activity)
	end	
	return post_acts		
end

#remove_pre_activities(*pre_acts) ⇒ Object

Removes the list of activities from the pre_activities collection of the activity.



148
149
150
151
152
153
154
155
# File 'lib/precedence/activity.rb', line 148

def remove_pre_activities(*pre_acts) #:nodoc:
	pre_acts.flatten!
	pre_acts.each do |activity|
		activity.deregister_post_activity(self)
		deregister_pre_activity(activity)
	end
	return pre_acts
end

#standard_deviationObject

The standard deviation of the duration of the activity dfined as

(maximum_duraion - minimum_duration) / 6


407
408
409
# File 'lib/precedence/activity.rb', line 407

def standard_deviation
	(maximum_duration - minimum_duration)/6.0
end

#startObject

Returns the start time of the activity dependent on what the start_type has been set to.



427
428
429
430
431
432
433
434
435
436
437
438
# File 'lib/precedence/activity.rb', line 427

def start
	case(start_type)
		when EARLIEST_START
			return self.earliest_start
		when LATEST_START
			return self.latest_start
		when DROP_START
			return self.drop_start
		else
			raise "Start type '#{type}' is unknown."
	end
end

#to_aObject

Returns this activity in an Array object.



277
278
279
# File 'lib/precedence/activity.rb', line 277

def to_a #:nodoc:
	return [self]
end

#to_sObject

Redefines the to_s method



287
288
289
290
291
292
293
294
295
# File 'lib/precedence/activity.rb', line 287

def to_s #:nodoc:
	return "Reference: #{reference}\n"+
		"Description: #{description}\n"+
		"Duration: #{duration}"+
		("\nDepends on:\n " unless @pre_activities.empty?).to_s +				
		(@pre_activities.collect do |activity|
			activity.reference
		end).join(',')
end

#to_yamlObject

Returns a YAML document representing the activity object.



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/precedence/activity.rb', line 298

def to_yaml()
	"---\n#{reference}:\n"+
	(description == "" ? "" : "  description: #{description}\n")+
	(expected_duration == 0 ? "" : "  expected duration: #{expected_duration}\n")+
	(minimum_duration == 0 ? "" : "  minimum duration: #{minimum_duration}\n")+
	(maximum_duration == 0 ? "" : "  maximum duration: #{maximum_duration}\n")+
	(post_activities.empty? ? "" : "  post activities:\n") +
	(post_activities.collect do |activity|
		"    - #{activity.reference}"
	end).join("\n")+"\n"+
	(resources.empty? ? "" : "  resources:\n")+
	(resources.to_a.collect do |resource,value|
		"    #{resource}: #{value}"
	end).join("\n")+"\n"			
end

#total_floatObject

The amount of float this activity has such that it does not delay the completion of the entire precedence network.



225
226
227
# File 'lib/precedence/activity.rb', line 225

def total_float
	return latest_finish - earliest_finish
end

#varianceObject

The variance of the duration of the activity. Defined as

(maximum_duration - minimum_duration)^2/36


401
402
403
# File 'lib/precedence/activity.rb', line 401

def variance
	return standard_deviation**2
end