Drools rules execution hangs - drools

The following rule hangs drools:
rule "Sound the alarm in case temperature rises above threshold"
when
$m1 : TempReading( temp >= 35 )
Number( doubleValue >= 2 ) from accumulate(
TempReading( temp >= 35, this after[0s, 1m] $m1 ),
init( double total = 0; ),
action( total += 1; ),
reverse( total -= 1; ),
result( total ) )
then
System.out.println("Temp over max")
end
I have log statements in ObjectXXXEvents which are all logged tight away.
It looks like this:
Object inserted
com.sample.DroolsTest$TempReading#6bab2585
Object inserted
com.sample.DroolsTest$TempReading#a486d78
Object inserted
com.sample.DroolsTest$TempReading#cdc3aae
Object inserted
com.sample.DroolsTest$TempReading#7ef2d7a6
Object inserted
com.sample.DroolsTest$TempReading#5dcbb60
I have log statements for matchCreated, matchCancelled, beforeMatchFired and afterMatchFired and NONE of them are logged.
If I change the clockType to psuedo it exits but the rule does not fire.
What gives?

Related

Drools variable binding: reassignment not allowed

Assume that MyObject is a Java Object with an integer property called integerProperty.
I would like to write a Drools rule like the following (syntactically incorrect):
rule "myRule"
when
MyObject( $integerProperty : integerProperty )
accumulate(
$o : MyObject(
integerProperty == $integerProperty + 1,
$integerProperty : this.integerProperty
);
$total : count($o);
$total > 10
)
then
[BLABLABLA]
end
I want to fire my rule when there is a set of more than 10 elements of type MyObject whose integerProperty values form an arithmetic sequence, e.g. 1, 2, 3, … In this case, I will assign a negative value to an HardMediumSoftLongScore object (hoping that information this helps).
I am sure that an MyObject having a given integerProperty is unique (eg. there is just one MyObject having integerProperty equal to, say, 2). The problem is that I'm not allowed to re-assign the variable binding $integerProperty. Is there a way around this?
Try implementing the below example and check whether you are getting your desired output. Before firing the rule insert the previous object as a global variable (prev in the example below) in the drool session.
global MyObject prev;
rule "myRule"
when
$total : Number(doubleValue > 10) from accumulate(
$o : MyObject( prev.getIntegerProperty() != null && $i : integerProperty == prev.getIntegerProperty() + 1),
init( double total = 0;),
action( total += 1; ),
reverse( total -= 1; ),
result( new Double( total ) ) )
then
[BLABLABLA]
end
In your java code before firing the rule set the previous object as a global object. Follow the code below :
kieSession.setGlobal("prev",myprevobject)
kieSession.insert(myobject)
kieSession.fireAllRules()

Drools - Accumulate logic

I need help in writing the accumulate logic for below requirement:
Requirement: Certain rules will provide the percentage to be applied for global value. Another set of rules should use the aggregate total percentage in determining the result.
For example: 0.75 is the global value passed as input(threshold).
Rule 1 might apply -10% of the fixed value ie. 0.75 - (0.75 * 0.10) = 0.675
Rule2 will apply + 20% off updated value. ie., 0.675 + (0.675 * 0.20) = 0.81
My global value is 0.75 (Threshold)
Using the below rules I am trying to applied the percentage applicable for a fixed value :
//class imports
global Double FIXED_THRESHOLD;
//Rules
rule "Prediction Rule_2"
lock-on-active true
no-loop true
salience (2)
when
LossInput (airBagDeployed == 'Y' , driveable == 'N')
result : RuleResult(predictedTotalsThreshold == 0)
then
insert(new ControlFact( -10.0 ) ); //Reduce -10% to global value 0.75 - 0.75* 0.10 = 0.675
System.err.println("New control fact added to working memory....");
end
rule "Prediction Rule_1"
lock-on-active true
no-loop true
salience (1)
when
LossInput (airBagDeployed == 'Y' , driveable == 'N', make == 'Honda' )
result : RuleResult(predictedTotalsThreshold == 0)
then
insert(new ControlFact( 20.0 ) ); // Add 20% to the updated aggregate (0.20 % of 0.675).
System.err.println("New control fact added to working memory....");
end
I tried the below accumulate logic but obviously it is wrong. It is applying only to fixed value always instead of the updated value.
rule "Aggregate All Threshold"
no-loop true
when
$aggregateTotalsThresholdPercentage : Number() from accumulate(
ControlFact( $totalsThreshold : totalsThresholdPercentage ),
sum( ( FIXED_THRESHOLD + ( FIXED_THRESHOLD * $totalsThreshold ) / 100 ) ) )
ruleResult: RuleResult(predictedTotalsThreshold == 0)
then
ruleResult.setPredictedTotalsThreshold($aggregateTotalsThresholdPercentage.doubleValue());
update(ruleResult);
end
POJO:
public class LossInput{
private String airBagDeployed;
private String driveable;
private String make;
}
public class ControlFact {
public double totalsThresholdPercentage;
}
public class RuleResult {
private double predictedTotalsThreshold;
}
//insert facts in working memory
kieSession.insert(lossInput);
kieSession.insert(ruleResult);
kieSession.setGlobal("FIXED_THRESHOLD", new Double(0.75));
kieSession.fireAllRules();
Please help on the accumulate logic to apply the updated value everytime when percentage threshold to be applied.
You cannot use accumulate/sum this way because you add the FIXED_THRESHOLD for each ControlFact.
Insert ControlFacts as you have in the "Prediction..." rules (without all the rule attributes). Use each ControlFact to update RuleResult's predictedTotalsThreshold. The "Aggregate" rule will fire repeatedly, and therefore you need to make sure to retract the used ControlFact.
rule "Aggregate All Threshold"
when
ControlFact( $ttp: totalsThresholdPercentage );
$res: RuleResult( $ptt: predictedTotalsThreshold)
then
double nt = $ptt + $ptt*$ttp/100;
modify( $res ){ setPredictedTotalsThreshold( $nt ) }
retract( $res );
end

Working with consecutive events in drools

I need help with the following rule:
Accounts with multiple consecutive deposits and immediately after 4 hours, multiple extractions whose sum is equal to the same amount deposited using different ATM in the same bank.
(There aren't intermediate operations between the last deposit and the first extraction)
I have the class Operation: Account, Amount, Operation, ATM, Timestamp.
I have this rule:
declare Operation
#role(event)
#timestamp(Timestamp)
end
rule
when
$op1:Operation($acc:Account,$b:Bank,$amount:Amount,Operation‌​=="CREDIT",$atm:ATM)
not Operation(Account == $acc,ATM != $atm, Bank == $b, this before $op1) accumulate($op2:Operation(Account == $acc,ATM != $atm, Bank == $b,Operation=="CREDIT",$amount1:Amount);$c:count($op2),$d:su‌​m($amount1);$c>=4,$d‌​>=300)
then
System.out.println( "Account: " + $acc + " amount " + ($amount + $d) + " operations " + $c+ " in different banks");
end
The previous rule returns the sum of the deposits of the accounts that have made more than 4 operations in different ATMs of the same bank,my doubt is how to take into account that they are consecutive and that after 4 hours compare the previous sum with the sum of the extractions from that account.
If this rule fires,
rule "set up Monitor"
when
$op1: Operation( $a:account, $b:bank, $amt1:amount, operation‌​=="CREDIT", $atm1: atm )
$op2: Operation( account==$a, bank==$b, $amt2:amount, operation‌​=="CREDIT", atm!= $atm1 )
not Operation(account == $acc, atm != $atm1, bank == $b,
this before $op2, this after $op1 )
not Monitor( bank == $bank, account == $acc )
then
insert( new Monitor( $bank, $acc, $amt1 + $amt2, "CREDIT" );
end
you have a Monitor inserted. The monitor has the obvious fields and a state field, set to "CREDIT".
rule "add deposit"
when
$op1: Operation( $a:account, $b:bank, $amt1:amount, operation‌​=="CREDIT", $atm1: atm )
$mon: Monitor( account==$a, bank==$b, $bal: balance, state == "CREDIT" )
then
// another deposit
modify( $op1 ){ setAmount( $bal + $amt1 ) }
end
With this event, the state changes to withdrawal.
rule "state changes to withdrawal"
when
$op1: Operation( $a:account, $b:bank, $amt1: amount, operation‌​=="WITHDRAW", $atm1: atm )
$mon: Monitor( account==$a, bank==$b, $bal: balance, state == "CREDIT" )
then
// switch to withdraw
modify( $op1 ){ setAmount( $bal + $amt1 ),
setState( "WITHDRAW" ) }
end
And here it begins to get messy. We need to check whether this (first) withdrawal cashes in on all deposits (balance == $amt1) or just reduces the balance or withdraws more than the previous sequence of deposits have made.
I quit here, but I think I've shown that this isn't possible to do with a single rule.

Why does loop crash and and not print? Unity3D

Given a cubic space, this function searches for the next large empty space, places a marker there, and then quits.
However, the function doesn't even print the check message that exists prior to the loops starting, so i don't know how to debug it. The checking starts at 0,0,0 and spaces outside the voxel are returned as true, so it should default all the first loops and send messages back. The unity.exe process jams and i have to abort it.
Why doesn't it print? What else is wrong with it? Even if it is slow, i should be able to track progress within the loops? why wouldn't it?
function findvoidable() //find void space in voxel volume
{
var step = dist+1;
print("start"); WaitForFixedUpdate(); //this doesnt print
for ( var k : int = 0; k < mesher.PNGpaths.Length ; k+=step/2)
for ( var j = 0; j < mesher.tex.height ; j+=step/2)
for ( var i = 0; i < mesher.tex.width ; i+=step/2){
print("in schema");WaitForFixedUpdate();
if (wst( i , j , k )==false )
if (wst( i+step,j ,k )==false )
if (wst( i-step,j ,k )==false )
if (wst( i ,j+step,k )==false )
if (wst( i ,j-step,k )==false )
if (wst( i ,j ,k+step )==false )
if (wst( i ,j ,k-step )==false )
{
var cnt=0;
for ( var x = i-step; x < i+step ; x+=1)
for ( var y = j-step; y < j+step ; y+=1)
for ( var z = k-step; z < k+step ; z+=1)
{
if ( wst( x , y , z ) == false )
cnt+=1;
}
if ( cnt >= step*step*step-3 )
{
refCube.transform.position=Vector3(i,j,k);
break;break;break;break;break;break;
}
else
{
WaitForFixedUpdate();
refCube.transform.position=Vector3(i,j,k);
}
}
}
}
WaitForFixedUpdate is a Coroutine and is not supposed to be run like a normal method.
Instead, try "yield" statement:
yield WaitForFixedUpdate();
More info: https://docs.unity3d.com/ScriptReference/Coroutine.html

Check whether the sum in a list is greater than 100

I have to write a drool function on a list which has to do the following thing
create a summation
check whether the summation is greater than 100.
below is the drool rule I have created
rule "001"
when
$charge : MainClass(subList.size() > 0)
$item : SubListClass(number < 0) from $charge.subOrderROList
$total : Number() from accumulate(SubListClass( $p : number ),sum( $p )
then
int index = $charge.SubListClass.indexOf($item)+1;
violations.error(kcontext, "ad", "ad.message", new String[]{String.valueOf(index),$item.getNumber().toString()},index);
end`
I am not able to check whether the $total is greater than 100
thanks
This would be correct if it were possible to obtain a sum > 100 by adding negative numbers. I have kept the constraints as they were in the Q, so change this as appropriate. Maybe number > 0?
rule "001"
when
$charge: MainClass(subList.size() > 0)
$total: Number( intValue > 100 )
from accumulate( SubListClass($p: number < 0)
from $charge.subOrderROList,
sum( $p ) )
then