Open danbryce opened 2 years ago
I think there are at least two ways to approach this, and in thinking about them I believe that it will be important to distinguish between a constraint and a tolerance in our representations.
The distinction between these, in my thinking, is that a constraint ends up being something that is managed by PAML, whereas a tolerance is something that is managed by the execution environment.
As a driving example, consider two protocols that include a fermentation step where the temperature can be anywhere between 20C and 30C.
The incubate
primitive in the plate_handling
library currently allows one to specify a temperature (25C) but not the tolerance or range.
Ways that we might express these additional relations:
Constraints: A Behavior
(Primitive
or Protocol
) can have associated precondition
and postcondition
constraints that can be checked by the execution engine before and after the execution of the Behavior
. The postcondition
constraint can be used for behavior during execution by looking at records (e.g., "all temperature records must be the the range of 20C - 30C, and there must be a record every 5 minutes"). An execution environment can look at the postcondition
in order to modulate its behavior. However, because this is supplied to a Behavior
and not a CallBehaviorAction
, the same postcondition
would have to be applied to all uses of incubate
. To supply a specific value, like 20C - 30C, we would need to add a postcondition
field to CallBehaviorAction
(or a parent class such as Action
or even ActivityNode
). I'm not comfortable they we understand what all the implications of doing that would be.
Inputs: Alternately, we can enhance the incubate
primitive with additional inputs that can be used to express tolerances or ranges. Under this model, the incubate
primitive would add an optional temperature_tolerance
parameter and/or optional temperature_range
parameters. Any execution environment implementing incubate
(whether humans or machines) would then need to decide what, if anything, to do with these extra parameters, and we will need to add extra parameters individually to each primitive. We can try to be systematic, but inevitably there will be heterogeneity across primitives in various libraries.
Generalize Measure
to allow precision and ranges information: Most places where we'd want to express a range or tolerance are related to parameters with type Measure
. While our current usage of Measure
has exact values, this class could be extended (either in PAML or in OM) to include an optional notion of precision or range in measure, rather than only being exact values. This would then be consistent across every primitive that uses measurements in its arguments. Execution environments would implement by deciding for each primitive what levels of precision they can or wish to support.
Of these three alternatives, I think the third may be the cleanest.
Need to support protocol constraints. First use case is for bounding parameters. @danbryce suggested that we extend the UML Constraint for parameters and to attach the constraints to the precondition of the protocol.