|
1 | 1 | 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, ) |
3 | 4 |
|
4 | 5 | class FML: |
5 | 6 |
|
6 | 7 | def __init__(self, ): |
7 | 8 | pass |
8 | 9 |
|
9 | 10 | 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 |
10 | 24 | if rules["type"] == "mamdani": |
11 | 25 | sys = T1Mamdani() |
12 | 26 | elif rules["type"] == "takagi-sugeno": |
13 | 27 | sys = T1TSK() |
14 | 28 | 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 | + |
16 | 102 |
|
17 | 103 | def parse_fml(self, fml_xml_string): |
18 | 104 | """ |
@@ -178,6 +264,7 @@ def parse_fml(self, fml_xml_string): |
178 | 264 | myFML = FML() |
179 | 265 | result = myFML.parse_fml(FML_STRING) |
180 | 266 | print(result) |
| 267 | + FS = myFML.generate(result[1], result[2]) |
181 | 268 |
|
182 | 269 |
|
183 | 270 |
|
|
0 commit comments