Drools how to compare Integer - drools

I have an Integer, and I want to compare it to some raw int like so:
$day : Day()
$itemsList : from collect(Item())
$number : Integer() from $day.getNumberOfItemsAvailable($itemsList)
$number > 4
but I'm getting
Message [id=1, kieBase=defaultKieBase, level=ERROR, path=ScoreRules.drl, line=42, column=0
text=[ERR 102] Line 42:21 mismatched input '<' in rule "rule"]
How do you compare an Integer to some other int value? Could you point me to some documentation that explains basics like this?

While you could use an eval statement as suggested in the previous answer, such constructs are not recommended because they can't be optimized.
Alternatively you could check in the same line where you assign your $number variable like this:
$number : Integer( this > 4 ) from $day.getNumberOfItemsAvailable($itemsList)
This will only assign number if the getNumberOfItems... call returns an integer greater than four. If the returned value is less, the condition won't be satisfied and the rule won't be evaluated.

You need to use the operator with int value.
eval($number.intValue() > 4)

Related

How to use length and rlike using logical operator inside when clause

Want to check if the column has values that have certain length and contains only digits.
The problem is that the .rlike or .contains returns a Column type. Something like
.when(length(col("abc")) == 20 & col("abc").rlike(...), myValue)
won't work as col("abc").rlike(...) will return Column and unlike length(col("abc")) == 20 which returns Boolean (length() however also returns Column). How do I combine the two?
After doing a bit of searching in compiled code, found this
def when(condition : org.apache.spark.sql.Column, value : scala.Any) : org.apache.spark.sql.Column
Therefore the conditions in when must return Column type. length(col("abc")) == 20 was evaluating to Boolean.
Also, found this function with the following signature
def equalTo(other : scala.Any) : org.apache.spark.sql.Column
So, converted the whole expression to this
.when(length(col("abc")).equalTo(20) && col("abc").rlike(...), myValue)
Note that the logical operator is && and not &.
Edit/Update : #Histro's comment is correct.

Ada - Commando- line reader and processer

A program that loads and processes command-line arguments should be created.
Here comes a few examples on how it should look when you run it (bold text is the text that the user will type):
Terminal prompt % **./my_program**
No arguments given.
Terminal prompt % **./my_program 123**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 10 XYZ 999 Greetings!**
Wrong amounts of arguments given.
Terminal prompt % **./my_program 3 HELLO**
Message: HELLOHELLOHELLO
The program "./my program" is ending.
Terminal prompt % **./my_program 0 Bye**
Message:
The program "./my program" is ending.
This is my code so far:
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
type String is array (Positive) of Character;
N : Integer;
Text : String;
begin
N := Argument_Count;
if N = 0 then
Put_Line("No arguments given.");
elsif N /= 2 then
Put_Line("Wrong number of arguments given.");
elsif N = 2 then
Put("Message: ");
for I in 1 .. N loop
Put(Text);
New_Line;
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
end my_program;
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says
Missing argument for parameter "Item" in call to "Put"
I don't know if I declared my string right because I don't want a string of a specific length. Can anyone come up with something that could help me solve case 4 and 5? It would be nice and highly appreciated
This seems to be a homework or exam question, so I would usually not provide a full answer. But Chris already gave that (with some defects), so here is my suggestion. Compared to Chris's solution, I try to avoid using unnecessary variables, and I favour case statements over if-then-else cascades, and I try to reduce the scope of exception handlers. I prefer to put use clauses in the subprogram so that the context-clause section contains only with clauses. I use the string-multiplying "*" operator from Ada.Strings.Fixed, but that is perhaps an unnecessary refinement.
with Ada.Command_Line;
with Ada.Strings.Fixed;
with Ada.Text_IO;
procedure My_Program
is
use Ada.Strings.Fixed;
use Ada.Text_IO;
begin
case Ada.Command_Line.Argument_Count is
when 0 =>
Put_Line ("No arguments given.");
when 2 =>
begin
Put_Line (
Natural'Value (Ada.Command_Line.Argument(1))
* Ada.Command_Line.Argument(2));
exception
when Constraint_Error =>
Put_Line ("Invalid input for argument 1.");
end;
when others =>
Put_Line ("Wrong amount of arguments given.");
end case;
Put_Line (
"The program """
& Ada.Command_Line.Command_Name
& """ is ending.");
end My_Program;
Note that my version:
Rejects negative first arguments (like "-3").
Outputs the repeated strings on a single line, as was required by the examples given.
Includes the name of the program in the final message, as was also required.
Given the clarification in comments as to the purpose of the program, to print a message n times where n is the first argument, and the message is the second argument, you need to parse the first argument as an integer. This can be done with Integer'Value.
Now, that raises the prospect of the user not running the program with an integer. So we have to handle the possible Constraint_Error exception.
with Ada.Text_IO; use Ada.text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line; use Ada.Command_Line;
procedure my_program is
argc : Integer;
N : Integer;
begin
argc := Argument_Count;
if argc = 0 then
Put_Line("No arguments given.");
elsif argc /= 2 then
Put_Line("Wrong number of arguments given.");
else
n := Integer'Value(Argument(1));
Put("Message: ");
for I in 1 .. N loop
Put_Line(Argument(2));
end loop;
Put("The program """);
Put(""" is ending. ");
end if;
exception
when Constraint_Error =>
Put_Line("Invalid input for argument 1.");
end my_program;
As an aside, when we've checked in our conditional if argc is zero, and that it doesn't equal two, we don't have to use elsif. The only other possibility is that it is 2.
You say
My program handles the first 3 three cases but when I go ahead with the 4th and 5th (last) case I get an error code at the row Put(Text) where it says "Missing argument for parameter "Item" in call to "Put". "
which doesn't make sense, because your program as shown doesn't compile. I guess what you mean is "when I try to add the code to handle cases 4 and 5, it doesn't compile".
The reason why it doesn’t compile is hidden in the actual error messages:
leun.adb:24:10: no candidate interpretations match the actuals:
leun.adb:24:10: missing argument for parameter "Item" in call to "put" declared at a-tiinio.ads:97, instance at a-inteio.ads:18
...
leun.adb:24:14: expected type "Standard.Integer"
leun.adb:24:14: found type "String" defined at line 7
leun.adb:24:14: ==> in call to "Put" at a-tiinio.ads:80, instance at a-inteio.
You have at line 7
type String is array (Positive) of Character;
which is both misleading and not what you meant.
It’s ’not what you meant’ because array (Positive) means an array of fixed length from 1 to Positive’Last, which will not fit into your computer’s memory. What you meant is array (Positive range <>).
Even with this correction, it's 'misleading' because although it would be textually the same as the declaration of the standard String in ARM 3.6.3(4), in Ada two different type declarations declare two different types. So, when you write Put(Text); the Put that you meant to call (the second in ARM A.10.7(16)) doesn’t match because it’s expecting a parameter of type Standard.String but Text is of type my_program.String.
Cure for this problem: don’t declare your own String type.

Optaplanner - Drools for int array constraint

I'm trying to write a constraint to check if any element of a integer array (binUsedArray) is greater than a bound (dailyMaxNb).
rule "BinResourceConstraint"
when
BinResource($array : binUsedArray, $dailyMaxNb : dailyMaxNb)
$x : Integer() from $array
$x > $dailyMaxNb
then
scoreHolder.addHardConstraintMatch(kcontext, -1);
end
I read drools doc 5.1.8 and tried to write a similar rule like this
rule "Iterate the numbers"
when
$xs : List()
$x : Integer() from $xs
then
$x matches and binds to each Integer in the collection
end
but got some error:
Caused by: java.lang.RuntimeException: [Message [id=1, kieBase=defaultKieBase, level=ERROR, path=com/cttq/aps/solver/taskScheduleConstraint.drl, line=78, column=0
text=[ERR 102] Line 78:11 mismatched input '>' in rule "BinResourceConstraint"], Message [id=2, kieBase=defaultKieBase, level=ERROR, path=com/cttq/aps/solver/taskScheduleConstraint.drl, line=0, column=0
text=Parser returned a null Package]]
===== updated with BinResource class, binUsedArray is a int array with size of 30, to keep number of bins used for next 30 days.
#PlanningEntity
public class BinResource {
private String index;
private String binType;
private String binArea;
private int dailyMaxNb;
#CustomShadowVariable(variableListenerRef = #PlanningVariableReference(entityClass = TaskAssignment.class, variableName = "modifiedProcessTimeInShift"))
private int[] binUsedArray;
The trivial solution would be to convert your array to a List and then it'll just work. Arrays.asList( array ) can be invoked on the LHS to convert the array ... something like:
BinResource($array : binUsedArray, $dailyMaxNb : dailyMaxNb)
$binUsed: List() from Arrays.asList($array)
Then you can do the same logic from the second rule to find the values which meet your criteria:
$x : Integer(this > $dailyMaxNb) from $binUsed
With that, your rule will trigger once for each value ($x) in the array / list which is greater than the dailyMaxNb value.
rule "BinResourceConstraint"
when
BinResource($array : binUsedArray, $dailyMaxNb : dailyMaxNb)
$binUsed: List() from Arrays.asList($array)
$x : Integer(this > $dailyMaxNb) from $binUsed
then
// this will trigger once PER MATCH ...
// eg if there are 3 values that > dailyMaxNb, this will trigger 3 times
scoreHolder.addHardConstraintMatch(kcontext, -1);
end
If, however, your binUsedArray is actually an ArrayList, you can omit the conversion and just use $x: Integer(this > $dailyMaxNb) from $array. I mention this because sometimes when people ask about an "array" they're actually referring to an array list, and you've not provided the code of your BinResource class. That being said, you can use this pattern (MyType( <condition> ) from $collection) for any iterable collection to attempt to match against all values in that collection.

Handle division is undefined on JasperReport

I have variables in JasperReport 6.60 which is doing some weighted average, and I tried to avoid division by zero by passing it through IF condition but it still producing "Division is undefined"
Let's say I want to show a variable $V{weighted_avg} on a group called ([Group] round), which is consist of two rounds. On the 1st round, $V{divisor} is zero (0), but on the 2nd round $V{divisor} is not zero
The variable $V{weighted_avg} contains expression :
IF($V{divisor}.compareTo(BigDecimal(0.00)) == 1, $V{dividend}.divide($V{divisor}, new MathContext(4)), null)
it will produced error "Division is undefined" on that expression when calculated.
But if I am doing this :
IF($V{divisor}.compareTo(BigDecimal(0.00)) == 1, "> 0", "< 0")
the result is correctly showed.
All variables is Bigdecimal and I expected the $V{weighted_avg} is showing "null" when the $V{divisor} is zero
The builtin IF function evaluates all its arguments, you need to use the Java ternary operator so that only the expression that corresponds to the matching branch gets evaluated.
As in
$V{divisor}.compareTo(BigDecimal(0.00)) == 1 ? $V{dividend}.divide($V{divisor}, new MathContext(4)) : null

Strings Expansion is changing order or the string

I'm trying to so some normal variable expansion in a string and, when it's in a function, it comes out out-of-order.
function MakeMessage99($startValue, $endValue) { "Ranges from $startValue to $endValue" }
MakeMessage99(1, 100)
This returns Ranges from 1 100 to then it should return Ranges from 1 to 100
Functions in powershell shouldn't use parenthesis to enclose parameters. Instead:
PS C:\> MakeMessage99 1 100
Ranges from 1 to 100
Where MakeMessage is your function, "1" is a parameter in the first position, and "100" is a parameter in the second position. According to about_Functions_Advanced_Parameters:
By default, all function parameters are positional. Windows PowerShell assigns position numbers to parameters in the order in which the parameters are declared in the function.
Powershell has several ways to check input going in. You could cast the input as a numeric type. There are also baked-in validation methods for parameters that may prevent this sort of error in the future. If you really want an integer, a simple cast would cause an array to be invalid input. For example:
function MakeMessage99 {
Param
(
[int]$startValue,
[int]$endValue
)
"Ranges from $startValue to $endValue"
}
You could also explore range validation (such as [ValidateRange(0,100)]), pattern validation (such as [ValidatePattern("[0-9][0-9][0-9][0-9]")] to validate a four-digit number) or other validation attributes listed in the link above.
This is a common pitfall in PowerShell. When you invoke...
MakeMessage99(1, 100)
...you're actually passing an array containing the values 1 and 100 as the first parameter. To pass 1 as the first parameter and 100 as the second parameter, use...
MakeMessage99 1 100