Matching a list (of tags) with another and detecting presence of common elements - drools

My requirement is to match tags. In the example, this particular HourConstraint checks the TeacherHour assigned to Hour(23).
Specifically, it checks TeacherHour.attributes["tags"] for the values ["asst_ct","teacher_john_smith"] and detects atleast one match, two in this case (both "asst_ct" and "teacher_john_smith") .
TeacherHour:
id: 47
assigned_hour: Null
attributes:Map<List<String>>
"tags":["asst_ct","no_strenuous_duties","kinda_boring","teacher_john_smith"]
"another_attribute":[...]
HourConstraint:
hour: Hour(23)
attribute: "tags"
values_list: ["asst_ct","teacher_john_smith"]
Question: How do I detect the presence (true or false) of common elements between two lists?
Drools Expert has memberOf and contains, but they check a scalar vs a collection, never a collection vs a collection.
I see two potential ways:
introduce a function boolean isIntersecting(list,list) and tell Drools to use that for truth checking
Implement TeacherHour.attributes[] as a string instead of a list and HourConstraint.valueslist as a regular expression that can match that list

There are a few options. Most straight forward is to use the Collections class to do that for you:
rule X
when
$t: TeacherHour( )
HourConstraint( Collections.disjoint( $t.attributes["tags"], values_list ) == false )
...
If this is something you would use often in your rules, then I recommend wrapping that function in a pluggable operator, supported by Drools. Lets say you name the operator "intersect", you can then write your rules like this:
rule X
when
$t: TeacherHour( )
HourConstraint( values_list intersect $t.attributes["tags"] )
...
A third option, is to use "from", but that is less efficient in runtime as it causes iterations on the first list:
rule X
when
$t: TeacherHour( )
$tag : String() from $t.attributes["tags"]
exists( HourConstraint( values_list contains $tag ) )
...

Related

Does pattern match in Raku have guard clause?

In scala, pattern match has guard pattern:
val ch = 23
val sign = ch match {
case _: Int if 10 < ch => 65
case '+' => 1
case '-' => -1
case _ => 0
}
Is the Raku version like this?
my $ch = 23;
given $ch {
when Int and * > 10 { say 65}
when '+' { say 1 }
when '-' { say -1 }
default { say 0 }
}
Is this right?
Update: as jjmerelo suggested, i post my result as follows, the signature version is also interesting.
multi washing_machine(Int \x where * > 10 ) { 65 }
multi washing_machine(Str \x where '+' ) { 1 }
multi washing_machine(Str \x where '-' ) { -1 }
multi washing_machine(\x) { 0 }
say washing_machine(12); # 65
say washing_machine(-12); # 0
say washing_machine('+'); # 1
say washing_machine('-'); # -1
say washing_machine('12'); # 0
say washing_machine('洗衣机'); # 0
TL;DR I've written another answer that focuses on using when. This answer focuses on using an alternative to that which combines Signatures, Raku's powerful pattern matching construct, with a where clause.
"Does pattern match in Raku have guard clause?"
Based on what little I know about Scala, some/most Scala pattern matching actually corresponds to using Raku signatures. (And guard clauses in that context are typically where clauses.)
Quoting Martin Odersky, Scala's creator, from The Point of Pattern Matching in Scala:
instead of just matching numbers, which is what switch statements do, you match what are essentially the creation forms of objects
Raku signatures cover several use cases (yay, puns). These include the Raku equivalent of the functional programming paradigmatic use in which one matches values' or functions' type signatures (cf Haskell) and the object oriented programming paradigmatic use in which one matches against nested data/objects and pulls out desired bits (cf Scala).
Consider this Raku code:
class body { has ( $.head, #.arms, #.legs ) } # Declare a class (object structure).
class person { has ( $.mom, $.body, $.age ) } # And another that includes first.
multi person's-age-and-legs # Declare a function that matches ...
( person # ... a person ...
( :$age where * > 40, # ... whose age is over 40 ...
:$body ( :#legs, *% ), # ... noting their body's legs ...
*% ) ) # ... and ignoring other attributes.
{ say "$age {+#legs}" } # Display age and number of legs.
my $age = 42; # Let's demo handy :$var syntax below.
person's-age-and-legs # Call function declared above ...
person # ... passing a person.
.new: # Explicitly construct ...
:$age, # ... a middle aged ...
body => body.new:
:head,
:2arms,
legs => <left middle right> # ... three legged person.
# Displays "42 3"
Notice where there's a close equivalent to a Scala pattern matching guard clause in the above -- where * > 40. (This can be nicely bundled up into a subset type.)
We could define other multis that correspond to different cases, perhaps pulling out the "names" of the person's legs ('left', 'middle', etc.) if their mom's name matches a particular regex or whatever -- you hopefully get the picture.
A default case (multi) that doesn't bother to deconstruct the person could be:
multi person's-age-and-legs (|otherwise)
{ say "let's not deconstruct this person" }
(In the above we've prefixed a parameter in a signature with | to slurp up all remaining structure/arguments passed to a multi. Given that we do nothing with that slurped structure/data, we could have written just (|).)
Unfortunately, I don't think signature deconstruction is mentioned in the official docs. Someone could write a book about Raku signatures. (Literally. Which of course is a great way -- the only way, even -- to write stuff. My favorite article that unpacks a bit of the power of Raku signatures is Pattern Matching and Unpacking from 2013 by Moritz. Who has authored Raku books. Here's hoping.)
Scala's match/case and Raku's given/when seem simpler
Indeed.
As #jjmerelo points out in the comments, using signatures means there's a multi foo (...) { ...} for each and every case, which is much heavier syntactically than case ... => ....
In mitigation:
Simpler cases can just use given/when, just like you wrote in the body of your question;
Raku will presumably one day get non-experimental macros that can be used to implement a construct that looks much closer to Scala's match/case construct, eliding the repeated multi foo (...)s.
From what I see in this answer, that's not really an implementation of a guard pattern in the same sense Haskell has them. However, Perl 6 does have guards in the same sense Scala has: using default patterns combined with ifs.
The Haskell to Perl 6 guide does have a section on guards. It hints at the use of where as guards; so that might answer your question.
TL;DR You've encountered what I'd call a WTF?!?: when Type and ... fails to check the and clause. This answer talks about what's wrong with the when and how to fix it. I've written another answer that focuses on using where with a signature.
If you want to stick with when, I suggest this:
when (condition when Type) { ... } # General form
when (* > 10 when Int) { ... } # For your specific example
This is (imo) unsatisfactory, but it does first check the Type as a guard, and then the condition if the guard passes, and works as expected.
"Is this right?"
No.
given $ch {
when Int and * > 10 { say 65}
}
This code says 65 for any given integer, not just one over 10!
WTF?!? Imo we should mention this on Raku's trap page.
We should also consider filing an issue to make Rakudo warn or fail to compile if a when construct starts with a compile-time constant value that's a type object, and continues with and (or &&, andthen, etc), which . It could either fail at compile-time or display a warning.
Here's the best option I've been able to come up with:
when (* > 10 when Int) { say 65 }
This takes advantage of the statement modifier (aka postfix) form of when inside the parens. The Int is checked before the * > 10.
This was inspired by Brad++'s new answer which looks nice if you're writing multiple conditions against a single guard clause.
I think my variant is nicer than the other options I've come up with in previous versions of this answer, but still unsatisfactory inasmuch as I don't like the Int coming after the condition.
Ultimately, especially if/when RakuAST lands, I think we will experiment with new pattern matching forms. Hopefully we'll come up with something nice that provides a nice elimination of this wart.
Really? What's going on?
We can begin to see the underlying problem with this code:
.say for ('TrueA' and 'TrueB'),
('TrueB' and 'TrueA'),
(Int and 42),
(42 and Int)
displays:
TrueB
TrueA
(Int)
(Int)
The and construct boolean evaluates its left hand argument. If that evaluates to False, it returns it, otherwise it returns its right hand argument.
In the first line, 'TrueA' boolean evaluates to True so the first line returns the right hand argument 'TrueB'.
In the second line 'TrueB' evaluates to True so the and returns its right hand argument, in this case 'TrueA'.
But what happens in the third line? Well, Int is a type object. Type objects boolean evaluate to False! So the and duly returns its left hand argument which is Int (which the .say then displays as (Int)).
This is the root of the problem.
(To continue to the bitter end, the compiler evaluates the expression Int and * > 10; immediately returns the left hand side argument to and which is Int; then successfully matches that Int against whatever integer is given -- completely ignoring the code that looks like a guard clause (the and ... bit).)
If you were using such an expression as the condition of, say, an if statement, the Int would boolean evaluate to False and you'd get a false negative. Here you're using a when which uses .ACCEPTS which leads to a false positive (it is an integer but it's any integer, disregarding the supposed guard clause). This problem quite plausibly belongs on the traps page.
Years ago I wrote a comment mentioning that you had to be more explicit about matching against $_ like this:
my $ch = 23;
given $ch {
when $_ ~~ Int and $_ > 10 { say 65}
when '+' { say 1 }
when '-' { say -1 }
default { say 0 }
}
After coming back to this question, I realized there was another way.
when can safely be inside of another when construct.
my $ch = 23;
given $ch {
when Int:D {
when $_ > 10 { say 65}
proceed
}
when '+' { say 1 }
when '-' { say -1 }
default { say 0 }
}
Note that the inner when will succeed out of the outer one, which will succeed out of the given block.
If the inner when doesn't match we want to proceed on to the outer when checks and default, so we call proceed.
This means that we can also group multiple when statements inside of the Int case, saving having to do repeated type checks. It also means that those inner when checks don't happen at all if we aren't testing an Int value.
when Int:D {
when $_ < 10 { say 5 }
when 10 { say 10}
when $_ > 10 { say 65}
}

Refer to only lower index in System Verilog

I have a bit array A[32][16].
I want to check if any of the lower index values have a certain pattern.
For eg.
A[1][8:0] may have that pattern A[2][8:0] may also have that pattern.
Any thing from A[31 - 0][8:0] may have that pattern. Is there a way to refer to all the higher index components in a single statement.
something like A[5'bxxxxx][8:0] ?
There is no syntax to select a non-contiguous set of bits from an array, packed or unpacked, in a single selection. If A is an unpacked array, you can use one of the array reduction methods to create an expression that might suit your needs.
if (A.or() with (item[8:0] == your_pattern) ) // if any match
if (A.and() with (item[8:0] == your_pattern) ) // if all match
If A is a packed array, you could use replication concatenation to match all
if ( {32{ {8'b?,your_pattern} } } ?== A )

Triggering more then 1 rules in DROOLS DRL File

I have a drl file containing 10 rules. Each has a condition like -
Rule 1
when
field1 == "X"
then
status == "A"
Rule 2
when
field1 == "Y"
then
status == "A"
So as seen based on value of variable field1 rules are to be executed.
Now I have a object containing more then 1 value like List. So if the List contains both values X & Y, only Rule 1 is applied and then processing is stopped. Rule 2 is never triggered.
Is there any way I can ask DROOLS to continue applying Rules even if 1 rule is successful ?
The correct way of writing a rule that matches a String field (called field) in a class Type is
rule "match field"
when
Type( field == "X" )
then
//...
end
You can write another rule where you match against "Y", which is indicated if you need to do something else. If you want to do the same, you can write a slightly more complex test:
rule "match field"
when
Type( field == "X" || == "Y" )
then
//...
end
(Yes, this unusual syntax is permitted in Drools' DRL language.)
To test for a value contained in a List, you can write
rule "match list element"
when
List( this contains "X" )
then
//...
end
Again, you can write another rule where you test for contains "Y", and it will fire, too, as long as the List<String> contains "X" and "Y".
A bare List as a fact in Working Memory is usually not a good idea. But if a class member is a List, a similar form can be used:
rule "match value in list member"
when
Type( list contains "X" )
then
//...
end
There is no need for special precaution to be taken for more than one rule firing. The standard activation session.fireAllRules() fires until all activations have been processed.
Some rule attributes may have the effect of terminating the processing of activations prematurely - use them cautiously.
Try calling fireAllRules(); available in Drools session.
It provides you following variances:
fireAllRules();
fireAllRules(AgendaFilter agendaFilter)
fireAllRules(AgendaFilter agendaFilter, int max)
fireAllRules(int max)
In last two variances, max is the upper limit on the rules to be fired. In your example, if you use max as 10, it can fire all 10 rules provided they meet the criteria.
Please Note: The rules should be configured in such a way that they qualify for execution based on the updated state. Request you to review the criteria fragment (the when clause of the rules and ensure that they indeed result into positive evaluation during execution.
e.g. if rules are written like below:
Rule 1
when
field1 == "X"
then
status == "A"
Rule 2
when
field1 == "Y"
then
status == "A"
then either field1 == "X" is true or field1 == "Y" is true and thus will trigger one rule at MAX.
But if we write the rules like
Rule 1
when
field1 == "X" || field1 == "Y"
then
status == "A"
Rule 2
when
field1 == "X" || field1 == "Y"
then
status == "A"
then both the rules i.e. Rule 1 and Rule 2 will qualify if field1 is X or Y.
Hope this helps.
I'm going to give you a bit of a different answer because I don't know what drools is but I can tell you how we do this in other languages. Basically it requires a string builder concept and some logic touch point changes.
Set your string:
string yourLongerStatusStringSetter = '';
Work through your checking and append your string:
Rule 1 when field1 == "X" then yourLongerStatusStringSetter &= "Meets Status A criteria."
Rule 2 when field1 == "Y" then yourLongerStatusStringSetter &= " Meets Status B criteria."
Continue rules and checks and appending (provided criteria is met)
Output your 'statuses':
howeverYouWriteYourOutput( yourLongerStatusStringSetter )
Which will print to the screen:
Meets Status A criteria. Meets Status B criteria
Just food for thought on an alternate approach.

Drools - Multiple matches in then clause

I am creating a rule which needs to fire when one or more conditions are met. The rule looks as follows:
rule "Demo Rule"
when
$data : Data (val == 1 || val == 2)
then
System.out.println($data);
end
I have a test for the rule, which has two matching Data objects (val 1 and val 2). The rule fires correctly, as it gets to the print statement. However, I can't find a way to parse $data and get access to the individual matching Data objects. The println results as follows:
custom.package.Data< val: 1, text:'Test1' >
custom.package.Data< val: 2, text:'Test2' >
So, I can see that multiple entries are present. But attempting to call as an array ($data[0]) or $data$1 or anything I could think of all result in parsing errors by Drools (complaining that $data is a Data object, not an array or list or other iterable).
The rule is fired once per each object matching your condition. So, you'll need to access the Data object directly as $data.val and data.text
If you need/want the objects in a list, you can use collect for that. Then your rule would be like
rule "Demo Rule"
when
$dataList : ArrayList() from collect( Data (val == 1 || val == 2) )
then
System.out.println($dataList);
end

Why does the 'from' keyword iterate backwards?

I have an ArrayList in working memory that I am iterating with a 'from' statement in my when clause. However, the rule is iterating backwards through the array. Is there a way to control this behavior?
List Creation:
List<Map<String,String>> list = new ArrayList<Map<String,String>>();
Map<String,String> m1 = ...
Map<String,String> m2 = ...
list.add(m1);
list.add(m2);
ImportItem item = new ImportItem(list); //model object. Constructor arg returned by getInput()
StatelessKnowledgeSession session = knowledgeBase.newStatelessKnowledgeSession();
session.insert(item);
session.fireAllRules();
Drools rules:
rule "My Rule"
dialect "java"
when
item : ImportItem(ignore == false) //model object that holds the input
map : Map() from item.getInput() // == the ArrayList from above
then
System.out.println(map);
end
Produces
<output of m2>
<output of m1>
The iteration is not backwards, as you can see if you attach an audit log to your session. The execution of the rules is what follows, by default, a LIFO order (in case you are not using any other conflict resolution strategy).
My suggestion for you is don't try to encapsulate the objects in data structures. If you are reading lines of a file and you need to process these lines in order, just use a class to represent the line and insert the lines directly into the session. To guarantee execution order, you can use the line number as a parameter to salience.
For instance:
rule "Process lines in order"
// salience executes from higher number to lowest number, so using the
// negative value you will executem them from the first to the last
salience (- $lineNumber )
when
$line : Line( $lineNumber : lineNumber )
then
// do something with $line
end
Obviously the same trick can be used with the "from" approach you took, but the engine is much more efficient matching facts in the working memory than it is iterating over collections of objects.
Hope it helps.
Edson
You should always try to write the rules so that the order doesn't count. If however, you really really need to have rules firing in certain order, or in this case, get the facts from a list in a certain order. Make sure that whatever changes in the rule engine internals doesn't break up your rules when you update to a newer version of the engine.
You can't trust the "from" even if it did the iteration the other way around.
There is one problem with this solution. If you update the ImportItem and need to iterate through the input again, you need to retract the MyIterator that is related to it.
declare MyIterator
index:int
lastIndex:int
importItem:ImportItem
end
rule "Insert ImportItem iterator"
when
item : ImportItem()
not MyIterator( importItem == item )
then
MyIterator myIterator = new MyIterator();
myIterator.setImportItem( item );
myIterator.setIndex( 0 );
myIterator.setLastIndex( item.getInput().size() );
insert( myIterator );
end
rule "My Rule"
when
myIterator :MyIterator( index < lastIndex )
item : ImportItem( this == myIterator.importItem,
ignore == false )
map : Map() from item.getInput().get( myIterator.getIndex() )
then
System.out.println(map);
myIterator.setIndex( myIterator.getIndex() + 1 );
update( myIterator );
end