New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for linked facts that span multiple activations and multiple rules #255
Comments
Linked facts (those produced by the public class TransitiveClosureRule : Rule
{
public override void Define()
{
// If a ⊑ b && b ⊑ c, then a ⊑ c
SubTypeConstraint sub1 = default!;
SubTypeConstraint sub2 = default!;
When()
.Match<SubTypeConstraint>(() => sub1)
.Match<SubTypeConstraint>(() => sub2, s => sub1.SuperType == s.SubType);
Then()
.Yield(c => CreateConstraint(sub1, sub2));
}
private static SubTypeConstraint CreateConstraint(SubTypeConstraint sub1, SubTypeConstraint sub2)
{
var derivedConstraint = new SubTypeConstraint(sub1.SubType, sub2.SuperType);
Console.WriteLine($"{sub1} && {sub2} -> {derivedConstraint}");
return derivedConstraint;
}
} And it prints the following:
Here you can clearly see that two different matches of the rule yield the same output. NRules does not natively support producing the same linked fact from multiple activations of the same rule or from different rules. It would need to do some sort of reference counting to support that. I think this is a good feature to support, so I'll keep this issue open, such that I can add this capability in the future. As a workaround, you can use two rules and an intermediary fact: public class CalculatedConstraint
{
public TypeVariable SubType { get; }
public TypeVariable SuperType { get; }
public CalculatedConstraint(TypeVariable subType, TypeVariable superType)
{
SubType = subType;
SuperType = superType;
}
}
public class TransitiveClosureCalculationRule : Rule
{
public override void Define()
{
// If a ⊑ b && b ⊑ c, then a ⊑ c
SubTypeConstraint sub1 = default!;
SubTypeConstraint sub2 = default!;
When()
.Match<SubTypeConstraint>(() => sub1)
.Match<SubTypeConstraint>(() => sub2, s => sub1.SuperType == s.SubType);
Then()
.Yield(c => new CalculatedConstraint(sub1.SubType, sub2.SuperType));
}
}
public class TransitiveClosureYieldRule : Rule
{
public override void Define()
{
IEnumerable<CalculatedConstraint> constraints = default!;
When()
.Query(() => constraints, q => q
.Match<CalculatedConstraint>()
.GroupBy(x => new {x.SubType, x.SuperType}));
Then()
.Yield(c => new SubTypeConstraint(constraints.First().SubType, constraints.First().SuperType));
}
} |
I'm trying to implement a rule that is to generate the transitive closure of a relation. I have the following fact class:
and a rule that expresses transitivity:
The idea is that if two
SubTypeContstraint
s are found that march the transitive relation, then a new fact should be yielded and added to the knowledge base. When I run this query:I get the following exception:
How can I generate the transitive closure of my relation using the rule? Do I explicitly have to check that a fact doesn't exist before Yielding it?
The text was updated successfully, but these errors were encountered: