Re: Rules in archetypes - what are the requirements?

2019-02-04 Thread Pieter Bos


From: openEHR-technical  on behalf 
of Thomas Beale 
Reply-To: For openEHR technical discussions 

Date: Saturday, 2 February 2019 at 20:10
To: "openehr-technical@lists.openehr.org" 
Subject: Re: Rules in archetypes - what are the requirements?



On 02/02/2019 16:21, Pieter Bos wrote:

From: openEHR-technical 
<mailto:openehr-technical-boun...@lists.openehr.org>
 on behalf of Thomas Beale 
<mailto:thomas.be...@openehr.org>
Reply-To: For openEHR technical discussions 
<mailto:openehr-technical@lists.openehr.org>
Date: Saturday, 2 February 2019 at 15:01
To: 
"openehr-technical@lists.openehr.org"<mailto:openehr-technical@lists.openehr.org>
 
<mailto:openehr-technical@lists.openehr.org>
Subject: Re: Rules in archetypes - what are the requirements?


Assuming you meant to put 'id7' as the first one, I don't understand what this 
achieves beyond just:

/events[id2]/data/items/element[id7]/value/magnitude >
/events[id2]/data/items/element[id4]/value/magnitude +
/events[id2]/data/items/element[id5]/value/magnitude +
/events[id2]/data/items/element[id6]/value/magnitude

which says the same thing, for all events in the runtime data that conform to 
the /events[id2] branch of the structure.

Since the occurrences of events[id2] can be more than one, 
/events[id2]/data/items/element[id7]/value/magnitude in the execution 
environment (actual data) maps to  a List.

well it could be understood that way - that would be to literally interpret it 
as a runtime path. The way I think of it is to mean 'this condition xyz must 
hold true' for each instance to which it applies. This greatly simplifies 
things - otherwise you end up in a complicated place like you have described 
below.

If not runtime but archetype paths, eventually you need to apply them to 
runtime data to evaluate. There are several ways of doing that – one way is 
what I did in Archie. Another one that I considered was automatically detecting 
common parent objects with effective_occurrences potentially > 1 and 
automatically adding for_all, plus some validation  – less code, but more 
complex code. Another one is requiring for_all statements written by the rule 
modeler/developer (this is not possible in the published draft without your 
relative path proposal below). There are more ways to do this. Each one will 
operate differently in different edge cases, if this is not specified.

If however you do your ‘this path is relative to the other one’ context binding 
below, with a for_all that works with these path bindings, I think that should 
solve most of the problems.

the Expression Language 
draft<https://specifications.openehr.org/releases/LANG/latest/expression_language.html#_defined_predicate>
 has the defined() predicate which I think should do the job.

It should, when combined with the new if-statement that is much more powerful 
than the implies-statement in the previous version.

However, it has some interesting implications when combined with the “'this 
condition xyz must hold true for each instance to which it applies”-idea 
specified above if not combined with an explicit for_all. Because also the 
corresponding defined()-check must be done for each instance. That’s the reason 
I integrated null-handling as ‘if an assertion/check has a null value, that 
means it’s missing data required to evaluate it. So the assertions is not 
relevant, meaning that it passes’. Then you can manually specify exists/defined 
conditions if you need them.

It would still be Real. The idea is that the path is relative to an EVENT, 
although that is not clear from the above. Perhaps something like:

$item_aaa -> (EVENT)/data/items/element[id7]/value/magnitude

That would solve it.

That would solve the problem. Why not just inline the assignments, such as:

$events := /events[id2]

this was in a previous draft. But I am pretty convinced we don't want to mix 
paths in with the main 'code'. This is particularly the case if we want to use 
TypeScript or some other mainstream language to write the main statements in - 
the bindings need to be separate.

I'll have more of a think about how the bindings should work.

If typescript/javascript (typescript compiles to javascript before execution), 
that will change quite a lot about the discussion before.

Since a path query is just a string, it’s not so hard to create an (included) 
path lookup function and an ‘assign value to this path’ function.

Regards,

Pieter Bos

___
openEHR-technical mailing list
openEHR-technical@lists.openehr.org
http://lists.openehr.org/mailman/listinfo/openehr-technical_lists.openehr.org


Re: Rules in archetypes - what are the requirements?

2019-02-02 Thread Thomas Beale


On 02/02/2019 16:21, Pieter Bos wrote:


*From: *openEHR-technical 
 on behalf of Thomas 
Beale 
*Reply-To: *For openEHR technical discussions 


*Date: *Saturday, 2 February 2019 at 15:01
*To: *"openehr-technical@lists.openehr.org" 


*Subject: *Re: Rules in archetypes - what are the requirements?

Assuming you meant to put 'id7' as the first one, I don't understand 
what this achieves beyond just:


/events[id2]/data/items/element[id7]/value/magnitude >
    /events[id2]/data/items/element[id4]/value/magnitude +
    /events[id2]/data/items/element[id5]/value/magnitude +
    /events[id2]/data/items/element[id6]/value/magnitude

which says the same thing, for all events in the runtime data that 
conform to the /events[id2] branch of the structure.


Since the occurrences of events[id2] can be more than one, 
/events[id2]/data/items/element[id7]/value/magnitude in the execution 
environment (actual data) maps to  a List.


well it could be understood that way - that would be to literally 
interpret it as a runtime path. The way I think of it is to mean 'this 
condition xyz must hold true' for each instance to which it applies. 
This greatly simplifies things - otherwise you end up in a complicated 
place like you have described below.


That means you need to define operators such as +, > and = on a list 
of reals. Or to define somehow that a statement containing only path 
bindings within a single multiply-occurring structure will mean that 
it gets evaluated for each occurrence of such a structure. The second 
case is complicated if you need to include data outside /events[id2] 
in your expression. A real world use case would be data in /protocol, 
which can influence the interpretation of event data, but is outside 
of the event.
So we did the first in Archie, with a bit of tricks to make this work 
for assignments. For example, how the plus operator is interpreted in 
Archie:


+(Real r1, Real r2)
  return the sum both numbers
...
Much of this complexity can be avoided by  not defining the operator 
on lists/sets, and requiring the for_all loop on lists or sets of data 
in the specification. This comes at a price, because the author of the 
expressions needs to understand more of the language and data 
structures. So we chose the second, since the previous draft 
specification did not specify at all how to handle these cases.


Undefined value handling is another subject, I have not checked yet if 
the new proposal solves it. We defined some functions to handle this 
explicitly if the automatic handling doesn’t do it ((input , 
alternative) -> return input  unless input is undefined, then 
alternative), as well as some rounding functions.


the Expression Language draft 
<https://specifications.openehr.org/releases/LANG/latest/expression_language.html#_defined_predicate> 
has the defined() predicate which I think should do the job.



If we were to allow the expression for_all $event in /data/events[id3] 
then we need to be clear on what it means: it actually refers to an 
object of type List, but do the members consist of EVENT 
objects found in data at the moment the expression is evaluated? Or 
just the statically defined members in the archetype - which can also 
be multiple, e.g. see the Apgar archetype, it has 1 min, 2 min, 5 min 
events?


You would need to evaluate on actual data. If you define it on the 
archetype data, you would need some kind of rules to convert it to an 
evaluation on actual data with different multiplicities than the rules 
specify, for example if events[id2] has occurrences > 1. Might be 
possible, I have not tried to define that. Would probably include some 
extra for_all loops plus some kind of validation errors for cases that 
cannot be converted.
So I would say always the data found at the moment which the 
expression is evaluated. You can still refer to separate statically 
defined members using their distinct node ids, and even those could 
have occurrences > 1 (not in the apgar example since those have 
occurrences {0..1} in the archetype).


Normally we want the processing of 'rules' expressions in archetypes 
to apply to the data when the archetype is being used in its normal 
role of creation / semantic validation at data commit time.


Agreed.

So it seems to me that if we want to support expressions like the 
above, we need to be able to do something like (don't worry about the 
concrete syntax too much, could easily be TS or java-flavoured):


*use_model*
    org.openehr.rm

*data_context*

$xxx_events: List
    $item_aaa, $item_bbb, $item_ccc, $item_ddd: Real

*definition*

check for_all event in $xxx_events:
    event/$item_aaa > event/$item_bbb + event/$item_ccc + 
event/$item_ddd


*data_bindings*-- pseudo-code for now

$xxx_events -> /events[id2]
    $item_aaa -> /data/items/element[id7]/value/magnitude
    $item_bbb -> /data/items/element[id4]/value/magnitude
    $item_ccc -> /data/it

Re: Rules in archetypes - what are the requirements?

2019-02-02 Thread Pieter Bos

From: openEHR-technical  on behalf 
of Thomas Beale 
Reply-To: For openEHR technical discussions 

Date: Saturday, 2 February 2019 at 15:01
To: "openehr-technical@lists.openehr.org" 
Subject: Re: Rules in archetypes - what are the requirements?


Assuming you meant to put 'id7' as the first one, I don't understand what this 
achieves beyond just:

/events[id2]/data/items/element[id7]/value/magnitude >
/events[id2]/data/items/element[id4]/value/magnitude +
/events[id2]/data/items/element[id5]/value/magnitude +
/events[id2]/data/items/element[id6]/value/magnitude

which says the same thing, for all events in the runtime data that conform to 
the /events[id2] branch of the structure.

Since the occurrences of events[id2] can be more than one, 
/events[id2]/data/items/element[id7]/value/magnitude in the execution 
environment (actual data) maps to  a List. That means you need to define 
operators such as +, > and = on a list of reals. Or to define somehow that a 
statement containing only path bindings within a single multiply-occurring 
structure will mean that it gets evaluated for each occurrence of such a 
structure. The second case is complicated if you need to include data outside 
/events[id2] in your expression. A real world use case would be data in 
/protocol, which can influence the interpretation of event data, but is outside 
of the event.
So we did the first in Archie, with a bit of tricks to make this work for 
assignments. For example, how the plus operator is interpreted in Archie:

+(Real r1, Real r2)
  return the sum both numbers
+(Real r1, List r2)
   return a list the same size as r2, with every element result[i] = r1 + r2[i]
+(List r1, r2)
   return a list the same size as r1, with every element result[i] = r1[i] + r2
+(Listl r1, List r2)
  if r1 and r2 have different length, throw an exception. Otherwise, return a 
list the same size as r1, with every element result[i] being r1[i] + r2[i]

And the > operator:

>(Real r1, Real r2)
  return true if r1 > r2, false otherwise
>(Real r1, List r2)
  return a list of Booleans, one for every element in r2, true if r1 > that 
element
>(List r1, r2)
  return a list of Booleans, one for every element in r1, true if that element 
> r2
>(Listl r1, List r2)
  if r1 and r2 have different length, throw an exception. Otherwise, return a 
list of Booleans, with every element result[i] being r1[i] > r2[i]

This is a simplification, in reality there is null-handling and integer-> real 
conversion involved, which is also missing in the specification I think.
We defined assertions/checks to only succeed if every Boolean in such a list is 
true or null/undefined (to not fail on data which is optional). Additionally in 
Archie every value returned contains every unique path in the data that was 
used to evaluate it, so you can see exactly for which data an assertion/check 
failed in the result, to notify the user where the problem occurs. Or to apply 
an assignment to the correct output if the output path does not match a single 
field. This last bit is implementation specific of course.

Much of this complexity can be avoided by  not defining the operator on 
lists/sets, and requiring the for_all loop on lists or sets of data in the 
specification. This comes at a price, because the author of the expressions 
needs to understand more of the language and data structures. So we chose the 
second, since the previous draft specification did not specify at all how to 
handle these cases.

Undefined value handling is another subject, I have not checked yet if the new 
proposal solves it. We defined some functions to handle this explicitly if the 
automatic handling doesn’t do it ((input , alternative) -> return input  unless 
input is undefined, then alternative), as well as some rounding functions.

If we were to allow the expression for_all $event in /data/events[id3] then we 
need to be clear on what it means: it actually refers to an object of type 
List, but do the members consist of EVENT objects found in data at the 
moment the expression is evaluated? Or just the statically defined members in 
the archetype - which can also be multiple, e.g. see the Apgar archetype, it 
has 1 min, 2 min, 5 min events?

You would need to evaluate on actual data. If you define it on the archetype 
data, you would need some kind of rules to convert it to an evaluation on 
actual data with different multiplicities than the rules specify, for example 
if events[id2] has occurrences > 1. Might be possible, I have not tried to 
define that. Would probably include some extra for_all loops plus some kind of 
validation errors for cases that cannot be converted.
So I would say always the data found at the moment which the expression is 
evaluated. You can still refer to separate statically defined members using 
their distinct node ids, and even those could have occurrences > 1 (not in the 
apgar examp

Re: Rules in archetypes - what are the requirements?

2019-02-02 Thread Pieter Bos
vation. So if you really want them to be 
typed on validation time, you need to check every attribute in the path to see 
if it can point to more than one value, then either make it a 
List> or define in which order to add it as a single list.
I implemented it by determining type at runtime, but it’s possible otherwise. 
This means that very often you need a for all statement, in which case data 
binding doesn’t really help. I defined some tricks with the basic operators 
also working on equally sized lists to make things a bit easier to understand 
for modelers. That’s why I asked about the execution rules. The tricks I did 
can be easily rewritten into for_all statements if we need to have them removed.

This leads to more interesting cases when you flatten rules to an OPT 2 
template, to obtain a single artifact that can be used for many things, 
including rule evaluation. That is very doable right now by prepending some 
paths and adding some for_all statements. I’m not sure how to do that with data 
binding.

Regards,


Pieter Bos

From: openEHR-technical 
mailto:openehr-technical-boun...@lists.openehr.org>>
 on behalf of Thomas Beale 
mailto:thomas.be...@openehr.org>>
Reply-To: For openEHR technical discussions 
mailto:openehr-technical@lists.openehr.org>>
Date: Friday, 1 February 2019 at 14:16
To: 
"openehr-technical@lists.openehr.org<mailto:openehr-technical@lists.openehr.org>"
 
mailto:openehr-technical@lists.openehr.org>>
Subject: Re: Rules in archetypes - what are the requirements?


Thanks Pieter,

this is very useful.
On 01/02/2019 12:54, Pieter Bos wrote:
For us the main requirement of the rules is to calculate the value of other 
fields based on other fields. Only the checking of assertions has relatively 
little added value for the use cases our customers encounter. I would find it 
very hard to explain to any users or modelers that they can write checks that 
do the actual score calculation, but that they cannot actually use the 
calculated value anywhere. So we ignore this limitation altogether.

the obvious solution to that requirement seems to be to a) use functions and b) 
to allow assignment:

rules
-- assert that manually set total is correct
check $apgar_total_value == apgar_total ($apgar_heartrate_value, 
$apgar_breathing_value, $apgar_reflex_value, $apgar_muscle_value, 
$apgar_colour_value)



rules
-- assign total value
$apgar_total_value = apgar_total ($apgar_heartrate_value, 
$apgar_breathing_value, $apgar_reflex_value, $apgar_muscle_value, 
$apgar_colour_value)



Also the value binding seems to have an case that has not been covered:


it is possible that a single path lookup results in a list of values. This 
means a single path-bound variable will contain multiple values (so a list of 
values). In the old case, you could handle this with a for_all statement to 
express that the assertion should be valid within the scope of a single event, 
for all events. How could value binding solve this? The same question applies 
to output variable binding as well as input variable binding.

conceptually, rules statements are typed, so in this case, the type will be 
List or List or whatever. In that case, expressions need to 
treat it in the normal way, i.e. with List or Set operators that obtain single 
values. E.g.

$systolic_bp_samples: List

there_exists v in $systolic_bp_samples : v > Systolic_bp_threshold implies 

These kinds of things (and for_all) are documented in the Expression Language 
draft<https://specifications.openehr.org/releases/LANG/latest/expression_language.html#_collection_operators>.

Related to this, both the current and proposed specification is missing 
execution rules, especially when paths lookup to a list of values instead of a 
single variable and how to handle that. For example what does the following 
mean when /data/events/data/items/element[id3]/value/magnitude resolves to more 
than one value?

I don't see how it can, since that path is defined to be of type Real (not 
List or Set etc) by the RM definition of DvQuantity. But I'm 
probably missing something in the sense of your question...

Anyway, the more I can find out about current requirements, working solutions, 
workaround etc, the better - the intention is to evolve the expression facility 
in archetypes to match those needs and to be as useful as possible.

- thomas


___
openEHR-technical mailing list
openEHR-technical@lists.openehr.org<mailto:openEHR-technical@lists.openehr.org>
http://lists.openehr.org/mailman/listinfo/openehr-technical_lists.openehr.org
___
openEHR-technical mailing list
openEHR-technical@lists.openehr.org
http://lists.openehr.org/mailman/listinfo/openehr-technical_lists.openehr.org


Re: Rules in archetypes - what are the requirements?

2019-02-02 Thread Thomas Beale


On 02/02/2019 13:15, Ian McNicoll wrote:

Hi Pieter,

"But why would I need a function to calculate a score that is just a 
sum of a number of values, instead of a few +-operators?"


It is an open question but one advantage of using the function 
approach, with simple values is that it can encapsulate the algorithm 
without too much dependency on understanding openEHR paths or path 
-bindings. That should allow broader engagement with non-openEHR 
specialists.


My preference is to support use of openEHR datatypes within the 
expression (albeit perhaps in reduced format), as otherwise passing 
units etc as scalars starts to get cumbersome.


agree - that is the idea of this construct in the EL

*use_model*
    org.openehr.rm

then you can declare vars to be of RM types like DvQuantity, DvOrdinal etc.

- t


___
openEHR-technical mailing list
openEHR-technical@lists.openehr.org
http://lists.openehr.org/mailman/listinfo/openehr-technical_lists.openehr.org


Re: Rules in archetypes - what are the requirements?

2019-02-02 Thread Thomas Beale


On 01/02/2019 14:53, Pieter Bos wrote:


About the calculation:

Ah, I see, the assignment seems like a good solution. But why would I 
need a function to calculate a score that is just a sum of a number of 
values, instead of a few +-operators?


well you might want to re-use that function. More generally, some 
functions are more interesting, e.g. MAP calculation, and it is 
potentially better to a) name them, b) declare them in a more obvious 
place and c) make them re-usable.





Multiplicities/data binding:

The there exists case is clear. However, what if I have four events, 
all having four elements, each with dv_quantity as value. Say I want 
the magnitude of the last of these quantities to be larger than the 
sum of the first three. Before I could write something like:


for_all $event in /data/events[id3]
 $event/data/items/element[id6]/value/magnitude >
$event/data/items/element[id4]/value/magnitude +
$event/data/items/element[id5]/value/magnitude +
$event/data/items/element[id6]/value/magnitude

Assuming you meant to put 'id7' as the first one, I don't understand 
what this achieves beyond just:


/events[id2]/data/items/element[id7]/value/magnitude >
    /events[id2]/data/items/element[id4]/value/magnitude +
    /events[id2]/data/items/element[id5]/value/magnitude +
    /events[id2]/data/items/element[id6]/value/magnitude

which says the same thing, for all events in the runtime data that 
conform to the /events[id2] branch of the structure.


If we were to allow the expression for_all $event in /data/events[id3] 
then we need to be clear on what it means: it actually refers to an 
object of type List, but do the members consist of EVENT objects 
found in data at the moment the expression is evaluated? Or just the 
statically defined members in the archetype - which can also be 
multiple, e.g. see the Apgar archetype, it has 1 min, 2 min, 5 min events?


Normally we want the processing of 'rules' expressions in archetypes to 
apply to the data when the archetype is being used in its normal role of 
creation / semantic validation at data commit time. So it seems to me 
that if we want to support expressions like the above, we need to be 
able to do something like (don't worry about the concrete syntax too 
much, could easily be TS or java-flavoured):


*use_model*
    org.openehr.rm

*data_context*

    $xxx_events: List
    $item_aaa, $item_bbb, $item_ccc, $item_ddd: Real

*definition*

    check for_all event in $xxx_events:
    event/$item_aaa > event/$item_bbb + event/$item_ccc + 
event/$item_ddd


*data_bindings* -- pseudo-code for now

$xxx_events -> /events[id2]
$item_aaa -> /data/items/element[id7]/value/magnitude
$item_bbb -> /data/items/element[id4]/value/magnitude
$item_ccc -> /data/items/element[id5]/value/magnitude
$item_ddd -> /data/items/element[id6]/value/magnitude

I don't know what this archetype is, so assume that $xxx_events, 
$item_aaa etc are more meaningful names.


The next problem you mentioned is:

PB: Note that a path that points to a single typed dvquantity in an 
archetype can still point to many items in the RM if somewhere up the 
tree there is a list or a set, for example more than one observation


So I think this implies an incorrect interpretation of this kind of code 
within an archetype. It can't be understood as simultaneously applying 
to multiple Observations if it is within an Observation archetype, only 
to one OBSERVATION instance at a time - usually one about to be committed.


You can still have Lists of things internal to the archetype, as shown 
above with the Events list, but to process the multiplicity, you would 
need to do as we have done and use for_all, or some other 
container-aware operator or function.


Anyway, does this get closer to the sense of what you would like to do? 
It's more than I had conceived of, so this is a useful challenge...


- thomas


___
openEHR-technical mailing list
openEHR-technical@lists.openehr.org
http://lists.openehr.org/mailman/listinfo/openehr-technical_lists.openehr.org


Re: Rules in archetypes - what are the requirements?

2019-02-02 Thread Ian McNicoll
Hi Pieter,

"But why would I need a function to calculate a score that is just a sum of
a number of values, instead of a few +-operators?"

It is an open question but one advantage of using the function approach,
with simple values is that it can encapsulate the algorithm without too
much dependency on understanding openEHR paths or path -bindings. That
should allow broader engagement with non-openEHR specialists.

My preference is to support use of openEHR datatypes within the expression
(albeit perhaps in reduced format), as otherwise passing units etc as
scalars starts to get cumbersome.

e.g

$apgar_heartrate, $apgar_breathing, $apgar_reflex, $apgar_muscle, $
apgar_colour)

where each of these is actually an ordinal, rather than a scalar value.

Not such a good example but think of a BMI calc, where the units used for
height and weight are critical
We can learn a lot from GDL experience in this regard.

Ian

Dr Ian McNicoll
mobile +44 (0)775 209 7859
office +44 (0)1536 414994
skype: ianmcnicoll
email: i...@freshehr.com
twitter: @ianmcnicoll


Co-Chair, openEHR Foundation ian.mcnic...@openehr.org
Director, freshEHR Clinical Informatics Ltd.
Director, HANDIHealth CIC
Hon. Senior Research Associate, CHIME, UCL


On Fri, 1 Feb 2019 at 14:53, Pieter Bos  wrote:

> About the calculation:
>
>
>
> Ah, I see, the assignment seems like a good solution. But why would I need
> a function to calculate a score that is just a sum of a number of values,
> instead of a few +-operators?
>
>
> Multiplicities/data binding:
>
> The there exists case is clear. However, what if I have four events, all
> having four elements, each with dv_quantity as value. Say I want the
> magnitude of the last of these quantities to be larger than the sum of the
> first three. Before I could write something like:
>
> for_all $event in /data/events[id3]
>  $event/data/items/element[id6]/value/magnitude >
> $event/data/items/element[id4]/value/magnitude +
> $event/data/items/element[id5]/value/magnitude +
> $event/data/items/element[id6]/value/magnitude
>
>
>
> (I omitted a few node ids here that are not important for the example)
>
> Not the most readable -  but it does the job. With data binding, how do I
> express this? There no longer seems to be a path lookup outside of data
> binding, so I can’t write:
>
> for_all $event in $events
>  $event/data/items/element[id6]/value/magnitude >
> $event/data/items/element[id4]/value/magnitude +
> $event/data/items/element[id5]/value/magnitude +
> $event/data/items/element[id6]/value/magnitude
>
>
>
> And binding all the separate paths to variables doesn’t work either – they
> will be bound as lists, and there is no way to iterate over four lists of
> values at once.
>
>
>
> Note that a path that points to a single typed dvquantity in an archetype
> can still point to many items in the RM if somewhere up the tree there is a
> list or a set, for example more than one observation. So if you really want
> them to be typed on validation time, you need to check every attribute in
> the path to see if it can point to more than one value, then either make it
> a List> or define in which order to add it as a single list.
>
> I implemented it by determining type at runtime, but it’s possible
> otherwise. This means that very often you need a for all statement, in
> which case data binding doesn’t really help. I defined some tricks with the
> basic operators also working on equally sized lists to make things a bit
> easier to understand for modelers. That’s why I asked about the execution
> rules. The tricks I did can be easily rewritten into for_all statements if
> we need to have them removed.
>
>
>
> This leads to more interesting cases when you flatten rules to an OPT 2
> template, to obtain a single artifact that can be used for many things,
> including rule evaluation. That is very doable right now by prepending some
> paths and adding some for_all statements. I’m not sure how to do that with
> data binding.
>
>
>
> Regards,
>
>
> Pieter Bos
>
>
>
> *From: *openEHR-technical 
> on behalf of Thomas Beale 
> *Reply-To: *For openEHR technical discussions <
> openehr-technical@lists.openehr.org>
> *Date: *Friday, 1 February 2019 at 14:16
> *To: *"openehr-technical@lists.openehr.org" <
> openehr-technical@lists.openehr.org>
> *Subject: *Re: Rules in archetypes - what are the requirements?
>
>
>
> Thanks Pieter,
>
> this is very useful.
>
> On 01/02/2019 12:54, Pieter Bos wrote:
>
> For us the main requirement of the rules is to calculate the value of
> other fields based on other fields. Only the checking of assertions has
> 

Re: Rules in archetypes - what are the requirements?

2019-02-01 Thread Pieter Bos
About the calculation:

Ah, I see, the assignment seems like a good solution. But why would I need a 
function to calculate a score that is just a sum of a number of values, instead 
of a few +-operators?


Multiplicities/data binding:

The there exists case is clear. However, what if I have four events, all having 
four elements, each with dv_quantity as value. Say I want the magnitude of the 
last of these quantities to be larger than the sum of the first three. Before I 
could write something like:

for_all $event in /data/events[id3]
 $event/data/items/element[id6]/value/magnitude >
$event/data/items/element[id4]/value/magnitude +
$event/data/items/element[id5]/value/magnitude +
$event/data/items/element[id6]/value/magnitude

(I omitted a few node ids here that are not important for the example)
Not the most readable -  but it does the job. With data binding, how do I 
express this? There no longer seems to be a path lookup outside of data 
binding, so I can’t write:

for_all $event in $events
 $event/data/items/element[id6]/value/magnitude >
$event/data/items/element[id4]/value/magnitude +
$event/data/items/element[id5]/value/magnitude +
$event/data/items/element[id6]/value/magnitude

And binding all the separate paths to variables doesn’t work either – they will 
be bound as lists, and there is no way to iterate over four lists of values at 
once.

Note that a path that points to a single typed dvquantity in an archetype can 
still point to many items in the RM if somewhere up the tree there is a list or 
a set, for example more than one observation. So if you really want them to be 
typed on validation time, you need to check every attribute in the path to see 
if it can point to more than one value, then either make it a 
List> or define in which order to add it as a single list.
I implemented it by determining type at runtime, but it’s possible otherwise. 
This means that very often you need a for all statement, in which case data 
binding doesn’t really help. I defined some tricks with the basic operators 
also working on equally sized lists to make things a bit easier to understand 
for modelers. That’s why I asked about the execution rules. The tricks I did 
can be easily rewritten into for_all statements if we need to have them removed.

This leads to more interesting cases when you flatten rules to an OPT 2 
template, to obtain a single artifact that can be used for many things, 
including rule evaluation. That is very doable right now by prepending some 
paths and adding some for_all statements. I’m not sure how to do that with data 
binding.

Regards,


Pieter Bos

From: openEHR-technical  on behalf 
of Thomas Beale 
Reply-To: For openEHR technical discussions 

Date: Friday, 1 February 2019 at 14:16
To: "openehr-technical@lists.openehr.org" 
Subject: Re: Rules in archetypes - what are the requirements?


Thanks Pieter,

this is very useful.
On 01/02/2019 12:54, Pieter Bos wrote:
For us the main requirement of the rules is to calculate the value of other 
fields based on other fields. Only the checking of assertions has relatively 
little added value for the use cases our customers encounter. I would find it 
very hard to explain to any users or modelers that they can write checks that 
do the actual score calculation, but that they cannot actually use the 
calculated value anywhere. So we ignore this limitation altogether.

the obvious solution to that requirement seems to be to a) use functions and b) 
to allow assignment:

rules
-- assert that manually set total is correct
check $apgar_total_value == apgar_total ($apgar_heartrate_value, 
$apgar_breathing_value, $apgar_reflex_value, $apgar_muscle_value, 
$apgar_colour_value)



rules
-- assign total value
$apgar_total_value = apgar_total ($apgar_heartrate_value, 
$apgar_breathing_value, $apgar_reflex_value, $apgar_muscle_value, 
$apgar_colour_value)



Also the value binding seems to have an case that has not been covered:


it is possible that a single path lookup results in a list of values. This 
means a single path-bound variable will contain multiple values (so a list of 
values). In the old case, you could handle this with a for_all statement to 
express that the assertion should be valid within the scope of a single event, 
for all events. How could value binding solve this? The same question applies 
to output variable binding as well as input variable binding.

conceptually, rules statements are typed, so in this case, the type will be 
List or List or whatever. In that case, expressions need to 
treat it in the normal way, i.e. with List or Set operators that obtain single 
values. E.g.

$systolic_bp_samples: List

there_exists v in $systolic_bp_samples : v > Systolic_bp_threshold implies 

These kinds of things (and for_all) are documented in the Expression Language 
draft<https://specifications.openehr.org/releases/LANG/latest

Re: Rules in archetypes - what are the requirements?

2019-02-01 Thread Thomas Beale

Thanks Pieter,

this is very useful.

On 01/02/2019 12:54, Pieter Bos wrote:


For us the main requirement of the rules is to calculate the value of 
other fields based on other fields. Only the checking of assertions 
has relatively little added value for the use cases our customers 
encounter. I would find it very hard to explain to any users or 
modelers that they can write checks that do the actual score 
calculation, but that they cannot actually use the calculated value 
anywhere. So we ignore this limitation altogether.


the obvious solution to that requirement seems to be to a) use functions 
and b) to allow assignment:


*rules
*    -- assert that manually set total is correct
*check *$apgar_total_value == apgar_total ($apgar_heartrate_value, 
$apgar_breathing_value, $apgar_reflex_value, $apgar_muscle_value, 
$apgar_colour_value)



*rules
*    -- assign total value
    $apgar_total_value = apgar_total ($apgar_heartrate_value, 
$apgar_breathing_value, $apgar_reflex_value, $apgar_muscle_value, 
$apgar_colour_value)




Also the value binding seems to have an case that has not been covered:

it is possible that a single path lookup results in a list of values. 
This means a single path-bound variable will contain multiple values 
(so a list of values). In the old case, you could handle this with a 
for_all statement to express that the assertion should be valid within 
the scope of a single event, for all events. How could value binding 
solve this? The same question applies to output variable binding as 
well as input variable binding.


conceptually, rules statements are typed, so in this case, the type will 
be List or List or whatever. In that case, expressions 
need to treat it in the normal way, i.e. with List or Set operators that 
obtain single values. E.g.


$systolic_bp_samples: List

there_exists v in $systolic_bp_samples : v > Systolic_bp_threshold 
implies 


These kinds of things (and for_all) are documented in the Expression 
Language draft 
.


Related to this, both the current and proposed specification is 
missing execution rules, especially when paths lookup to a list of 
values instead of a single variable and how to handle that. For 
example what does the following mean when 
/data/events/data/items/element[id3]/value/magnitude resolves to more 
than one value?


I don't see how it can, since that path is defined to be of type Real 
(not List or Set etc) by the RM definition of DvQuantity. 
But I'm probably missing something in the sense of your question...


Anyway, the more I can find out about current requirements, working 
solutions, workaround etc, the better - the intention is to evolve the 
expression facility in archetypes to match those needs and to be as 
useful as possible.


- thomas


___
openEHR-technical mailing list
openEHR-technical@lists.openehr.org
http://lists.openehr.org/mailman/listinfo/openehr-technical_lists.openehr.org


Re: Rules in archetypes - what are the requirements?

2019-02-01 Thread Pieter Bos
For us the main requirement of the rules is to calculate the value of other 
fields based on other fields. Only the checking of assertions has relatively 
little added value for the use cases our customers encounter. I would find it 
very hard to explain to any users or modelers that they can write checks that 
do the actual score calculation, but that they cannot actually use the 
calculated value anywhere. So we ignore this limitation altogether.

Also the value binding seems to have an case that has not been covered:

it is possible that a single path lookup results in a list of values. This 
means a single path-bound variable will contain multiple values (so a list of 
values). In the old case, you could handle this with a for_all statement to 
express that the assertion should be valid within the scope of a single event, 
for all events. How could value binding solve this? The same question applies 
to output variable binding as well as input variable binding.

Related to this, both the current and proposed specification is missing 
execution rules, especially when paths lookup to a list of values instead of a 
single variable and how to handle that. For example what does the following 
mean when /data/events/data/items/element[id3]/value/magnitude resolves to more 
than one value?

/data/events/data/items/element[id15]/value/magnitude = 
/data/events/data/items/element[id3]/value/magnitude + 3

And what if 3 is replaced by another path instead? What if the left hand side 
matches one value? And what if it matches more than one? In Archie I 
implemented ways to handle these cases by defining the operations on single 
values, on equally sized lists and in cases where one value is a list and the 
other one is a single value. But unless this is specified, this will be 
different for different implementations.

Regards,

Pieter Bos

From: openEHR-technical  on behalf 
of Thomas Beale 
Reply-To: For openEHR technical discussions 

Date: Friday, 1 February 2019 at 13:01
To: Openehr-Technical 
Subject: Rules in archetypes - what are the requirements?


For many years, there has been a little-used capability in ADL which enables 
basic expressions to be stated such as the following in the Apgar Observation 
archetype:

rules

score_sum: 
/data[id3]/events[id4]/data[id2]/items[id26]/value[id44]/magnitude = 
/data[id3]/events[id4]/data[id2]/items[id6]/value[id40]/value + 
/data[id3]/events[id4]/data[id2]/items[id10]/value[id39]/value + 
/data[id3]/events[id4]/data[id2]/items[id14]/value[id41]/value + 
/data[id3]/events[id4]/data[id2]/items[id18]/value[id42]/value + 
/data[id3]/events[id4]/data[id2]/items[id22]/value[id43]/value

where all those paths point to the various Apgar leaf data values, i.e. total, 
heart rate etc.

This kind of statement is intended to assert that the total value = the sum of 
the 5 elements, as per the Apgar formula. However, it was never that clear that 
it is an assertion, not a value-setting formula, which might also be something 
we want.

It's also not very readable, even if the paths were rendered with a tool, they 
are long and painful to read.

Another kind of assertion was to for conditional mandation of some part of the 
data depending on some other data element (or more generally, an expression), 
e.g.

rules

/data[id2]/items[id21]/items[id15]/value[id50]/defining_code matches 
{[at19]} implies exists /data[id2]/items[id21]/items[id20]

Here the logical intention is to mandate that the data at the second path, 
which is about details of transfer (i.e. discharge to other care) if the value 
of the datum at the first path, which is 'type of separation' = at19|transfer|. 
Other examples are mandating data containing details of tobacco use if the 
value of the data item 'tobacco use' /= at44|non-user|.

This also is not that easy to read, or clear in its intentions.

More recently, as part of the development of a simple expression language that 
can be used across openEHR (archetypes, Task Planning, GDL etc), I proposed 
some key improvements to expressions in archetypes, namely:

  *   symbolic names for paths, done by bindings
  *   an explicit 'check' instruction to make the intention of assertion clearer
  *   a defined() predicate to replace the use of 'exists'

Examples of how these changes look are shown here in the working copy of the 
ADL2 
spec<https://specifications.openehr.org/releases/AM/latest/ADL2.html#_rules_section>.
 In this form, the above Apgar example becomes:

rules
check $apgar_total_value = $apgar_heartrate_value + $apgar_breathing_value 
+ $apgar_reflex_value + $apgar_muscle_value + $apgar_colour_value

data_bindings

content_bindings = <
["apgar_breathing_value"] = 
<"/data[id3]/events[id4]/data[id2]/items[id10]/value[id39]/value">
["apgar_heartrate_value"] = 
<"/data[id3]/events[id4]/data[id2]/items[id6]/value[id40]/value">
["apgar_muscle_va

Re: Rules in archetypes - what are the requirements?

2019-02-01 Thread Diego Boscá
I'm fine with this improvements, the only thing I feel that can be
troublesome for users is having data_bindings and computed values in a
completely different format/style


El vie., 1 feb. 2019 a las 13:01, Thomas Beale ()
escribió:

> For many years, there has been a little-used capability in ADL which
> enables basic expressions to be stated such as the following in the Apgar
> Observation archetype:
>
> *rules*
>
> *score_sum*:
> /data[id3]/events[id4]/data[id2]/items[id26]/value[id44]/magnitude =
> /data[id3]/events[id4]/data[id2]/items[id6]/value[id40]/value +
> /data[id3]/events[id4]/data[id2]/items[id10]/value[id39]/value +
> /data[id3]/events[id4]/data[id2]/items[id14]/value[id41]/value +
> /data[id3]/events[id4]/data[id2]/items[id18]/value[id42]/value +
> /data[id3]/events[id4]/data[id2]/items[id22]/value[id43]/value
>
> where all those paths point to the various Apgar leaf data values, i.e.
> total, heart rate etc.
>
> This kind of statement is intended to assert that the total value = the
> sum of the 5 elements, as per the Apgar formula. However, it was never that
> clear that it is an assertion, not a value-setting formula, which might
> also be something we want.
>
> It's also not very readable, even if the paths were rendered with a tool,
> they are long and painful to read.
>
> Another kind of assertion was to for conditional mandation of some part of
> the data depending on some other data element (or more generally, an
> expression), e.g.
>
> *rules*
>
> /data[id2]/items[id21]/items[id15]/value[id50]/defining_code *matches
> *{[at19]} *implies exists */data[id2]/items[id21]/items[id20]
>
> Here the logical intention is to mandate that the data at the second path,
> which is about details of transfer (i.e. discharge to other care) if the
> value of the datum at the first path, which is 'type of separation' =
> at19|transfer|. Other examples are mandating data containing details of
> tobacco use if the value of the data item 'tobacco use' /= at44|non-user|.
>
> This also is not that easy to read, or clear in its intentions.
>
> More recently, as part of the development of a simple expression language
> that can be used across openEHR (archetypes, Task Planning, GDL etc), I
> proposed some key improvements to expressions in archetypes, namely:
>
>- symbolic names for paths, done by bindings
>- an explicit 'check' instruction to make the intention of assertion
>clearer
>- a defined() predicate to replace the use of 'exists'
>
> Examples of how these changes look are shown here in the working copy of
> the ADL2 spec
> .
> In this form, the above Apgar example becomes:
>
> *rules*
> *check *$apgar_total_value = $apgar_heartrate_value + $
> apgar_breathing_value + $apgar_reflex_value + $apgar_muscle_value + $
> apgar_colour_value
>
> *data_bindings*
>
> content_bindings = <
> ["apgar_breathing_value"] =
> <"/data[id3]/events[id4]/data[id2]/items[id10]/value[id39]/value">
> ["apgar_heartrate_value"] =
> <"/data[id3]/events[id4]/data[id2]/items[id6]/value[id40]/value">
> ["apgar_muscle_value"] =
> <"/data[id3]/events[id4]/data[id2]/items[id14]/value[id41]/value">
> ["apgar_reflex_value"] =
> <"/data[id3]/events[id4]/data[id2]/items[id18]/value[id42]/value">
> ["apgar_colour_value"] =
> <"/data[id3]/events[id4]/data[id2]/items[id22]/value[id43]/value">
> ["apgar_total_value"] =
> <"/data[id3]/events[id4]/data[id2]/items[id26]/value[id44]/magnitude">
> >
>
> And the smoking example is:
>
> *check *$is_smoker = *True **implies **defined *($smoking_details)
>
> Note that this does not address the possible requirement of being able to
> state a formula that *sets *a field, or defines a purely computed value
> at a path.
>
> We are still working on details of the expression language, variable
> binding idea and so on. I am interested in feedback on the approach shown
> in the spec, preferably provided here in the first instance.
>
> - thomas
> ___
> openEHR-technical mailing list
> openEHR-technical@lists.openehr.org
>
> http://lists.openehr.org/mailman/listinfo/openehr-technical_lists.openehr.org
>


-- 

[image: VeraTech for Health SL] 

[image: Twitter]   [image: LinkedIn]
 [image: Maps]


Diego Boscá Tomás / Senior developer
diebo...@veratech.es
yamp...@gmail.com

VeraTech for Health SL
+34 654604676 <+34%20654604676>
www.veratech.es

La información contenida en este mensaje y/o archivo(s) adjunto(s), enviada
desde VERATECH FOR HEALTH, SL, es confidencial/privilegiada y está
destinada a ser leída sólo por la(s) persona(s) a la(s) que va dirigida. Le
recordamos que sus datos han sido incorporados en el sistema de tratamiento
de VERATECH FOR HEALTH, 

Rules in archetypes - what are the requirements?

2019-02-01 Thread Thomas Beale
For many years, there has been a little-used capability in ADL which 
enables basic expressions to be stated such as the following in the 
Apgar Observation archetype:


*rules*

/score_sum/: 
/data[id3]/events[id4]/data[id2]/items[id26]/value[id44]/magnitude = 
/data[id3]/events[id4]/data[id2]/items[id6]/value[id40]/value + 
/data[id3]/events[id4]/data[id2]/items[id10]/value[id39]/value + 
/data[id3]/events[id4]/data[id2]/items[id14]/value[id41]/value + 
/data[id3]/events[id4]/data[id2]/items[id18]/value[id42]/value + 
/data[id3]/events[id4]/data[id2]/items[id22]/value[id43]/value


where all those paths point to the various Apgar leaf data values, i.e. 
total, heart rate etc.


This kind of statement is intended to assert that the total value = the 
sum of the 5 elements, as per the Apgar formula. However, it was never 
that clear that it is an assertion, not a value-setting formula, which 
might also be something we want.


It's also not very readable, even if the paths were rendered with a 
tool, they are long and painful to read.


Another kind of assertion was to for conditional mandation of some part 
of the data depending on some other data element (or more generally, an 
expression), e.g.


*rules*

/data[id2]/items[id21]/items[id15]/value[id50]/defining_code *matches 
*{[at19]} *implies exists */data[id2]/items[id21]/items[id20]


Here the logical intention is to mandate that the data at the second 
path, which is about details of transfer (i.e. discharge to other care) 
if the value of the datum at the first path, which is 'type of 
separation' = at19|transfer|. Other examples are mandating data 
containing details of tobacco use if the value of the data item 'tobacco 
use' /= at44|non-user|.


This also is not that easy to read, or clear in its intentions.

More recently, as part of the development of a simple expression 
language that can be used across openEHR (archetypes, Task Planning, GDL 
etc), I proposed some key improvements to expressions in archetypes, namely:


 * symbolic names for paths, done by bindings
 * an explicit 'check' instruction to make the intention of assertion
   clearer
 * a defined() predicate to replace the use of 'exists'

Examples of how these changes look are shown here in the working copy of 
the ADL2 spec 
. 
In this form, the above Apgar example becomes:


*rules*
*check *$apgar_total_value = $apgar_heartrate_value + 
$apgar_breathing_value + $apgar_reflex_value + $apgar_muscle_value + 
$apgar_colour_value


*data_bindings*

    content_bindings = <
    ["apgar_breathing_value"] = 
<"/data[id3]/events[id4]/data[id2]/items[id10]/value[id39]/value">
    ["apgar_heartrate_value"] = 
<"/data[id3]/events[id4]/data[id2]/items[id6]/value[id40]/value">
    ["apgar_muscle_value"] = 
<"/data[id3]/events[id4]/data[id2]/items[id14]/value[id41]/value">
    ["apgar_reflex_value"] = 
<"/data[id3]/events[id4]/data[id2]/items[id18]/value[id42]/value">
    ["apgar_colour_value"] = 
<"/data[id3]/events[id4]/data[id2]/items[id22]/value[id43]/value">
    ["apgar_total_value"] = 
<"/data[id3]/events[id4]/data[id2]/items[id26]/value[id44]/magnitude">

    >

And the smoking example is:

*check *$is_smoker = *True **implies **defined *($smoking_details)

Note that this does not address the possible requirement of being able 
to state a formula that /sets /a field, or defines a purely computed 
value at a path.


We are still working on details of the expression language, variable 
binding idea and so on. I am interested in feedback on the approach 
shown in the spec, preferably provided here in the first instance.


- thomas

___
openEHR-technical mailing list
openEHR-technical@lists.openehr.org
http://lists.openehr.org/mailman/listinfo/openehr-technical_lists.openehr.org