Title: | Perform Recursive Computations |
---|---|
Description: | Mass rollup for a Bill of Materials is an example of a class of computations in which elements are arranged in a tree structure and some property of each element is a computed function of the corresponding values of its child elements. Leaf elements, i.e., those with no children, have values assigned. In many cases, the combining function is simple arithmetic sum; in other cases (e.g., mass properties), the combiner may involve other information such as the geometric relationship between parent and child, or statistical relations such as root-sum-of-squares (RSS). This package implements a general function for such problems. It is adapted to specific recursive computations by functional programming techniques; the caller passes a function as the update parameter to rollup() (or, at a lower level, passes functions as the get, set, combine, and override parameters to update_prop()) at runtime to specify the desired operations. The implementation relies on graph-theoretic algorithms from the 'igraph' package of Csárdi, et al. (2006 <doi:10.5281/zenodo.7682609>). |
Authors: | James Steven Jenkins [aut, cre, cph] |
Maintainer: | James Steven Jenkins <[email protected]> |
License: | MIT + file LICENSE |
Version: | 0.1.0.9000 |
Built: | 2025-01-21 08:46:07 UTC |
Source: | https://github.com/jsjuni/rolluptree |
rollup()
default_validate_tree()
ensures that a tree is acyclic,
loop-free, single-edged, connected, directed, and single-rooted with edge
direction from child to parent.
default_validate_tree(tree)
default_validate_tree(tree)
tree |
|
single root vertex identifier if tree is valid; stops otherwise
default_validate_tree(wbs_tree)
default_validate_tree(wbs_tree)
df_get_by_id
returns the value of specified property (column) in a specified row
of a data frame. The row is specified by a value for the id
column.
df_get_by_id(df, idval, prop)
df_get_by_id(df, idval, prop)
df |
a data frame |
idval |
id of the row to get |
prop |
name of the column to get |
The requested value
df_get_by_id(wbs_table, "1.1", "work")
df_get_by_id(wbs_table, "1.1", "work")
df_get_by_key
returns the value of specified property (column) in a specified row
of a data frame. The row is specified by a key column and a value from that column.
df_get_by_key(df, key, keyval, prop)
df_get_by_key(df, key, keyval, prop)
df |
a data frame |
key |
name of the column used as key |
keyval |
value of the key for the specified row |
prop |
column name of the property value to get |
The requested value
df_get_by_key(wbs_table, "id", "1.1", "work")
df_get_by_key(wbs_table, "id", "1.1", "work")
The default name for a key column in rollup
is id
. df_get_ids
gets all values
from the id
column in a data frame.
df_get_ids(df)
df_get_ids(df)
df |
a data frame |
all values of the id
column
df_get_ids(wbs_table)
df_get_ids(wbs_table)
df_get_keys
gets all values from a designated column in a data frame.
df_get_keys(df, key)
df_get_keys(df, key)
df |
a data frame |
key |
name of the column used as key |
All values of the key column
df_get_keys(wbs_table, "id")
df_get_keys(wbs_table, "id")
Set property by key "id" in data frame
df_set_by_id(df, idval, prop, val)
df_set_by_id(df, idval, prop, val)
df |
a data frame |
idval |
id value for the specified row |
prop |
column name of the property value to get |
val |
value to set |
updated data frame
df_set_by_id(wbs_table, "1", "work", 45.6)
df_set_by_id(wbs_table, "1", "work", 45.6)
Set property by key in data frame
df_set_by_key(df, key, keyval, prop, val)
df_set_by_key(df, key, keyval, prop, val)
df |
a data frame |
key |
name of the column used as key |
keyval |
value of the key for the specified row |
prop |
column name of the property value to get |
val |
value to set |
The updated data frame
df_set_by_key(wbs_table, "id", "1", "work", 45.6)
df_set_by_key(wbs_table, "id", "1", "work", 45.6)
Example Fault Tree Data
fault_table
fault_table
A data frame with columns:
unique key for each row
event type ("basic", "and", or "or")
event probability
https://control.com/technical-articles/deep-dive-into-fault-tree-analysis/
Example Fault Tree
fault_tree
fault_tree
An igraph tree with edges from child id to parent id.
https://control.com/technical-articles/deep-dive-into-fault-tree-analysis/
rollup()
traverses a tree depth-first (post order) and calls a
user-specified update function at each vertex, passing the method a data set,
the unique key of that target vertex in the data set, and a list of source
keys. The update method typically gets some properties of the source
elements of the data set, combines them, sets some properties of the
target element of the data set to the combined value, and returns the
updated data set as input to the update of the next vertex. The final
operation updates the root vertex.
An update_prop()
helper function is available to simplify building
compliant update methods.
Before beginning the traversal, rollup()
calls a user-specified method to
validate that the tree is well-formed (see default_validate_tree()
). It
also calls a user-specified method to ensure that the id sets of the tree
and data set are identical, and that data set elements corresponding to
leaf vertices in the tree satisfy some user-specified predicate, e.g.,
is.numeric()
.
rollup(tree, ds, update, validate_ds, validate_tree = default_validate_tree)
rollup(tree, ds, update, validate_ds, validate_tree = default_validate_tree)
tree |
|
ds |
data set to be updated; can be any object |
update |
function called at each vertex as update(ds, parent_key, child_keys) |
validate_ds |
data set validator function called as validate_ds(tree, ds) |
validate_tree |
tree validator function called as validate_tree(tree) |
The data set passed to rollup()
can be any object for which an
update function can be written. A common and simple example is a data
frame, but lists work as well.
updated input data set
rollup(wbs_tree, wbs_table, update = function(d, p, c) { if (length(c) > 0) d[d$id == p, c("work", "budget")] <- apply(d[is.element(d$id, c), c("work", "budget")], 2, sum) d }, validate_ds = function(tree, ds) TRUE )
rollup(wbs_tree, wbs_table, update = function(d, p, c) { if (length(c) > 0) d[d$id == p, c("work", "budget")] <- apply(d[is.element(d$id, c), c("work", "budget")], 2, sum) d }, validate_ds = function(tree, ds) TRUE )
update_df_prop_by_id()
is a convenience wrapper around update_prop()
for the common case in which the data set is a data frame whose key column
is named "id"
update_df_prop_by_id(df, target, sources, prop, ...)
update_df_prop_by_id(df, target, sources, prop, ...)
df |
a data frame |
target |
key of data set element to be updated |
sources |
keys of data set elements to be combined |
prop |
column name of the property |
... |
other arguments passed to |
The updated dataframe
update_df_prop_by_id(wbs_table, "1", list("1.1", "1.2"), "work")
update_df_prop_by_id(wbs_table, "1", list("1.1", "1.2"), "work")
update_df_prop_by_key()
is a convenience wrapper around update_prop()
for the common case in which the data set is a data frame.
update_df_prop_by_key(df, key, target, sources, prop, ...)
update_df_prop_by_key(df, key, target, sources, prop, ...)
df |
a data frame |
key |
name of the column serving as key |
target |
key of data set element to be updated |
sources |
keys of data set elements to be combined |
prop |
column name of the property |
... |
other arguments passed to |
The updated data frame
update_df_prop_by_key(wbs_table, "id", "1", list("1.1", "1.2"), "work")
update_df_prop_by_key(wbs_table, "id", "1", list("1.1", "1.2"), "work")
update_prop
calls user-specified methods to get properties
of a source set of elements in a data set, combine those properties,
and set the properties of a target element to the combined value.
If the source set is empty, the data set is returned unmodified. The
default combine operation is addition.
The override
argument can be used to selectively override the
computed value based on the target element. By default, it simply
returns the value computed by the combiner.
update_prop( ds, target, sources, set, get, combine = function(l) Reduce("+", l), override = function(ds, target, v) v )
update_prop( ds, target, sources, set, get, combine = function(l) Reduce("+", l), override = function(ds, target, v) v )
ds |
data set to be updated |
target |
key of data set element to be updated |
sources |
keys of data set elements to be combined |
set |
function to set properties for a target element called as set(ds, key, value) |
get |
function to get properties for source elements called as get(ds, key) |
combine |
function to combine properties called as combine(vl) |
override |
function to selectively override combined results called as override(ds, key,) |
updated data set
update_prop(wbs_table, "1", list("1.1", "1.2"), function(d, k, v) {d[d$id == k, "work"] <- v; d}, function(d, k) d[d$id == k, "work"] ) update_prop(wbs_table, "1", list("1.1", "1.2"), function(d, k, v) {d[d$id == k, c("work", "budget")] <- v; d}, function(d, k) d[d$id == k, c("work", "budget")], function(l) Reduce("+", l) )
update_prop(wbs_table, "1", list("1.1", "1.2"), function(d, k, v) {d[d$id == k, "work"] <- v; d}, function(d, k) d[d$id == k, "work"] ) update_prop(wbs_table, "1", list("1.1", "1.2"), function(d, k, v) {d[d$id == k, c("work", "budget")] <- v; d}, function(d, k) d[d$id == k, c("work", "budget")], function(l) Reduce("+", l) )
update_rollup()
performs a minimal update of a data set assuming a single leaf element property
has changed. It performs updates along the path from that vertex to the root. There should be no difference
in the output from calling rollup()
again. update_rollup()
is perhaps more efficient and useful in an interactive context.
update_rollup(tree, ds, vertex, update)
update_rollup(tree, ds, vertex, update)
tree |
|
ds |
data set to be updated; can be any object |
vertex |
The start vertex |
update |
function called at each vertex as update(ds, parent_key, child_keys) |
updated input data set
update_rollup(wbs_tree, wbs_table, igraph::V(wbs_tree)["3.2"], update = function(d, p, c) { if (length(c) > 0) d[d$id == p, c("work", "budget")] <- apply(d[is.element(d$id, c), c("work", "budget")], 2, sum) d } )
update_rollup(wbs_tree, wbs_table, igraph::V(wbs_tree)["3.2"], update = function(d, p, c) { if (length(c) > 0) d[d$id == p, c("work", "budget")] <- apply(d[is.element(d$id, c), c("work", "budget")], 2, sum) d } )
rollup()
validate_df_by_id()
is a convenience wrapper for validate_ds()
for the common case in which the
data set is a data frame with key column named "id".
validate_df_by_id(tree, df, prop, ...)
validate_df_by_id(tree, df, prop, ...)
tree |
tree to validate against |
df |
data frame |
prop |
property whose value is checked (leaf elements only) |
... |
other parameters passed to validate_ds() |
TRUE if validation succeeds, halts otherwise
validate_df_by_id(wbs_tree, wbs_table, "work")
validate_df_by_id(wbs_tree, wbs_table, "work")
rollup()
validate_df_by_key()
is a convenience wrapper for validate_ds()
for the common case in which the
data set is a dataframe.
validate_df_by_key(tree, df, key, prop, ...)
validate_df_by_key(tree, df, key, prop, ...)
tree |
tree to validate against |
df |
data frame |
key |
name of the column serving as key |
prop |
property whose value is checked (leaf elements only) |
... |
other parameters passed to validate_ds() |
TRUE if validation succeeds, halts otherwise
validate_df_by_key(wbs_tree, wbs_table, "id", "work")
validate_df_by_key(wbs_tree, wbs_table, "id", "work")
rollup()
validate_ds()
ensures that a data set contains the same identifiers as a specified tree and that
elements of the data set corresponding to leaf vertices in the tree satisfy a user-specified predicate.
validate_ds( tree, ds, get_keys, get_prop, op = function(x) is.numeric(x) & !is.na(x) )
validate_ds( tree, ds, get_keys, get_prop, op = function(x) is.numeric(x) & !is.na(x) )
tree |
|
ds |
data set to be updated; can be any object |
get_keys |
function to get keys of the data set called as |
get_prop |
function to get the property value to validate for leaf element with id |
op |
logical function to test return value of |
TRUE if validation succeeds, halts otherwise
validate_ds(wbs_tree, wbs_table, function(d) d$id, function(d, l) d[d$id == l, "work"])
validate_ds(wbs_tree, wbs_table, function(d) d$id, function(d, l) d[d$id == l, "work"])
Example Work Breakdown Structure Data
wbs_table
wbs_table
A data frame with columns:
unique key for each row
parent key for each row
character name of the element
percent of total work for this element
budget for this element
https://www.workbreakdownstructure.com
Example Work Breakdown Structure Data After Rollup
wbs_table_rollup
wbs_table_rollup
A data frame with columns:
unique key for each row
parent key for each row
character name of the element
percent of total work for this element
budget for this element
https://www.workbreakdownstructure.com
Example Work Breakdown Structure Data
wbs_tree
wbs_tree
An igraph tree with edges from child id to parent id.
https://www.workbreakdownstructure.com