Skip to content
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

Fact can only be modified once based on the fact name #17

Open
cdemulde opened this issue Dec 6, 2019 · 4 comments · May be fixed by #18
Open

Fact can only be modified once based on the fact name #17

cdemulde opened this issue Dec 6, 2019 · 4 comments · May be fixed by #18
Assignees
Labels
question Further information is requested

Comments

@cdemulde
Copy link

cdemulde commented Dec 6, 2019

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 founderror, 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).

@cdemulde cdemulde linked a pull request Dec 6, 2019 that will close this issue
@nilp0inter
Copy link
Owner

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?

@cdemulde
Copy link
Author

cdemulde commented Dec 12, 2019

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).

@nilp0inter
Copy link
Owner

nilp0inter commented Dec 17, 2019

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()

@nilp0inter nilp0inter added the question Further information is requested label Dec 17, 2019
@nilp0inter nilp0inter self-assigned this Dec 17, 2019
@cdemulde
Copy link
Author

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants