Skip to content

Commit e48577b

Browse files
committed
Initial FML support ...
1 parent bc10d4a commit e48577b

File tree

2 files changed

+101
-4
lines changed

2 files changed

+101
-4
lines changed

pyit2fls/FML.py

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,104 @@
11
import xml.etree.ElementTree as ET
2-
from pyit2fls import (T1Mamdani, T1TSK, )
2+
from numpy import (linspace, )
3+
from pyit2fls import (T1Mamdani, T1TSK, T1FS, tri_mf, ltri_mf, rtri_mf, trapezoid_mf, gaussian_mf, singleton_mf, )
34

45
class FML:
56

67
def __init__(self, ):
78
pass
89

910
def generate(self, variables, rules):
11+
"""
12+
Generates a Type-1 Fuzzy Logic System (Mamdani or TSK) based on
13+
parsed variables and rules.
14+
"""
15+
# Mapping FML membership function shapes to pyit2fls functions
16+
MF_MAP = {
17+
"triangularShape": tri_mf,
18+
"trapezoidalShape": trapezoid_mf,
19+
"gaussianShape": gaussian_mf,
20+
"singletonShape": singleton_mf,
21+
}
22+
23+
# Initialize the system based on the rule base type
1024
if rules["type"] == "mamdani":
1125
sys = T1Mamdani()
1226
elif rules["type"] == "takagi-sugeno":
1327
sys = T1TSK()
1428
else:
15-
raise ValueError(f"Unknown system type: {rules["type"]}")
29+
raise ValueError(f"Unknown system type: {rules['type']}")
30+
31+
# Cache to store created T1FS objects or TSK coefficients
32+
# Structure: {variable_name: {term_name: T1FS_or_coeff_dict}}
33+
sets_cache = {}
34+
35+
# 1. Process Input and Output Variables
36+
for var_type in ["input", "output"]:
37+
for var_name, var_info in variables[var_type].items():
38+
if var_type == "input":
39+
sys.add_input_variable(var_name)
40+
else:
41+
sys.add_output_variable(var_name)
42+
43+
sets_cache[var_name] = {}
44+
45+
# Define the universe of discourse (domain) for T1FS
46+
domain = linspace(var_info["domainleft"], var_info["domainright"], 100)
47+
48+
for term_name, term_info in var_info["terms"].items():
49+
mf_type = term_info["set"]
50+
params = [float(p) for p in term_info["params"]]
51+
52+
# For all inputs and Mamdani outputs, we create T1FS objects
53+
if rules["type"] == "mamdani" or var_type == "input":
54+
# pyit2fls membership functions require a height parameter (params[-1])
55+
# FML defaults to 1.0 if not specified
56+
if mf_type == "triangularShape" and len(params) == 3:
57+
params.append(1.0)
58+
elif mf_type == "trapezoidalShape" and len(params) == 4:
59+
params.append(1.0)
60+
elif mf_type == "gaussianShape" and len(params) == 2:
61+
params.append(1.0)
62+
elif mf_type == "singletonShape" and len(params) == 1:
63+
params.append(1.0)
64+
65+
sets_cache[var_name][term_name] = T1FS(domain, MF_MAP[mf_type], params)
66+
67+
if term_info["complement"] == "true":
68+
sets_cache[var_name][term_name] = - sets_cache[var_name][term_name]
69+
70+
# For TSK outputs, we store coefficient dictionaries
71+
else:
72+
if mf_type == "singletonShape":
73+
sets_cache[var_name][term_name] = {"const": float(params[0])}
74+
# Initialize other input coefficients to 0 for linear TSK
75+
for inp in variables["input"]:
76+
sets_cache[var_name][term_name][inp] = 0.0
77+
else:
78+
# Default to 0 constant if shape is not a singleton
79+
sets_cache[var_name][term_name] = {"const": 0.0}
80+
81+
# 2. Add Rules to the System
82+
# Iterate through the rules dictionary populated by parse_fml
83+
rule_data = rules["rules"]
84+
if isinstance(rule_data, dict):
85+
rule_data = rule_data.values()
86+
87+
for rule in rule_data:
88+
# Construct antecedent: list of (var_name, T1FS)
89+
antecedent = []
90+
for var_name, term_name in rule["antecedent"]:
91+
antecedent.append((var_name, sets_cache[var_name][term_name]))
92+
93+
# Construct consequent: list of (var_name, T1FS) or (var_name, coeff_dict)
94+
consequent = []
95+
for var_name, term_name in rule["consequent"]:
96+
consequent.append((var_name, sets_cache[var_name][term_name]))
97+
98+
sys.add_rule(antecedent, consequent)
99+
100+
return sys
101+
16102

17103
def parse_fml(self, fml_xml_string):
18104
"""
@@ -178,6 +264,7 @@ def parse_fml(self, fml_xml_string):
178264
myFML = FML()
179265
result = myFML.parse_fml(FML_STRING)
180266
print(result)
267+
FS = myFML.generate(result[1], result[2])
181268

182269

183270

pyit2fls/pyit2fls.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,18 @@ def tri_mf(x, params):
144144
>>> x = linspace(0, 1, 201)
145145
>>> membership_value = tri_mf(x, [0.1, 0.3, 0.5, 1])
146146
"""
147-
return minimum(1, maximum(0, ((params[3] * (x - params[0]) / (params[1] - params[0])) * (x <= params[1]) + \
148-
((params[3] * ((params[2] - x) / (params[2] - params[1]))) * (x > params[1]))) ))
147+
# params[1] = max(params[0], params[1])
148+
# params[2] = max(params[1], params[2])
149+
150+
if params[0] == params[1]:
151+
return minimum(1, maximum(0, (0 * (x <= params[1]) + \
152+
((params[3] * ((params[2] - x) / (params[2] - params[1]))) * (x > params[1]))) ))
153+
elif params[1] == params[2]:
154+
return minimum(1, maximum(0, ((params[3] * (x - params[0]) / (params[1] - params[0])) * (x <= params[1]) + \
155+
(0 * (x > params[1]))) ))
156+
else:
157+
return minimum(1, maximum(0, ((params[3] * (x - params[0]) / (params[1] - params[0])) * (x <= params[1]) + \
158+
((params[3] * ((params[2] - x) / (params[2] - params[1]))) * (x > params[1]))) ))
149159

150160

151161
def rtri_mf(x, params):

0 commit comments

Comments
 (0)