uima ruta create two annotations in one ruta rule - uima

I'm writing ruta scirpts to capture sbp&dbp annotations from the text like "bp: 120/80mmHg". What I want to obtain are :
Sign: name="sbp", value=120, unit=mmHg
Sign: name="dbp", value=80, unit=mmHg
Anyone can indicate me how to do that? thanks

Doing this correctly and in the right way requires a lot of additional resources and analysis engines, e.g., concept mapping mabye against loinc, detecting arbitrary complex numeric values, detecting units and measurements, also in slash enums, normalization against si base units and so on.
Here's a simple Ruta script as a initial prototype (tested with 2.6.1):
DECLARE BloodPressure (DOUBLE systolic, DOUBLE diastolic, STRING unit);
DECLARE Unit, BloodPressureIndicator;
// mock annotations, replace with dictionary or unit parser
"mmHg" -> Unit;
"bp" -> BloodPressureIndicator;
DOUBLE d1, d2;
(BloodPressureIndicator COLON? NUM{PARSE(d1)} SPECIAL.ct=="/" NUM{PARSE(d2)} u:Unit)
{-> CREATE(BloodPressure, "systolic" = d1, "diastolic" = d2, "unit" = u.ct)};
and here an example creating two annotations of different types:
DECLARE BloodPressure (DOUBLE value, STRING unit);
DECLARE BloodPressure SBP, DBP;
DECLARE Unit, BloodPressureIndicator;
// mock annotations, replace with dictionary or unit parser
"mmHg" -> Unit;
"bp" -> BloodPressureIndicator;
DOUBLE d1, d2;
(BloodPressureIndicator COLON?
NUM{PARSE(d1) -> CREATE(SBP, "value" = d1, "unit" = u.ct)}
SPECIAL.ct=="/"
NUM{PARSE(d2) -> CREATE(DBP, "value" = d2, "unit" = u.ct)}
u:Unit);
DISCLAIMER: I am a developer of UIMA Ruta

Related

Function generation with arbitrary signature - revisited

I am resubmitting a question asked almost a decade ago on this site link - but which is not as generic as I would like.
What I am hoping for is a way to construct a function from a list of types, where the final output type can have an arbitrary/default value (such as 0.0 for a float, or "" for a string). So, from
[float; int; float;]
I would get something that amounts to
fun(f: float) ->
fun(i: int) ->
0.0
I am hopeful of achieving this, but am so far unable to. It would be helping me out a lot if I could see a sample that does the above.
The answer in the above link goes some of the way, but the example seems to know its function signature at compile time, which I won't, and also generates a compiler warning.
The scenario I have, for those that find context helpful, is that I want to be able to open a dll and one way or another identify a method which will have a given signature with argument-types limited to a known set of types (i.e. float, int). For each input parameter in this function signature I will run code to generate a 'buffer' object, which will have
a buffer of data items of the given type, i.e. [1.2; 3.2; 4.5]
a supplier of that data type (supplies may be intermittent so the receiving buffer may be empty at any one time)
a generator function that transforms data items before being dispatched. This function can be updated at any time.
a dispatch function. The dispatch target of bufferA will be bufferB, and for bufferB it will be a pub-sub thing where subscribers can subscribe to the end result of the calculation, in this case a stream of floats. Data accumulates in applicative style down the chain of buffers, until the final result is published as a new stream.
a regulator that turns the stream of data heading out to the consumer on or off. This ensures orderly function application.
The function from the dll will eventually be given to BufferA to apply to a float and pass the result on to buffer B (to pick up an int). However, while setting up the buffer infrastructure I only need a function with the correct signature, so a dummy value, such as 0.0, is fine.
For a function of a known signature I can handcraft the code that creates the necessary infrastructure, but I would like to be able to automate this, and ideally register dlls and have new calculated streams available plugin-style without rebuilding the application.
If you're willing to throw type safety out the window, you could do this:
let rec makeFunction = function
| ["int"] -> box 0
| ["float"] -> box 0.0
| ["string"] -> box ""
| "int" :: types ->
box (fun (_ : int) -> makeFunction types)
| "float" :: types ->
box (fun (_ : float) -> makeFunction types)
| "string" :: types ->
box (fun (_ : string) -> makeFunction types)
| _ -> failwith "Unexpected"
Here's a helper function for invoking one of these monstrosities:
let rec invokeFunction types (values : List<obj>) (f : obj) =
match types, values with
| [_], [] -> f
| ("int" :: types'), (value :: values') ->
let f' = f :?> (int -> obj)
let value' = value :?> int
invokeFunction types' values' (f' value')
| ("float" :: types'), (value :: values') ->
let f' = f :?> (float -> obj)
let value' = value :?> float
invokeFunction types' values' (f' value')
| ("string" :: types'), (value :: values') ->
let f' = f :?> (string -> obj)
let value' = value :?> string
invokeFunction types' values' (f' value')
| _ -> failwith "Unexpected"
And here it is in action:
let types = ["int"; "float"; "string"] // int -> float -> string
let f = makeFunction types
let values = [box 1; box 2.0]
let result = invokeFunction types values f
printfn "%A" result // output: ""
Caveat: This is not something I would ever recommend in a million years, but it works.
I got 90% of what I needed from this blog by James Randall, entitled compiling and executing fsharp dynamically at runtime. I was unable to avoid concretely specifying the top level function signature, but a work-around was to generate an fsx script file containing that signature (determined from the relevant MethodInfo contained in the inspected dll), then load and run that script. James' blog/ github repository also describes loading and running functions contained in script files. Having obtained the curried function from the dll, I then apply it to default arguments to get representative functions of n-1 arity using
let p1: 'p1 = Activator.CreateInstance(typeof<'p1>) :?> 'p1
let fArity2 = fArity3 p1
Creating and running a script file is slow, of course, but I only need to perform this once when setting up the calculation stream

How to make use of the unit attribute within a model in Modelica?

Motivation
Modelica does store units of measurement (e.g. SI units and Non-SI units) as an attribute with regard to a variable. Here is an example for a Non-SI-unit:
type Time_months = Real( quantity = "Time", unit = "mo", displayUnit = "months" )
Since for models in economics it will be rather akward to give rates in seconds, I would like to write a rather general unit conversion function that will allow to convert units of time. So ideally a function to convert to another time base should work with three inputs and one output:
input Real timeValue "the value of time to be converted";
input String timeBaseA "the time base for timeValue, e.g. \"mo\" ";
input String timeBaseB "the time base to convert to, e.g. \"yr\" ";
output Real convertedTimeValue "the result of the conversion";
Questions
If we assume that a variable for some time value already has a specific unit attribute (e.g. "mo") it would make sense to use that meta information within a model.
Question 1: How can meta information like unit be accessed within a model?
Ideally something like the following would be great:
String timeBaseA := timeValue.unit;
or
String timeBaseA := getUnit( timeValue ) "some function to read unit information";
Question 2: How can meta information like unit be assigned within a function?
In the example we would of course like to return the output value with the correct unit of time. So ideally we would like to have:
output Real convertedTime( quantity = "Time", unit = strTimeBaseB )
Unfortunately, using an input will give rise to an error as the variability is different: The unit attribute should have constant variability but the input variable has parameter variability. (Using a function - which would be nice - also fails for the same reason.)
Regarding Question 1:
I have never used Wolfram SystemModeler, but the Modelica Language Specification 3.4 says in chapter 4.8 (Predefined Types and Classes):
The attributes of the predefined variable types (Real, Integer, Boolean, String) ... cannot be accessed using dot notation, and are not constrained by equations and algorithm sections.
Regarding Question 2:
I think it is only possible to define the unit of a variable on declaration from a literal or from a final parameter - at least this is what I observed in Dymola.
Alternative - use operator records
You could use operator records for your task. This will allow you to store the time in seconds and convert it to what ever needed when the value comes to use.
Operator records allow you to define several function to create them, compare or add them, convert to String, etc.
See the brief example below, where a operator record Time is defined, which can be created with two different constructor functions from seconds or days and can be converted to Strings with day or seconds
operator record Time
Integer s "Second";
encapsulated operator 'constructor'
import Time;
function from_s
input Integer s "Seconds";
output Time t(s=s);
algorithm
end from_s;
function from_d
input Integer d "Days";
output Time t(s=d*24*3600);
algorithm
end from_d;
end 'constructor';
encapsulated operator 'String' "Convert Time to string"
import Time;
function formated
input Time t;
input String format = "s" annotation(choices(choice="s" "seconds", choice="d" "days"));
output String str;
algorithm
if format == "d" then
str :=String(t.s/24/3600);
else
str :=String(t.s);
end if;
end formated;
end 'String';
encapsulated operator function '==' "Compare time records"
import Time;
input Time t1;
input Time t2;
output Boolean result "= t1 == t2";
algorithm
result := t1.s == t2.s;
end '==';
end Time;
Usage:
import Modelica.Utilities.Streams.print
t1 = Time(d=12) // create record using day constructor
t2 = Time(s=3600*24*2) // create record using second constructor
print(String(t1, format="s")) // prints 1036800
print(String(t1, format="d")) // prints 12
print(String(t2, format="s")) // prints 172800
print(String(t2, format="d")) // prints 2
See Modelica Spec 3.4 Chapter 14 "Overloaded Operators" for details.
Note: This was tested with Dymola 2019, not with Wolfram SystemModeler
In Modelica usually every variable is computed based on SI units. Then you have displayUnits to plot them in a different unit (not affecting the actual computation).
I don't know about SystemModeler, but in Dymola the conversion between the unit (of computation) and the displayUnit (only for plotting) is handled by a pre-defined script (displayUnit.mos). It can be extended by the user to contain custom displayUnits. The code for the display units related to time is shown below. I extended it to have week (w) additionally to the predefined ones.
// Syntax:
// defineUnitConversion(<unit>, <derived unit>, <scale>, <opt. offset>);
// Time
defineUnitConversion("s", "ms", 1000);
defineUnitConversion("s", "min", 1/60);
defineUnitConversion("s", "h", 1/3600);
defineUnitConversion("s", "d", 1/86400);
defineUnitConversion("s", "w", 1/604800);
This can then be selected in plots manually or as the default ´displayUnit´ via Modelica.SIunits.Time t(displayUnit = "w") = ...;
The disadvantage is, that this extension has to be done in a file in the install directory. So it has to be changed again after re-installing the tool or when using a different computer.
If there are numerical reasons to not compute solutions in seconds (e.g. because values would get to big), the solution would be the nominal attribute, which enables a scaling of the variables.
BTW: I think months are not a very good unit of time as they can have 28 to 31 days. That's why I chose weeks in my example.
You could use conversion like is done in the MSL, for example the function Modelica.SIunits.Conversions.to_degC which has the signature:
function to_degC
input Temperature Kelvin "Kelvin value";
output NonSIunits.Temperature_degC Celsius "Celsius value";
end to_degC;
This works, but you need one such function for each unit you want to convert between (which is why most calculations are done using SI-units).

Need to compare the feature of two annotations which having same index position-UIMA RUTA

I have two annotations named First and Second.In this I need to compare the feature of two annotations which having same index position.
First.csv:
Position1;0
Position2;1
Script:
DECLARE Second(INT secondpass);
"Position1"->Second;
WORDTABLE FirstList = 'First.csv';
DECLARE Annotation First(INT firstpass);
Document{->MARKTABLE(First, 2, FirstList,true,0,"",0, "firstpass" = 1 )};
DECLARE Text;
p1:First ANY*? p2:Second{p1.secondpass == p2.firstpass -> MARK(Text)};
p1:First # p2:Second{p1.secondpass == p2.firstpass -> MARK(Text)}; wont work because both annotations are in same positions.
Depending on how exactly the offsets need to be checked, something like the following would probably do:
p1:First{-> MARK(Text)}<-{p2:Second{p1.begin==p2.begin,p1.end==p2.end,p1.firstpass==p2.secondpass};};
or
p1:First{p1.firstpass == Second.secondpass -> MARK(Text)};
You can specify this also with a conjunct rule element (&), but I would recommend to avoid these if not really necessary.
DISCLAIMER: I am a developer of UIMA Ruta

F#: No abstract property was found that corresponds to this override

Hello fellow Overflowers. I am working on a group project to create a ray tracer that draws a 2D rendering of a 3D scene. The task I am currently on involves matrix transformation of objects (shapes), that need to be moved around, mirrored, sheared etc.
In working with shapes we have chosen to implement an interface that defines the type for a hit function. This hit function is defined in each shape, such as sphere, box, plane etc. When transforming a shape I need to transform the rays that hit the shape and the way to do that seems to be with a higher order function that alters the original hit function.
In order to do this I have implemented the function transformHitFunction, which seems to work, but the new type transformedShape, that implements the Shape interface, is giving me the error
No abstract property was found that corresponds to this override
which doesn't make any sense to me, as it works with other hit functions of the same type. Can anyone spot what's wrong?
I have tried to strip away all modules, namespaces and code that is not relevant to this issue.
type Transformation = Matrix of float [,]
type Vector =
| V of float * float * float
let mkVector x y z = V(x, y, z)
let vgetX (V(x,_,_)) = x
let vgetY (V(_,y,_)) = y
let vgetZ (V(_,_,z)) = z
type Point =
| P of float * float * float
let mkPoint x y z = P(x, y, z)
let pgetX (P(x,_,_)) = x
let pgetY (P(_,y,_)) = y
let pgetZ (P(_,_,z)) = z
type Material = Material
type Texture =
| T of (float -> float -> Material)
type Shape =
abstract member hit: Point * Vector -> (Texture*float*Vector) option
let transformPoint (p:Point) t =
match t with
| Matrix m -> mkPoint ((pgetX(p))*m.[0,0] + (pgetY(p))*m.[0,1] + (pgetZ(p))*m.[0,2] + m.[0,3])
((pgetX(p))*m.[1,0] + (pgetY(p))*m.[1,1] + (pgetZ(p))*m.[1,2] + m.[1,3])
((pgetX(p))*m.[2,0] + (pgetY(p))*m.[2,1] + (pgetZ(p))*m.[2,2] + m.[2,3])
let transformVector (v:Vector) t =
match t with
| Matrix m -> mkVector ((vgetX(v))*m.[0,0] + (vgetY(v))*m.[0,1] + (vgetZ(v))*m.[0,2] + m.[0,3])
((vgetX(v))*m.[1,0] + (vgetY(v))*m.[1,1] + (vgetZ(v))*m.[1,2] + m.[1,3])
((vgetX(v))*m.[2,0] + (vgetY(v))*m.[2,1] + (vgetZ(v))*m.[2,2] + m.[2,3])
let transformHitFunction fn (t:Transformation) =
fun (p:Point,v:Vector) ->
let tp = transformPoint p t
let tv = transformVector v t
match fn(tp,tv) with
| None -> None
| Some (tex:Texture, d:float, n) -> let tn = transformVector n t
Some (tex, d, tn)
type transformedShape (sh:Shape, t:Transformation) =
interface Shape with
member this.hit = transformHitFunction sh.hit t
Short answer
When having problems with implementing or overriding members, provide the argument list exactly as in the abstract or virtual member's definition. (Also, mind your parentheses, because additional parentheses can change the type of a member in subtle ways.)
E.g. in this case: member this.hit (arg1, arg2) = ...
Slightly longer answer
You're encountering a situation in which the difference between F#'s first-class functions and its support of object-oriented style methods is relevant.
For compatibility with the Common Language Infrastructure's (CLI's) object-oriented languages (and object-oriented programming style in F# programs), F# sometimes discriminates between not only functions and values, but even functions in the object-oriented and functional style.
F# uses very similar syntax for two things: the "classical" CLI methods that take an argument list (and also support overloading and optional parameters) versus F#'s own favorite function type FSharpFunc, which always takes one parameter but supports currying and may take multiple parameters via tuples. But the semantics of these two can be different.
The last line of the question tries to pass a function with tupled input to implement a method that takes two arguments the way a method in C# or VB.NET takes them: a CLI method's argument list. Directly assigning an F#-style first-class function won't work here, and nether would a single tuple argument; the compiler insists to get every argument explicitly. If you write the implementation with its complete method argument list, it will work. For example:
member this.hit (arg1, arg2) = transformHitFunction sh.hit t (arg1, arg2)
Another solution would be to declare hit as:
abstract member hit: (Point * Vector -> (Texture*float*Vector) option)
(Note the parentheses!) Now it's a property that contains a first-class function; you can implement it by returning such a function, but the type of the member subtly changed.
The latter is why even implementing the original interface as a single-argument function, e.g. like this:
member this.hit a = transformHitFunction sh.hit t a // error
will not work. More precisely, The compiler will refuse to see a as a tuple. The same issue applies to
member this.hit ((arg1, arg2)) = transformHitFunction sh.hit t (arg1, arg2) // error
What's wrong now? The outer parentheses define the argument list, but the inner parentheses use a tuple pattern to decompose a single argument! So the argument list still has only one argument, and compilation fails. The outermost parentheses and commas when writing methods are a different feature than the tuples used elsewhere, even though the compiler translates between the two in some cases.
At the moment, your transformedShape.hit is a non-indexed property. When invoked, it returns a function that you need to provide with a Point*Vector tuple, and you'll get the result you want. You'll be able to see that better if you add a helper binding: Hover over f here:
type transformedShape (sh:Shape, t:Transformation) =
interface Shape with
member this.hit =
let f = transformHitFunction sh.hit t
f
As others have remarked already, all you need to do is spell out the arguments explicitly, and you're good:
type transformedShape2 (sh:Shape, t:Transformation) =
interface Shape with
member this.hit(p, v) = transformHitFunction sh.hit t (p, v)

How to match specific tokens in UIMA Ruta?

DECLARE A,B;
DECLARE Annotation C(Annotation firstA, Annotation secondA,...);
"token1|token2|...|tokenn" -> A;
"token3|token4" -> B;
A A B {->MARK(C,1,3)};
I did with GATHER
(A COMMA A B) {-> GATHER(C,1,4,"firstA"=1,"secondA" = 3,"B"=4)};
But how about in case of unknown sequence of A type? as below, how can it be possible to store all A in features? The number of features are also unknown. In plan java, we declare String array and can add element, but in Ruta seems to be no as such process.
(A (COMMA A)+ B) {-PARTOF(C) -> GATHER(C,beginPosition,endPosition,"firstA"=1,"secondA" = 3,"thirdA"=?,so on)};
Annotations in UIMA refer to the complete span, from the begin offset to the end offset. So, if you want to specify something with two elements, then a simple annotation is not sufficient. You cannot create an annotation of the type C that covers the first A and the B but not the second A.
However, you can store the important information in feature values. How to implement it depends on various things.
If there are always exactly two annotation you want to remember, then add two features to type C and assign the feature values in the given rule, e.g., by CREATE(C,1,3,"first" = A, "second" = B ).
You can also use different actions like GATHER, or use one FSArray feature in order to store the annotations.
A complete example with a FSArray:
DECLARE A, B;
DECLARE Annotation C (FSArray as, B b);
"A" -> A;
"B" -> B;
(A (COMMA A)+ B){-PARTOF(C) -> CREATE(C, "as" = A, "b" = B)};
If applied on a text like "A, A, A B", the last rule creates one annotation of type C that stores three A annotations in the feature "as" and one B annotation in the feature "b"