Skip to content

Instantly share code, notes, and snippets.

@robertbrook
Last active February 16, 2021 19:00
Show Gist options
  • Save robertbrook/b0d6dd21ed3c9dc28c93679b485c6dc0 to your computer and use it in GitHub Desktop.
Save robertbrook/b0d6dd21ed3c9dc28c93679b485c6dc0 to your computer and use it in GitHub Desktop.
# this code gets all routes and processes in whatever order they emerge from the database (randomly)
# in order to ensure routes are parsed correctly, we need to ensure that all inbound routes to a step are parsed before we parse the outbound route
# this means we need to start at the start step, acknowledging that some procedure maps have more than one start step
# in order to do this we need to ...
# hard code an array of start steps
# start step for PNSI: u7VOBBH0
procedure.pnsi.start_steps = [u7VOBBH0]
# start steps for draft negative: wShvPQbP, j4iPxsxb
procedure.draft_negative.start_steps = [wShvPQbP, j4iPxsxb]
# start steps for made negative: wShvPQbP, j4iPxsxb
procedure.made_negative.start_steps = [wShvPQbP, j4iPxsxb]
# move this into procedure model alongside conclusion steps as part of step collection
# these routes will be returned unsorted
# get an array of routes in the procedure
routes = []
for route in routes
# this will record whether the route is current or whether it ended in the past or starts in the future
# add a boolean attribute of current with value NULL
route.current = NULL
# this will record the state of the route as it's parsed, being NULL, TRUE, FALSE or UNTRAVERSABLE
# add a string attribute of status with value NULL
route.status = NULL
# this will record whether a route has been fully parsed or not
# routes being output from an AND or an OR step may need to be parsed more than once depending on the parse order
# it is possible therefore for a route to have a parsed state of not NULL but to still not be fully parsed
# all routes start unparsed - obviously
# add a boolean attribute of parsed with value FALSE
route.parsed = FALSE
end
# Looping through all the routes until all routes are parsed, remembering they are unsorted
for route in routes
if route.parsed == TRUE
log "parsed route", route
else
# which step does the route come from?
# this is 'fromStep' in the procedure model
# get the source step of the route
# check the type of the source step and process accordingly
# BUSINESS STEP
if route.source_step == business_step
# we expect a business step to have one and only one input
if route.source_step.inputs != 1
log "unexpected number of inputs", route.source_step
else
# check if we're trying to parse a route before we have parsed the immediately preceding route
# because we're in a loop, this has the effect of all preceding routes needing to be parsed before the current route can be
if route.parsed = FALSE
# the default behaviour when trying to parse a route from a business step is to not parse if the immediately preceding route has not yet been parsed
if !(start_steps.include?(route.source_step))
# do nothing with this route
# proceed - via the loop - to the next route in the array and attempt to parse that
# we will attempt to parse this route again on the next and subsequent loops
# we do not parse a route until all inbounds up the tree have been parsed
# this is a brute force, breadth first traversal
# which is a recursion explosion?!?
# exception for start steps to force the parsing to start
# otherwise if the step is in the array of start steps
# ignore the state and time boundedness of the inbound routes of start steps or no route will ever get parsed
# and we'd be stuck in an infinte loop
# this should, in theory, force us to traverse the graph from the start steps
# check whether the route we're parsing is current
# if it's not current ...
if (route.start_date > today) or (route.end_date < today)
route.status = UNTRAVERSABLE
route.current = FALSE
route.parsed = TRUE
# if the route we're parsing is current ...
elsif route.current == TRUE
route.current = TRUE
route.parsed = TRUE
if (route.source_step.actualised.past?) or (route.source_step.actualised == today)
route.status = TRUE
elsif (route.source_step.actualised.future?) or (no date)
route.status = NULL
elsif route.source_step.actualised == ""
route.status = NULL
end
end
end
# attempt to parse a route from a business step where the inbound route to that step has already been parsed
if input route.parsed == TRUE
route.parsed = TRUE
# if the route is not current
if (route.start_date > today) or (route.end_date < today)
route.status = UNTRAVERSABLE
route.current = FALSE
# if the route is current
elsif !(route.start_date > today) and !(route.end_date < today)
route.current = TRUE
if input route.value == UNTRAVERSABLE
# taint the roads off the bridge as closed if the bridge is closed
route.status = UNTRAVERSABLE
elsif input route.value != UNTRAVERSABLE
if (route.source_step.actualised.past?) or (route.source_step.actualised == today)
route.status = TRUE
elsif (route.source_step.actualised.future?) or (route.source_step.actualised == "")
route.status = NULL
# elsif (source step is not actualised)
elsif !(route.source_step == actualised)
route.status = NULL
end
end
end
end
end
# AND gate
elsif (route.source_step == "AND step")
if !(route.source_step is the target step for two routes)
log "unexpected number of inputs", route
elsif route.source_step is the target step of two routes
if both input routes to the route.source_step .parsed == TRUE
route.parsed = TRUE
if (route.start_date.future?) or (route.end_date.past?)
route.value = UNTRAVERSABLE
route.current = FALSE
elsif !(route.start_date.future?) and !(route.end_date.past?)
route.current = TRUE
# process as per AND gate logic
# https://ukparliament.github.io/ontologies/procedure/flowcharts/meta/design-notes/#truth-table-and
end
elsif (one input route to the source step has a parsed attribute of TRUE) and (the other has a parsed attribute of FALSE)
if (route.start_date.future?) or (route.end_date.past?)
route.value = UNTRAVERSABLE
route.current = FALSE
elsif !(route.start_date.future?) and !(route.end_date.past?)
route.current = TRUE
# process as per AND gate logic
# pass in the status attribute of the unparsed input route as NULL
# we're assuming that the unparsed input has a value of NULL until we return to this route with both inputs parsed
# this route will be reparsed once both inputs have been parsed
# https://ukparliament.github.io/ontologies/procedure/flowcharts/meta/design-notes/#truth-table-and
end
elsif both input routes to the source step .parsed == FALSE
# do nothing and pick up on next loop
# this is forcing traversal from the start
end
end
# OR gate
elsif (route.source_step == "OR step")
if the OR step is the target step for less than or more than two routes
log an error: unexpected number of inputs
elsif the source OR step is the target step of two routes
if both input routes to the source step have a parsed attribute of TRUE
route.parsed = TRUE
if (route.start_date > today) or (route.end_date < today)
route.value = UNTRAVERSABLE
route.current = FALSE
elsif !(route.start_date > today) and !(route.end_date < today)
route.current = TRUE
# process as per OR gate logic
# https://ukparliament.github.io/ontologies/procedure/flowcharts/meta/design-notes/#truth-table-or
end
elsif one input route to the source step has a parsed attribute of TRUE and the other has a parsed attribute of FALSE
if (route.start_date is greater than today) or (its end date is less than today)
route.value = UNTRAVERSABLE
route.current = FALSE
elsif the route's start date is not greater than today and its end date is not less than today
set the route current attribute to TRUE
# process as per OR gate logic
# pass in the status attribute of the unparsed input route as NULL
# we're assuming that the unparsed input has a value of NULL until we return to this route with both inputs parsed
# this route will be reparsed once both inputs have been parsed
# https://ukparliament.github.io/ontologies/procedure/flowcharts/meta/design-notes/#truth-table-or
end
elsif both input routes to the source step have a parsed attribute of FALSE
# do nothing and pick up on next loop
# this is forcing traversal from the start
end
end
# NOT gate
elsif (route.source_step == "NOT step")
if the NOT step is the target step for less than or more than one route
log an error: unexpected number of inputs
elsif the source NOT step is the target step of one route
if the input route parsed attribute is FALSE
# do nothing and pick up on next loop
# this is forcing traversal from the start
elsif the input route parsed attribute is TRUE
route.parsed = TRUE
if (route.start_date is greater than today) or (its end date is less than today)
route.value = UNTRAVERSABLE
route.current = FALSE
elsif (route.start_date is not greater than today) and (its end date is not less than today)
route.current = TRUE
# process as per NOT gate logic
# https://ukparliament.github.io/ontologies/procedure/flowcharts/meta/design-notes/#truth-table-not
end
end
end
# Decision step
elsif (route.source_step == "decision step")
if !(the decision step is the target step for one route)
log "unexpected number of inputs", route
elsif the source decision step is the target step of one route
if the input route .parsed == FALSE
# do nothing and pick up on next loop
# this is forcing traversal from the start
elsif the input route parsed == TRUE
route.parsed = TRUE
if (route.start_date.future?) or (route.end_date.past?)
route.value = UNTRAVERSABLE
route.current = FALSE
elsif !(route.start_date.future?) and !(route.end_date.past?)
route.current = TRUE
# process as per decision step logic
# htps://ukparliament.github.io/ontologies/procedure/flowcharts/meta/design-notes/#truth-table-decision
end
end
end
end
# END OF ROUTE PARSING
# having parsed the route and established its state, we can now look at the target step and, if it's a business step, set its potential state
get the target step of the route
if route.target_step is a business step
if route.value == TRUE
flag target business step as CAUSED TO BE ACTUALISED
elsif route.value == ALLOWS
flag the target step as ALLOWED TO BE ACTUALISED
# theoretically reachable given current procedural "rules"
# future potential state
# for example, a question on a fatal motion has not been put because no fatal motion has been tabled yet and may possibly never be
elsif (route.value == NULL) or (route.value == FALSE)
flag target step as NOT YET ACTUALISABLE
end
# not theoretically reachable given current procedural "rules"
# for example, EVEL standing order suspension
# the bridge is closed so steps on the far side cannot be reached unless the bridge opens
elsif route.value == UNTRAVERSABLE
flag target step as NOT NOW ACTUALISABLE
elsif the target step is a logic step or decision step
# do nothing and pick up on next loop
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment