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

Got a AttributeError: 'Rule' object has no attribute '__name__' #39

Open
wangyingsm opened this issue Nov 8, 2018 · 2 comments
Open

Comments

@wangyingsm
Copy link

wangyingsm commented Nov 8, 2018

Background, I am new to Pyknow. I want to build a expert system to auto calculate a cell quality score based on some parameters. The score algorithm should be loaded from a json data, such like:

	{
		"PN": [{
			"condition": "pn",
			"symbol": "=",
			"value": "2PN",
			"score": "20",
			"weight": "1.0"
		}, {
			"condition": "time",
			"symbol": "<=",
			"value": "12",
			"score": "20",
			"weight": "1.0"
		}],
		"4C": [{
			"condition": "cell",
			"symbol": "=",
			"value": "4C",
			"score": "20",
			"weight": "1.0"
		}, {
			"condition": "even",
			"symbol": "=",
			"value": true,
			"score": "20",
			"weight": "1.0"
		}, {
			"condition": "fragment",
			"symbol": "=",
			"value": "<5%",
			"score": "20",
			"weight": "1.0"
		}, {
			"condition": "fragment",
			"symbol": "=",
			"value": "5%-10%",
			"score": "15",
			"weight": "1.0"
		}, {
			"condition": "fragment",
			"symbol": "=",
			"value": "10%-20%",
			"score": "10",
			"weight": "1.0"
		}, {
			"condition": "time",
			"symbol": "<=",
			"value": "36",
			"score": "20",
			"weight": "1.0"
		}]
	}

Here are my codes for this,

	from pyknow import *
	from functools import partial

	class EmbryoScore(KnowledgeEngine):
	    score = 0
	    @classmethod
	    def removeAllRules(cls):
	        for m in [attr for attr in cls.__dict__ if attr.startswith('rule')]:
	            delattr(cls, m)

	def parse_json_rules(rule_json):
	    import json
	    rules = json.loads(rule_json)
	    sal = 100
	    index = 0
	    for stage in rules:
	        for rule_item in rules[stage]:
	            rule = {'condition': rule_item['condition']}
	            rule['stage'] = stage
	            if rule_item['symbol'] not in ('=', '<', '<=', '>', '>='):
	                continue
	            def _cond(value, symbol):
	                if symbol == '=': return EQ(value)
	                if symbol == '<': return LT(value)
	                if symbol == '<=': return LE(value)
	                if symbol == '>': return GT(value)
	                if symbol == '>=': return GE(value)

	            def _add(self, **kwargs):
	                if 'score' not in kwargs or 'weight' not in kwargs:
	                    raise ValueError('No score or weight specified')
	                s, w = int(kwargs['score']), float(kwargs['weight'])
	                self.score += s * w
	        
	            R = Rule(AND(Fact(**rule, value=MATCH.value & 
                        _cond(rule_item['value'], rule_item['symbol']))),
	                    salience=sal)(partial(_add, score=rule_item['score'], 
                        weight=rule_item['weight']))
	            setattr(EmbryoScore, f'rule{index}', R)
	            index += 1
	            sal -= 1

	def init_engine(rule_json):
	    EmbryoScore.removeAllRules()
	    parse_json_rules(rule_json)
	    engine = EmbryoScore()
	    engine.reset()
	    return engine

	import unittest

	class ScoreTest(unittest.TestCase):
		def test(self):
			engine = init_engine(rule_json)
			engine.declare(Fact(condition='pn', stage='PN', value='2PN'))
			engine.declare(Fact(stage='4C', condition='cell', value='4C'))
			engine.declare(Fact(stage='4C', condition='fragment', value='10%-20%'))
			engine.declare(Fact(stage='4C', condition='time', value='32'))
			engine.run()
			self.assertEqual(engine.score, 70)


	if __name__ == '__main__':
	    unittest.main()

It raises a AttributeError: 'Rule' object has no attribute 'name' when engine.run() on engine.py line 162

	watchers.RULES.info(
         "FIRE %s %s: %s",
         execution,
         activation.rule.__name__,
         ", ".join(str(f) for f in activation.facts))

I can't find out what the problem is. Wonder if I can get some help here. THANKS.

@nilp0inter
Copy link
Contributor

Hi,

the error you are receiving is due to the usage of partial functions in the RHS of the rule.

You can solve this using a closure instead of a partial function:

            def _add_partial(score, weight):
                def _add(self, **kwargs):
                    s, w = int(score), float(weight)
                    self.score += s * w
                return _add

            R = Rule(AND(Fact(**rule, value=MATCH.value & 
                    _cond(rule_item['value'], rule_item['symbol']))),
                    salience=sal)(_add_partial(score=rule_item['score'], 
                                               weight=rule_item['weight']))

Hope this help!

@wangyingsm
Copy link
Author

Hi,

the error you are receiving is due to the usage of partial functions in the RHS of the rule.

You can solve this using a closure instead of a partial function:

            def _add_partial(score, weight):
                def _add(self, **kwargs):
                    s, w = int(score), float(weight)
                    self.score += s * w
                return _add

            R = Rule(AND(Fact(**rule, value=MATCH.value & 
                    _cond(rule_item['value'], rule_item['symbol']))),
                    salience=sal)(_add_partial(score=rule_item['score'], 
                                               weight=rule_item['weight']))

Hope this help!

Wow. It DOES WORK.
THANKS.

wangyingsm added a commit to EmbryoAI/EmbryoAI-System that referenced this issue Nov 9, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants