Skip to content

Commit 5511b87

Browse files
committed
Extending support to linguistic terms in singletons and introducing support for templated replacements in functions
1 parent 311b3bc commit 5511b87

File tree

2 files changed

+99
-1
lines changed

2 files changed

+99
-1
lines changed

simpful/rule_parsing.py

+4
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,16 @@ def postparse(STRINGA, verbose=False):
8787
raise Exception("ERROR: badly formatted rule, please check capitalization and syntax.\n"
8888
+ " ---- PROBLEMATIC RULE:\n"
8989
+ STRINGA)
90+
91+
9092
# Probabilistic fuzzy rule
9193
if re.match(r"P\(", stripped) is not None:
9294
return tuple(re.findall(r"\w+(?=\sis)|(?<=is\s)\w+|\d\.\d\d", stripped))
95+
9396
# Weighted fuzzy rule
9497
elif re.search(r"WEIGHT\s*(\d|\.)", stripped) is not None:
9598
return tuple(re.findall(r"\w+(?=\sIS\s)|(?<=\sIS\s)\w+|\.?\d\.?\d*", stripped))
99+
96100
# Normal fuzzy rule
97101
else:
98102
return tuple(re.findall(r"\w+(?=\sIS\s)|(?<=\sIS\s)\w+", stripped))

simpful/simpful.py

+95-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
# for sanitization
2424
valid_characters = string.ascii_letters + string.digits + "()_ "
2525

26+
# constants for templating system
27+
TEMPLATES_ENGAGED = 0
28+
TEMPLATES_DISENGAGED = 1
29+
TEMPLATES_MISSING_INFO = 2
2630

2731
class UndefinedUniverseOfDiscourseError(Exception):
2832

@@ -275,6 +279,9 @@ def __init__(self, operators=None, show_banner=True, sanitize_input=False, verbo
275279

276280
self._detected_type = None
277281

282+
self._replacement_dictionary = {}
283+
self._templates_enabled = False
284+
278285
self._sanitize_input = sanitize_input
279286
if sanitize_input and verbose:
280287
print (" * Warning: Simpful rules sanitization is enabled, please pay attention to possible collisions of symbols.")
@@ -308,6 +315,7 @@ def get_fuzzy_sets(self, variable_name):
308315
except ValueError:
309316
raise Exception("ERROR: linguistic variable %s does not exist" % variable_name)
310317

318+
311319
def get_fuzzy_set(self, variable_name, fs_name):
312320
"""
313321
Returns a FuzzySet object associated to a linguistic variable.
@@ -341,12 +349,14 @@ def set_variable(self, name, value, verbose=False):
341349
"""
342350
if self._sanitize_input: name = self._sanitize(name)
343351
try:
344-
value = float(value)
352+
if type(value)==int:
353+
value = float(value)
345354
self._variables[name] = value
346355
if verbose: print(" * Variable %s set to %f" % (name, value))
347356
except ValueError:
348357
raise Exception("ERROR: specified value for "+name+" is not an integer or float: "+value)
349358

359+
350360
def set_constant(self, name, value, verbose=False):
351361
"""
352362
Sets the numerical value of a linguistic variable to a constant value (i.e. ignore fuzzy inference).
@@ -365,6 +375,33 @@ def set_constant(self, name, value, verbose=False):
365375
except ValueError:
366376
raise Exception("ERROR: specified value for "+name+" is not an integer or float: "+value)
367377

378+
379+
def set_input_templates(self, replacement_dictionary={}):
380+
"""
381+
Sets the current status of categorical values using a template system. The replacement
382+
rules are specified as a dictionary. EXPERIMENTAL.
383+
"""
384+
self._replacement_dictionary = replacement_dictionary
385+
if self._check_templates() == TEMPLATES_ENGAGED:
386+
print( " * Templates replacement set to:", self._replacement_dictionary)
387+
else:
388+
print( "WARNING: templates replacement set but no templates were found in the functions")
389+
390+
391+
def _check_templates(self):
392+
# replacement dictionary filled and templates used in functions
393+
if len(self._replacement_dictionary)>0 and self._templates_enabled:
394+
return TEMPLATES_ENGAGED
395+
396+
# no replacement set but templates are used in functions (not good)
397+
elif len(self._replacement_dictionary)==0 and self._templates_enabled:
398+
return TEMPLATES_MISSING_INFO
399+
else:
400+
401+
# replacement not set or templates are disabled
402+
return TEMPLATES_DISENGAGED
403+
404+
368405
def add_rules_from_file(self, path, verbose=False):
369406
"""
370407
Imports new fuzzy rules by reading the strings from a text file.
@@ -407,6 +444,7 @@ def add_rules(self, rules, verbose=False):
407444
print()
408445
if verbose: print(" * %d rules successfully added" % len(rules))
409446

447+
410448
def get_rules(self):
411449
"""
412450
Returns the rule base of the fuzzy system.
@@ -430,6 +468,7 @@ def get_rules(self):
430468

431469
return rule_base
432470

471+
433472
def replace_rule(self, i, new_rule, verbose=False):
434473
"""
435474
Replaces the i-th rule in the FuzzySystem object. Rules are stored in the same order they were added.
@@ -498,9 +537,15 @@ def set_output_function(self, name, function, verbose=False):
498537
"""
499538
if self._sanitize_input: name = self._sanitize(name)
500539
self._outputfunctions[name]=function
540+
if "{" in function:
541+
self._templates_enabled = True
542+
if verbose:
543+
print(" * Template system engaged")
544+
501545
if verbose: print(" * Output function for '%s' set to '%s'" % (name, function))
502546
self._set_model_type("Sugeno")
503547

548+
504549
def _set_model_type(self, model_type):
505550
if self._detected_type == "inconsistent": return
506551
if self._detected_type is None:
@@ -535,6 +580,43 @@ def get_firing_strengths(self, input_values=None):
535580
firings.append(res)
536581
return firings
537582

583+
584+
def _replace_values(self, function, verbose=False):
585+
res_string=function[:]
586+
newstring = ""
587+
while "{" in res_string:
588+
589+
try:
590+
prestring = res_string[:res_string.find("{")]
591+
substring = res_string[res_string.find("{")+1:res_string.find("}")]
592+
if verbose: print("Pre- and sub-strings:", prestring, substring)
593+
except:
594+
print("ERROR: missing curly brace in template, aborting.")
595+
exit()
596+
597+
variable = substring[2: substring.find("IS")].strip()
598+
case = substring[substring.find("IS")+2:substring.find("THEN")].strip()
599+
value = substring[substring.find("THEN")+4:].strip()
600+
if verbose: print("Analysing rule: IF %s IS %s THEN %s" % (variable, case, value))
601+
602+
# checking everything all the time is not a good idea, optimize later
603+
detected = False
604+
for k,v in self._replacement_dictionary.items():
605+
if k==variable and v==case:
606+
if verbose: print(" - case detected for", k,v)
607+
newstring = newstring+prestring+ str(value)
608+
res_string = res_string[res_string.find("}")+1:]
609+
detected = True
610+
611+
if detected: continue
612+
613+
res_string = res_string[res_string.find("}")+1:]
614+
newstring += prestring + "0"
615+
616+
newstring += res_string
617+
return newstring
618+
619+
538620
def mediate(self, outputs, antecedent, results, ignore_errors=False, ignore_warnings=False, verbose=False):
539621

540622
final_result = {}
@@ -543,10 +625,12 @@ def mediate(self, outputs, antecedent, results, ignore_errors=False, ignore_warn
543625
list_output_funs = [x[0] for x in self._outputfunctions.items()]
544626

545627
for output in outputs:
628+
"""
546629
if verbose:
547630
print(" * Processing output for variable '%s'" % output)
548631
print(" whose universe of discourse is:", self._lvs[output].get_universe_of_discourse())
549632
print(" contains the following fuzzy sets:", self._lvs[output]._FSlist )
633+
"""
550634

551635
num = 0
552636
den = 0
@@ -575,6 +659,16 @@ def mediate(self, outputs, antecedent, results, ignore_errors=False, ignore_warn
575659
raise Exception("ERROR in consequent of rule %s.\nSugeno reasoning does not support output fuzzy sets." % ("IF " + str(ant) + " THEN " + str(res)))
576660
else:
577661
string_to_evaluate = self._outputfunctions[outterm]
662+
663+
# replacement here
664+
if self._check_templates() == TEMPLATES_ENGAGED:
665+
print(" * Replacing templates in function for '%s'" % res[0])
666+
print(" name of function: '%s'" % res[1])
667+
string_to_evaluate = self._replace_values(string_to_evaluate)
668+
print(" * Final version of the '%s' rule: %s" % (res[1], string_to_evaluate))
669+
#exit()
670+
671+
578672
for k,v in self._variables.items():
579673
# old version
580674
# string_to_evaluate = string_to_evaluate.replace(k,str(v))

0 commit comments

Comments
 (0)