experta
experta copied to clipboard
Fact can only be modified once based on the fact name
Hi,
I would like for my rule engine to run, save some values and then use those values, after the run, to modify some facts. For background: I want to run the engine 'dynamically': for each time step, I am running the engine, it provides a result, and based on that my facts change for the next time instance (the next run).
A minimal working example (without any relevant facts and rules):
import experta as exp
class Fact_1(exp.Fact):
value_1 = exp.Field(int)
class Fact_2(exp.Fact):
value_2 = exp.Field(int)
class Rules(exp.KnowledgeEngine):
@exp.Rule(Fact_1(value_1 = exp.MATCH.v1),
Fact_2(value_2 = exp.MATCH.v2))
def subtract(self, v1, v2):
return v1-v2
engine = Rules()
fact_1 = Fact_1(value_1 = 1)
fact_2 = Fact_2(value_2 = 3)
engine.reset()
engine.declare(fact_1)
engine.declare(fact_2)
engine.run()
engine.modify(fact_1)
engine.run()
engine.modify(fact_1)
This yields a Fact not found
error, I think because any time a fact is modified, it moves to the end of the fact list (engine.facts), while it is the number in this list that is used for the next modification.
I am new to working with rule-engines, so this might be a very specific problem that only I am facing, but I still have the feeling this might be a useful thing to have (i.e. repeated modification of facts by use of their name).
The facts that you can use with modify
are the ones returned by declare
or the ones received in a rule as parameters. In your example:
engine = Rules()
fact_1 = Fact_1(value_1 = 1)
fact_2 = Fact_2(value_2 = 3)
engine.reset()
declared_1 = engine.declare(fact_1)
declared_2 = engine.declare(fact_2)
engine.run()
engine.modify(declared_1, value_1=5)
engine.modify(declared_2, value_2=3)
engine.run()
This is due to the fact that you can instantiate a fact and use it with multiple engines at the same time or be modified in an unsafe manner by the user. To avoid data corruption, when you declare a fact an immutable copy is made and managed by the engine.
Do this solve your problem?
Hi,
I did not actually, at least not for the test case. I noticed that in your answer, you modify declared_1
and declared_2
, while what I would like to be able to do is modify declared_1
twice, with an engine run in between. And that still throws the same error (except when I use the fix I proposed earlier).
In that case what you need to do is to store the fact returned by modify
, this is an example:
import experta as exp
class Fact_1(exp.Fact):
value_1 = exp.Field(int)
class Fact_2(exp.Fact):
value_2 = exp.Field(int)
class Rules(exp.KnowledgeEngine):
@exp.Rule(Fact_1(value_1 = exp.MATCH.v1),
Fact_2(value_2 = exp.MATCH.v2))
def subtract(self, v1, v2):
print(v1-v2)
engine = Rules()
fact_1 = Fact_1(value_1 = 1)
fact_2 = Fact_2(value_2 = 3)
engine.reset()
f1 = engine.declare(fact_1)
f2 = engine.declare(fact_2)
engine.run()
f1_1 = engine.modify(f1, value_1=3)
engine.run()
f1_2 = engine.modify(f1_1, value_1=8)
engine.run()
Aha, that does the trick indeed, for the working example at least. For the time being, I'll keep working with the fix I proposed though. Somehow, I think it does make more sense to update a fact and leave it in place, i.e. with the same fact number and everything.
Thank you for your answers!