23
23
# for sanitization
24
24
valid_characters = string .ascii_letters + string .digits + "()_ "
25
25
26
+ # constants for templating system
27
+ TEMPLATES_ENGAGED = 0
28
+ TEMPLATES_DISENGAGED = 1
29
+ TEMPLATES_MISSING_INFO = 2
26
30
27
31
class UndefinedUniverseOfDiscourseError (Exception ):
28
32
@@ -275,6 +279,9 @@ def __init__(self, operators=None, show_banner=True, sanitize_input=False, verbo
275
279
276
280
self ._detected_type = None
277
281
282
+ self ._replacement_dictionary = {}
283
+ self ._templates_enabled = False
284
+
278
285
self ._sanitize_input = sanitize_input
279
286
if sanitize_input and verbose :
280
287
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):
308
315
except ValueError :
309
316
raise Exception ("ERROR: linguistic variable %s does not exist" % variable_name )
310
317
318
+
311
319
def get_fuzzy_set (self , variable_name , fs_name ):
312
320
"""
313
321
Returns a FuzzySet object associated to a linguistic variable.
@@ -341,12 +349,14 @@ def set_variable(self, name, value, verbose=False):
341
349
"""
342
350
if self ._sanitize_input : name = self ._sanitize (name )
343
351
try :
344
- value = float (value )
352
+ if type (value )== int :
353
+ value = float (value )
345
354
self ._variables [name ] = value
346
355
if verbose : print (" * Variable %s set to %f" % (name , value ))
347
356
except ValueError :
348
357
raise Exception ("ERROR: specified value for " + name + " is not an integer or float: " + value )
349
358
359
+
350
360
def set_constant (self , name , value , verbose = False ):
351
361
"""
352
362
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):
365
375
except ValueError :
366
376
raise Exception ("ERROR: specified value for " + name + " is not an integer or float: " + value )
367
377
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
+
368
405
def add_rules_from_file (self , path , verbose = False ):
369
406
"""
370
407
Imports new fuzzy rules by reading the strings from a text file.
@@ -407,6 +444,7 @@ def add_rules(self, rules, verbose=False):
407
444
print ()
408
445
if verbose : print (" * %d rules successfully added" % len (rules ))
409
446
447
+
410
448
def get_rules (self ):
411
449
"""
412
450
Returns the rule base of the fuzzy system.
@@ -430,6 +468,7 @@ def get_rules(self):
430
468
431
469
return rule_base
432
470
471
+
433
472
def replace_rule (self , i , new_rule , verbose = False ):
434
473
"""
435
474
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):
498
537
"""
499
538
if self ._sanitize_input : name = self ._sanitize (name )
500
539
self ._outputfunctions [name ]= function
540
+ if "{" in function :
541
+ self ._templates_enabled = True
542
+ if verbose :
543
+ print (" * Template system engaged" )
544
+
501
545
if verbose : print (" * Output function for '%s' set to '%s'" % (name , function ))
502
546
self ._set_model_type ("Sugeno" )
503
547
548
+
504
549
def _set_model_type (self , model_type ):
505
550
if self ._detected_type == "inconsistent" : return
506
551
if self ._detected_type is None :
@@ -535,6 +580,43 @@ def get_firing_strengths(self, input_values=None):
535
580
firings .append (res )
536
581
return firings
537
582
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
+
538
620
def mediate (self , outputs , antecedent , results , ignore_errors = False , ignore_warnings = False , verbose = False ):
539
621
540
622
final_result = {}
@@ -543,10 +625,12 @@ def mediate(self, outputs, antecedent, results, ignore_errors=False, ignore_warn
543
625
list_output_funs = [x [0 ] for x in self ._outputfunctions .items ()]
544
626
545
627
for output in outputs :
628
+ """
546
629
if verbose:
547
630
print(" * Processing output for variable '%s'" % output)
548
631
print(" whose universe of discourse is:", self._lvs[output].get_universe_of_discourse())
549
632
print(" contains the following fuzzy sets:", self._lvs[output]._FSlist )
633
+ """
550
634
551
635
num = 0
552
636
den = 0
@@ -575,6 +659,16 @@ def mediate(self, outputs, antecedent, results, ignore_errors=False, ignore_warn
575
659
raise Exception ("ERROR in consequent of rule %s.\n Sugeno reasoning does not support output fuzzy sets." % ("IF " + str (ant ) + " THEN " + str (res )))
576
660
else :
577
661
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
+
578
672
for k ,v in self ._variables .items ():
579
673
# old version
580
674
# string_to_evaluate = string_to_evaluate.replace(k,str(v))
0 commit comments