Drool does not sort numbers correctly - drools

I am new to Drools and am trying to get the sample program to work.
This sample is given in the drools documentation http://docs.jboss.org/drools/release/5.5.0.Final/drools-expert-docs/html_single/index.html#d0e9542.
This drool rule is expected to sort integers. I just changed the numbers from what are given in the sample and they do not get sorted as expected.
Tried using drools version 5.5.0, 5.5.1 and the master 6.0.0, but got the same wrong results.
Following is the main code:
package com.sample;
public class Example2 {
public static void main(String[] args) throws Exception {
Number[] numbers = new Number[] { wrap(5), wrap(6), wrap(4), wrap(1), wrap(2) };
new RuleRunner().runRules(new String[] { "Example3.drl" }, numbers);
}
private static Integer wrap(int i) {
return new Integer(i);
}
}
The RuleRunner class is the same as given in the example and I do not think I should give that here, since it will clutter the question. It simply creates the KnowledgeBase, stateful session, inserts the facts as given in the 'numbers' array above and then calls fireAllRules method on the session.
The rule file (Example3.drl) is:
rule "Rule 04"
dialect "mvel"
when
$number : Number()
not Number(intValue < $number.intValue)
then
System.out.println("Number found with value: " + $number.intValue());
retract($number);
end
The output I get is as follows:
Loading file: Example3.drl
Inserting fact: 5
Inserting fact: 6
Inserting fact: 4
Inserting fact: 1
Inserting fact: 2
Number found with value: 1
Number found with value: 4
Number found with value: 2
Number found with value: 5
Number found with value: 6
Not the correct expected ascending sorted order.
What might I be doing wrong? I cannot imagine that the drools rule engine would be broken at this basic level.

This seems to be a bug that was introduced in 5.5.0 onwards and still exists.
This sorting code works fine with 5.4.0.
Workaround:
Instead of: "not Number(intValue < $number.intValue)" If you use: "not Number(intValue() < $number.intValue)" Then it works.
A non-getter method without telling that it is a function seems to create a problem.
A debilitating problem that reduces the confidence in the product in the evaluation phase.

Related

Solidity - Contract not working as expected

I am new to Solidity and Ethereum. I am at the stage where I have worked with basic HelloWorld and similar examples.
I have created a contract to generate a random number as follows
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
contract RandomNumber {
function generateRandomNumber(uint range) public view returns(uint) {
// As of 1-1-22 this contract is working okay at https://remix.ethereum.org/
// However I am having issues in running it through the Visual Studio Code IDE
return uint(keccak256(abi.encodePacked(block.timestamp,block.difficulty, msg.sender))) % range;
}
}
This contract is working when I deploy and run it at https://remix.ethereum.org/
However, If I try to deploy & run it within Visual Studio Code I get the following error
BN { negative: 0, words: [ 3, <1 empty item> ], length: 1, red: null }
Why should this happen? Any inputs are appreciated. I know I might be missing something basic here
Thanks in advance
It's been a while since I did any solidity coding, but this one is easy.
I believe your contract is working fine.
BN { negative: 0, words: [ 3, <1 empty item> ], length: 1, red: null }
BN is "big number". Since a 256 bit uint doesn't work with a javascript "number" (floating point) type, the result is encoded in a BN data structure. (i.e. your random number is embedded in the words member of your returned object. (I think it's a literal 3 if I read that output right).
In your local javascript that tests your Solidity contract, just invoke toString on the BN object that is returned.
https://ethereum.stackexchange.com/questions/67087/how-to-use-bignumbers-in-truffle-tests
Even though you did not share your javacript code, I can tell that it is because you are not awaiting.
Calling contract code is asynchronous and you either call it with async.await or with then/catch
//in truffle console:
randomContract=await RandomNumber.deployed()
randomNumber=await randomContract.generateRandomNumber(rangeInteger)
// this should print
randomNumber.toString()
Try to update the solidity library in Vs

How to Parse an int in an EF Core 3 Query?

Upon upgrading to EF Core 3, I am getting the following error at the following code:
System.InvalidOperationException: 'The LINQ expression 'DbSet
.Max(c => Convert.ToInt32(c.ClaimNumber.Substring(c.ClaimNumber.Length - 6)))'
could not be translated. Either rewrite the query in a form that can
be translated, or switch to client evaluation explicitly by inserting
a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or
ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for
more information.'
var maxId = Db.Claims
.Select(c => c.ClaimNumber.Substring(c.ClaimNumber.Length - 6))
.Max(x => Convert.ToInt32(x));
I have also tried using int.Parse instead of Convert.ToInt32, and it produces the same error. I understand the error message. However, it's trivial to get SQL Server to parse a string to an int in T-SQL with CAST or CONVERT, I would hope there's a simple way to write the query so that it translates to a server-side operation right?
UPDATE After Claudio's excellent answer, I thought I should add some info for the next person who comes along. The reason I believed the parsing was the problem with the above code is because the following runs without error and produces the right result:
var maxId = Db.Claims
.Select(c => c.ClaimNumber.Substring(c.ClaimNumber.Length - 6))
.AsEnumerable()
.Max(x => int.Parse(x));
However, I dug deeper and found that this is the SQL query EF is executing from that code:
SELECT [c].[ClaimNumber], CAST(LEN([c].[ClaimNumber]) AS int) - 6
FROM [Claims] AS [c]
WHERE [c].[ClaimNumber] IS NOT NULL
That is clearly not doing anything like what I wanted, and therefore, Claudio is right that the call to Substring is, in fact, the problem.
Disclaimer: although feasable, I strongly recommed you do not use type conversion in your query, because causes heavy query performance degradation.
Fact is that Convert.ToInt(x) part is not the problem here. It is c.ClaimsNumber.Substring(c.ClaimNumber.Length - 6), that the EF Core translator isn't able to translate in T-SQL.
Despite RIGHT function exists in Sql Server, also, you won't able to use it with current versions of EF Core (last version is 3.1.2 at the moment I'm writing).
Only solution to get what you want is to create a Sql Server user function, map it with EF Core and use it in your query.
1) Create function via migration
> dotnet ef migrations add CreateRightFunction
In newly created migration file put this code:
public partial class CreateRightFunctions : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(#"
CREATE FUNCTION fn_Right(#input nvarchar(4000), #howMany int)
RETURNS nvarchar(4000)
BEGIN
RETURN RIGHT(#input, #howMany)
END
");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(#"
DROP FUNCTION fn_Right
");
}
}
Then run db update:
dotnet ef database update
2) Map function to EF Core context
In your context class[DbFunction("fn_Right")]
public static string Right(string input, int howMany)
{
throw new NotImplementedException(); // this code doesn't get executed; the call is passed through to the database function
}
3) Use function in your query
var maxId = Db.Claims.Select(c => MyContext.Right(c.ClaimNumber, 6)).Max(x => Convert.ToInt32(x));
Generated query:
SELECT MAX(CONVERT(int, [dbo].[fn_Right]([c].[ClaimNumber], 6)))
FROM [Claims] AS [c]
Again, this is far from best practice, I think you should consider to add an int column to your table to store this "number", whatever it represents in your domain.
Also, first time last 6 characters of ClaimNumber contain a non-digit character, this won't work anymore. If the ClaimNumber is input by a human, sooner or later this will happen.
You should code and design your database and application for robustness, even if you're super sure that those 6 characters will always represent a number. They could not do it forever :)
Please change your code as below. It's working for me in Dotnet core 3.1 version
var maxId = Db.Claims.Select(c => c.ClaimNumber.Substring(c.ClaimNumber.Length - 6))
.Max(x => (Convert.ToInt32((x == null)? "0" : x.ToString())));

Drools: Get identifier from LHS pattern

I am using Drools 6.3.0 Final. Assuming I have a rule like this
rule "Child of Person over 18"
when
$person : Person(age > 18)
$child : from $person.children
then
end
Let us further assume I build my KieSession with this rule, add some facts and now I want to know the identifiers used in all rules / in all rules that matched my facts.
So what I want to get here is $person and $child.
I know I can get the rules, which fired using an AgendaEventListener and from the event I can get the name of the rule, as well as the objects for $person and $child. But I fail to find a way to get the identifiers $person and $child from my match. Using a debugger I can see the information is there... actually the Rule I get from the event, is a RuleImpl, which has a lhsRoot, in which I can find that information... but this sounds much more complicated than it should be and not the intended way.
So I was wondering if there is not a better way for this.
Your requirement can be easily achieved by using Drools' public API. You were looking at the right place (AgendaEventListener) but Match.getObjects() is not what you need. What you need is a combination of Match.getDeclarationIds() (to get the list of identifiers) and then Match.getDeclarationValue(String id) (to get the value for each identifier). As an example, this is how an AgendaEventListener that logs this information in the console will look like:
import org.kie.api.event.rule.BeforeMatchFiredEvent;
import org.kie.api.event.rule.DefaultAgendaEventListener;
...
ksession.addEventListener(new DefaultAgendaEventListener() {
#Override
public void beforeMatchFired(BeforeMatchFiredEvent event) {
String ruleName = event.getMatch().getRule().getName();
List<String> declarationIds = event.getMatch().getDeclarationIds();
System.out.println("\n\n\tRule: "+ruleName);
for (String declarationId : declarationIds) {
Object declarationValue = event.getMatch().getDeclarationValue(declarationId);
System.out.println("\t\tId: "+declarationId);
System.out.println("\t\tValue: "+declarationValue);
}
System.out.println("\n\n");
}
});
As #laune mentioned,you can also get an instance of the match that activated a rule in the RHS of the rules themselves. In this case, the Match object is accessible through drools.getMatch().
Hope it helps,

Java 8 Optional.ifPresent is my code wrong or is it eclipse?

I am new to Java 8 and trying out Null type annotations and Optional.
For my example below, I have used String rather than my class and am calling toUpperCase just to call something, in my case I actually call a function passing in a parameter (so don't think I can use :: operator and/or maps).
In Eclipse I have the Java - Compiler - Errors/Warnings - Null Analysis Errors turned on.
My test code below:
public void test1(#Nullable String s) {
// the 2nd s2 has a Potential null pointer access error.
// I was hoping ifPresent would imply NonNull
Optional.ofNullable(s).ifPresent(s2 -> s2.toUpperCase());
}
#Nullable
public String getSomeString() {
return null;
}
public void test2() {
String s = getSomeString();
// This is fine, unlike the first example, I would have assumed that
// it would know s was still nullable and behave the same way.
Optional.ofNullable(s).ifPresent(s2 -> s2.toUpperCase());
}
It would seem that using Eclipse type null annotations and Optional.ifPresent doesn't go well together.
Am I wasting my time trying to get something like this to work? Should I just revert back to assigning the getter to a temp var then checking if null, and if not call my function?
JDT's null analysis cannot know about the semantics of each and every method in JRE and other libraries. Therefore, no conclusions are drawn from seeing a call to ifPresent. This can be remedied by adding external annotations to Optional so that the analysis will see method ofNullable as
<T> Optional<#NonNull T> ofNullable(#Nullable T value)
External annotations are supported starting with Eclipse Mars, released June, 24, 2015. See Help: Using external null annotations.
The difference between the two variants in the question is due to how null analysis is integrated with Java 8 type inference: In variant (1) s has type #Nullable String. When this type is used during type inference, it is concluded that the argument to ifPresent is nullable, too. In variant (2) s has type String (although flow analysis can see that is may be null after the initialization from getSomeString). The unannotated type String is not strong enough to aid type inference to the same conclusion as variant (1) (although this could possibly be improved in a future version of JDT).
First of: #Nullable seams not to be part of the public Java 8 SDK. Have a look at the package you imported: com.sun.istack.internal.Nullable.
Second: I have run both of your methods: test1(null) and test2() and nothing out of the ordinary happened. Everything was fine (as expected). So what did you observe?
run test1(null) => no execution of lambda expression.
run test2() => no execution of lambda expression.
I changed your code for testing in the following way:
public void test1(#Nullable String s) {
Optional.ofNullable(s).ifPresent(s2 -> System.out.println("executed"));
}
public void test2() {
String s = getSomeString();
Optional.ofNullable(s).ifPresent(s2 -> System.out.println("executed"));
}

FakeItEasy expectation fail against HashSet comparisons

I am using Xamarin Studio 5.2 on Mac OS X 10.9.4 with NUnit 2.6.3 and FakeItEasy 1.23.0.
When I run tests for this code:
using System;
using ValueSet = System.Collections.Generic.HashSet<uint>;
using NUnit.Framework;
using FakeItEasy;
namespace SetTest
{
[TestFixture]
class TestFixture
{
[Test]
public void CallsUsersWithSetAndReducedSet()
{
var values = new ValueSet { 1, 2, 3 };
var setUser = A.Fake<SetUser>();
ClassUnderTest testInstance = new ClassUnderTest();
using (var scope = Fake.CreateScope())
{
testInstance.RunWith(setUser);
using (scope.OrderedAssertions())
{
A.CallTo(() => setUser.Use(A<ValueSet>.That.IsEqualTo(values))).MustHaveHappened(Repeated.Exactly.Once);
A.CallTo(() => setUser.Use(A<ValueSet>.That.Matches(set =>
set.Count == 2 && set.Contains(1)))).MustHaveHappened(Repeated.Exactly.Once);
}
}
}
}
public class SetUser
{
public virtual void Use(ValueSet set)
{
}
}
class ClassUnderTest
{
public static void Main(string[] arguments)
{
}
public void RunWith(SetUser setUser)
{
var values = new ValueSet { 1, 2, 3 };
setUser.Use(values);
values.Remove(3);
setUser.Use(values);
}
}
}
I get the following error output:
FakeItEasy.ExpectationException: Assertion failed for the following call: SetTest.SetUser.Use(1[System.UInt32]>) Expected to find it exactly once but found it #0 times among the calls:
1. SetTest.SetUser.Use(set: System.Collection.Generic.HashSet1[System.UInt32]) repeated 2 times
I don't understand what is causing this failure and how to fix it.
What is needed to get this type of test to pass?
#Tim Long is on the right track in his comment.
Here's a little more detail, as well as updates to respond to your comments of 2014-08-11 03:25:56:
The first reason the first MustHaveHappened fails:
According to the FakeItEasy argument constraints documentation, That.IsEqualTo tests for "object equality using object.Equals". That's what's causing the unexpected behaviour.
Not passing values into the method isn't necessarily a problem, or wouldn't be if ValueSet.Equals performed a value comparison, but ValueSet is a HashSet<uint>, so you can see from that class's method documentation that it doesn't—it uses object.Equals, which tests for reference equality. Thus, your IsEqualTo assertion fails. If you use a more sophisticated matcher that performed a value-type comparison for HashSet, perhaps something closer to what you use in your second A.CallTo, or maybe something using That.Contains, I think you'll have better success.
You may think to use That.IsSameSequenceAs, but be careful if doing so: the HashSet doesn't guarantee the order of the elements in the enumeration, so even if the set has the same elements, you may get a failure.
The second reason the first MustHaveHappened fails:
RunWith changes the contents of the values set between calls to setUser.Use. So the same set is used in two calls, first with 3 elements, then when it has only 2 elements. This means that by the time the first MustHaveHappened call is made, the set has only 2 elements, so the comparison fails. You could see this more clearly by writing an argument formatter for the ValueSet. That would provide more information.
The cause of the mismatch is that when a call is made to a faked method, FakeItEasy captures the arguments. However, for reference types, such as ValueSet (HashSet), only the reference to the argument is kept. Thus, if the object is modified later, in particular between the execution and the verification stages of the test, the object will look different than it did at the time of the faked call. See #jimmy_keen's answer to MustHaveHappened fails when called twice on the same object. There's a little more discussion over at FakeItEasy Issue 306 - Verifying multiple method calls with reference parameters.
In this case, the usual approach is to do as he suggests—provide code to capture the important state of the incoming argument at call time, and then query that saved state later.
You might be able to use something like this:
[Test]
public void CallsUsersWithSetAndReducedSet()
{
var capturedValueSets = new List<List<uint>>();
var setUser = A.Fake<SetUser>();
A.CallTo(() => setUser.Use(A<ValueSet>._)) // matches any call to setUser.Use
.Invokes((ValueSet theSet) => capturedValueSets.Add(theSet.ToList()));
ClassUnderTest testInstance = new ClassUnderTest();
testInstance.RunWith(setUser);
Assert.That(capturedValueSets, Has.Count.EqualTo(2),
"not enough calls to setUser.Use");
Assert.That(capturedValueSets[0], Is.EquivalentTo(new uint[] {1, 2, 3}),
"bad set passed to first call to setUser.Use");
Assert.That(capturedValueSets[1], Has.Count.EqualTo(2) & Has.Member(1),
"bad set passed to second call to setUser.Use");
}
You can see that each time Use is called, we add the contents of the ValueSet argument to capturedValueSets. Then at the end we
make sure 2 calls were made, by checking the length of capturedValueSets
make sure that the first time Use was called, the set had the elements 1, 2, and 3. Is.EquivalentTo checks the two lists but ignores order
make sure that the second time Use was called, the set had 2 elements, one of which was 1
By checking the two captured value sets in turn, all the bits about the scopes and ordered assertions became unnecessary.