def test_range(self) -> None: self.assertEqual((1.0, 1.0), fl.FllImporter().range("1.0000 1.0000")) self.assertEqual((-fl.inf, fl.inf), fl.FllImporter().range("-inf\tinf")) self.assertEqual(str((fl.nan, fl.nan)), str(fl.FllImporter().range("-nan nan"))) with self.assertRaisesRegex(SyntaxError, re.escape( "expected range of two values, but got ['1', '2', '3']")): fl.FllImporter().range("1 2 3")
def test_invalid_components(self) -> None: with self.assertRaisesRegex( SyntaxError, re.escape("'invalid' is not a valid component of 'Engine'")): fl.FllImporter().engine("""Engine: name\n invalid: component""") with self.assertRaisesRegex( SyntaxError, re.escape( "'invalid' is not a valid component of 'InputVariable'")): fl.FllImporter().input_variable( """InputVariable: name\n invalid: component""") with self.assertRaisesRegex( SyntaxError, re.escape( "'invalid' is not a valid component of 'OutputVariable'")): fl.FllImporter().output_variable( """OutputVariable: name\n invalid: component""") with self.assertRaisesRegex( SyntaxError, re.escape( "'invalid' is not a valid component of 'RuleBlock'")): fl.FllImporter().rule_block( """RuleBlock: name\n invalid: component""") with self.assertRaisesRegex( SyntaxError, re.escape( "factory manager does not contain a factory named 'variable' " "to construct objects of type '<class 'fuzzylite.variable.Variable'>'" )): fl.FllImporter().component(fl.Variable, """Variable: Invalid""") # type: ignore
def test_rule(self) -> None: rule = "rule: if obstacle is left then steer is right" self.assertEqual(rule, str(fl.FllImporter().rule(rule))) self.assertFalse(cast(fl.Rule, fl.FllImporter().rule(rule)).is_loaded()) engine = fl.FllImporter().from_string(BELL_FLL) self.assertEqual(rule, str(fl.FllImporter().rule(rule, engine))) self.assertTrue(cast(fl.Rule, fl.FllImporter().rule(rule, engine)).is_loaded())
def test_snorm(self) -> None: snorm = "AlgebraicSum" self.assertEqual(snorm, str(fl.FllImporter().snorm(snorm))) self.assertEqual(None, fl.FllImporter().snorm("")) self.assertEqual(None, fl.FllImporter().snorm("none")) with self.assertRaisesRegex(ValueError, re.escape( "constructor of 'AlgebraicProduct' not found in SNormFactory")): fl.FllImporter().snorm("AlgebraicProduct")
def test_defuzzifier(self) -> None: defuzzifier = "Centroid" self.assertEqual(defuzzifier + " 100", str(fl.FllImporter().defuzzifier(defuzzifier))) defuzzifier = "WeightedAverage TakagiSugeno" self.assertEqual(defuzzifier, str(fl.FllImporter().defuzzifier(defuzzifier))) self.assertEqual(None, fl.FllImporter().defuzzifier("none")) with self.assertRaisesRegex(ValueError, re.escape( "constructor of 'Invalid' not found in DefuzzifierFactory")): fl.FllImporter().defuzzifier("Invalid")
def test_activation(self) -> None: activation = "General" self.assertEqual(activation, str(fl.FllImporter().activation(activation))) activation = "Highest 2" self.assertEqual(activation, str(fl.FllImporter().activation(activation))) self.assertEqual(None, fl.FllImporter().activation("none")) with self.assertRaisesRegex(ValueError, re.escape( "constructor of 'Invalid' not found in ActivationFactory")): fl.FllImporter().activation("Invalid")
def test_term(self) -> None: term = "term: left Triangle 0.000 0.333 0.666" self.assertEqual(term, str(fl.FllImporter().term(term))) engine = fl.Engine() term = "term: function Function 1 + 1" self.assertEqual(term, str(fl.FllImporter().term(term))) self.assertEqual(None, cast(fl.Function, fl.FllImporter().term(term)).engine) self.assertEqual(engine, cast(fl.Function, fl.FllImporter().term(term, engine)).engine) with self.assertRaisesRegex(SyntaxError, re.escape( "expected format 'term: name Term [parameters]', but got 'term: name'")): fl.FllImporter().term("term: name")
def test_write_from_scope_all_variables_2(self) -> None: from fuzzylite.examples.hybrid import tipper engine = fl.FllImporter().from_string(str(tipper.engine)) writer = io.StringIO() fl.FldExporter().write_from_scope( engine, writer, values=16, scope=fl.FldExporter.ScopeOfValues.AllVariables, active_variables=set(engine.input_variables)) self.assertEqual("""\ service food mTip tsTip 0.000 0.000 4.999 5.000 0.000 3.333 7.756 6.538 0.000 6.667 12.949 10.882 0.000 10.000 13.571 11.667 3.333 0.000 8.569 7.500 3.333 3.333 10.110 8.673 3.333 6.667 13.770 12.925 3.333 10.000 14.368 13.889 6.667 0.000 12.895 11.000 6.667 3.333 13.204 12.797 6.667 6.667 17.986 20.636 6.667 10.000 21.156 22.778 10.000 0.000 13.571 11.667 10.000 3.333 13.709 13.889 10.000 6.667 20.216 22.778 10.000 10.000 25.001 25.000 """, writer.getvalue())
def test_write_from_scope_all_variables_1(self) -> None: engine = fl.FllImporter().from_string(str(SimpleDimmer.engine)) writer = io.StringIO() fl.FldExporter().write_from_scope( engine, writer, values=16, scope=fl.FldExporter.ScopeOfValues.AllVariables, active_variables=set(engine.input_variables)) self.assertEqual("""\ Ambient Power 0.000 nan 0.067 0.750 0.133 0.750 0.200 0.750 0.267 0.727 0.333 0.659 0.400 0.605 0.467 0.543 0.533 0.457 0.600 0.395 0.667 0.341 0.733 0.273 0.800 0.250 0.867 0.250 0.933 0.250 1.000 nan """, writer.getvalue())
def test_to_file_from_reader(self) -> None: engine = fl.FllImporter().from_string(str(SimpleDimmer.engine)) reader = """\ Ambient Power 0.000000000 nan 0.499023438 0.501459144 #0.500000000 0.500000000 0.509765625 0.486065263 0.510742188 0.484743908 """ file_name = ("file-" + ''.join(random.choice(string.ascii_lowercase) for _ in range(5)) + ".fld") fl.FldExporter().to_file_from_reader( Path(file_name), engine, io.StringIO(reader), skip_lines=1) self.assertTrue(Path(file_name).exists()) obtained = Path(file_name).read_text() Path(file_name).unlink() self.assertEqual("""\ Ambient Power 0.000 nan 0.499 0.501 0.510 0.486 0.511 0.485\n""", obtained)
def export(path: str) -> None: import io import time fl.lib.decimals = 9 importer = fl.FllImporter() exporters = [ fl.FllExporter(), fl.PythonExporter(), # fl.FldExporter() ] with io.open(path, 'r') as file: import_fll = file.read() engine = importer.from_string(import_fll) file_name = file.name[file.name.rfind('/'):file.name.rfind('.')] for exporter in exporters: start = time.time() if isinstance(exporter, fl.FldExporter): exporter.to_file_from_scope( Path("/tmp/fl/" + file_name + ".fld"), engine, 100_000) elif isinstance(exporter, fl.FllExporter): exporter.to_file(Path("/tmp/fl/" + file_name + ".fll"), engine) elif isinstance(exporter, fl.PythonExporter): exporter.to_file(Path("/tmp/fl/" + file_name + ".py"), engine) fl.lib.logger.info(str(path) + f".fld\t{time.time() - start}")
def test_write_from_reader(self) -> None: engine = fl.FllImporter().from_string(str(SimpleDimmer.engine)) reader = """\ Ambient Power 0.000000000 nan 0.499023438 0.501459144 #0.500000000 0.500000000 0.509765625 0.486065263 0.510742188 0.484743908 """ # Fails with headers with self.assertRaisesRegex(ValueError, r"could not convert string to float: 'Ambient'"): fl.FldExporter().write_from_reader( engine, io.StringIO(), io.StringIO(reader), skip_lines=0) # Success skipping headers writer = io.StringIO() fl.FldExporter().write_from_reader(engine, writer, io.StringIO(reader), skip_lines=1) self.assertEqual("""\ Ambient Power 0.000 nan 0.499 0.501 0.510 0.486 0.511 0.485\n""", writer.getvalue())
def test_engine(self) -> None: engine = """\ Engine: Bell description: obstacle avoidance for self-driving cars """ self.assertEqual(engine.replace("\n\n", "\n"), str(fl.FllImporter().engine(engine)))
def test_input_variable(self) -> None: iv = """\ InputVariable: obstacle description: location of obstacle relative to vehicle enabled: true range: 0.000 1.000 lock-range: false term: left Triangle 0.000 0.333 0.666 term: right Triangle 0.333 0.666 1.000""" self.assertEqual(iv.replace("\n\n", "\n"), str(fl.FllImporter().input_variable(iv)))
def test_extract_value(self) -> None: self.assertEqual("value", fl.FllImporter().extract_value("Key: value")) self.assertEqual("value", fl.FllImporter().extract_value("Key : value")) self.assertEqual( "value1 : value2", fl.FllImporter().extract_value("Key: value1 : value2", "Key")) self.assertEqual( "value1 : value2 : value 3", fl.FllImporter().extract_value("Key: value1 : value2 : value 3", "Key")) with self.assertRaisesRegex( SyntaxError, re.escape( "expected 'key: value' definition, but found 'key value1 value2'" )): fl.FllImporter().extract_value("key value1 value2") with self.assertRaisesRegex( SyntaxError, re.escape("expected 'DESCRIPTION: value' definition, " "but found 'description: value1 value2'")): fl.FllImporter().extract_value("description: value1 value2", "DESCRIPTION")
def test_rule_block(self) -> None: rb = """\ RuleBlock: steer_away description: steer away from obstacles enabled: true conjunction: none disjunction: none implication: Minimum activation: General rule: if obstacle is left then steer is right rule: if obstacle is right then steer is left""" self.assertEqual(rb.replace("\n\n", "\n"), str(fl.FllImporter().rule_block(rb)))
def export(file_path: str) -> None: import io import time import pathlib import importlib import numpy as np np.seterr(divide="ignore", invalid="ignore") fl.lib.floating_point_type = np.float64 path = pathlib.Path(file_path) if path.suffix == ".fll": with io.open(path, 'r') as file: import_fll = file.read() engine = fl.FllImporter().from_string(import_fll) elif path.suffix == ".py": package: List[str] = [] for parent in path.parents: package.append(parent.name) if parent.name == "fuzzylite": break module = ".".join(reversed(package)) + f".{path.stem}" engine = importlib.import_module(module).engine # type: ignore else: raise Exception(f"unknown importer of files like {path}") exporters = [fl.FllExporter(), fl.PythonExporter(), fl.FldExporter()] file_name = path.stem for exporter in exporters: start = time.time() target_path = Path( "/tmp/fl/") / path.parent.parent.stem / path.parent.stem target_path.mkdir(parents=True, exist_ok=True) fl.lib.decimals = 3 fl.lib.logger.info(str(path) + f" -> {exporter.class_name}") if isinstance(exporter, fl.FldExporter): fl.lib.decimals = 9 exporter.to_file_from_scope(target_path / (file_name + ".fld"), engine, 1024) elif isinstance(exporter, fl.FllExporter): exporter.to_file(target_path / (file_name + ".fll"), engine) elif isinstance(exporter, fl.PythonExporter): exporter.to_file(target_path / (file_name + ".py"), engine) fl.lib.logger.info( str(path) + f" -> {exporter.class_name}\t{time.time() - start}")
def test_write_from_scope_each_variable_1(self) -> None: engine = fl.FllImporter().from_string(str(SimpleDimmer.engine)) writer = io.StringIO() fl.FldExporter().write_from_scope( engine, writer, values=4, scope=fl.FldExporter.ScopeOfValues.EachVariable, active_variables=set(engine.input_variables)) self.assertEqual("""\ Ambient Power 0.000 nan 0.333 0.659 0.667 0.341 1.000 nan """, writer.getvalue())
def test_output_variable(self) -> None: ov = """\ OutputVariable: steer description: direction to steer the vehicle to enabled: true range: 0.000 1.000 lock-range: false aggregation: Maximum defuzzifier: Centroid 100 default: nan lock-previous: false term: left Bell 0.333 0.167 3.000 term: right Bell 0.666 0.167 3.000""" self.assertEqual(ov.replace("\n\n", "\n"), str(fl.FllImporter().output_variable(ov)))
def test_to_string_from_scope(self) -> None: engine = fl.FllImporter().from_string(str(SimpleDimmer.engine)) obtained = fl.FldExporter().to_string_from_scope( engine, values=4, scope=fl.FldExporter.ScopeOfValues.EachVariable, active_variables=set(engine.input_variables)) self.assertEqual("""\ Ambient Power 0.000 nan 0.333 0.659 0.667 0.341 1.000 nan """, obtained)
def test_write_from_scope_all_variables_one_inactive(self) -> None: from fuzzylite.examples.hybrid import tipper engine = fl.FllImporter().from_string(str(tipper.engine)) writer = io.StringIO() fl.FldExporter().write_from_scope( engine, writer, values=16, scope=fl.FldExporter.ScopeOfValues.AllVariables, active_variables={engine.input_variables[0]}) self.assertEqual("""\ service food mTip tsTip 0.000 nan nan nan 3.333 nan 15.000 15.000 6.667 nan 15.000 15.000 10.000 nan nan nan """, writer.getvalue())
def test_to_string(self) -> None: with self.assertRaisesRegex(ValueError, "expected an Engine, but got InputVariable"): fl.FldExporter().to_string(fl.InputVariable()) from fuzzylite.examples.takagi_sugeno import SimpleDimmer engine = fl.FllImporter().from_string(str(SimpleDimmer.engine)) obtained = fl.FldExporter().to_string(engine) self.assertEqual(1025 + 1, len(obtained.split("\n"))) self.assertEqual("""\ Ambient Power 0.000 nan 0.001 0.750 0.002 0.750 0.003 0.750""", '\n'.join(obtained.split("\n")[:5]))
def test_write(self) -> None: # Empty write writer = io.StringIO() fl.FldExporter().write(fl.Engine(), writer, [], set()) self.assertEqual("\n", writer.getvalue()) # Not enough values with self.assertRaisesRegex(ValueError, "not enough input values"): fl.FldExporter().write(fl.Engine( input_variables=[fl.InputVariable()]), writer, [], set()) # input and output values writer = io.StringIO() engine = fl.FllImporter().from_string(str(SimpleDimmer.engine)) fl.FldExporter(input_values=True, output_values=True).write( engine, writer, [0.25], set(engine.input_variables)) self.assertEqual("0.250 0.750\n", writer.getvalue()) # input values only writer = io.StringIO() fl.FldExporter(input_values=True, output_values=False).write( engine, writer, [0.25], set(engine.input_variables)) self.assertEqual("0.250\n", writer.getvalue()) # output values only writer = io.StringIO() fl.FldExporter(input_values=False, output_values=True).write( engine, writer, [0.25], set(engine.input_variables)) self.assertEqual("0.750\n", writer.getvalue()) # no values writer = io.StringIO() engine.process = MagicMock() # type: ignore fl.FldExporter(input_values=False, output_values=False).write( engine, writer, [0.25], set(engine.input_variables)) self.assertEqual("\n", writer.getvalue()) engine.process.assert_called_once() # type: ignore # active variables writer = io.StringIO() engine.input_variables[0].value = 0.250 test_variable = fl.InputVariable("test") test_variable.value = 0.0 engine.input_variables.append(test_variable) fl.FldExporter().write(engine, writer, [fl.inf, fl.inf], {test_variable}) self.assertEqual("0.250 inf 0.750\n", writer.getvalue())
def test_boolean(self) -> None: self.assertEqual(True, fl.FllImporter().boolean("true")) self.assertEqual(True, fl.FllImporter().boolean(" true ")) self.assertEqual(False, fl.FllImporter().boolean("false")) self.assertEqual(False, fl.FllImporter().boolean(" false ")) with self.assertRaisesRegex(SyntaxError, re.escape( "expected boolean in ['true', 'false'], but got 'True'")): fl.FllImporter().boolean("True") with self.assertRaisesRegex(SyntaxError, re.escape( r"expected boolean in ['true', 'false'], but got 'False'")): fl.FllImporter().boolean("False")
def test_to_string_from_reader(self) -> None: engine = fl.FllImporter().from_string(str(SimpleDimmer.engine)) reader = """\ Ambient Power 0.000000000 nan 0.499023438 0.501459144 #0.500000000 0.500000000 0.509765625 0.486065263 0.510742188 0.484743908 """ obtained = fl.FldExporter().to_string_from_reader(engine, io.StringIO(reader), skip_lines=1) self.assertEqual("""\ Ambient Power 0.000 nan 0.499 0.501 0.510 0.486 0.511 0.485\n""", obtained)
def test_import_examples(self) -> None: self.maxDiff = None # show all differences importer = fl.FllImporter() exporter = fl.FllExporter() fl.lib.decimals = 9 import logging fl.lib.logger.setLevel(logging.INFO) import fuzzylite.examples.terms terms = next(iter(fuzzylite.examples.terms.__path__)) # type: ignore counter = 0 for fll_file in glob.iglob(terms + '/*.fll', recursive=True): counter += 1 with open(fll_file, 'r') as file: fl.lib.logger.info(fll_file) fll_from_string = file.read() engine = importer.from_string(fll_from_string) export_fll = exporter.to_string(engine) self.assertEqual(fll_from_string, export_fll) self.assertEqual(20, counter) fl.lib.decimals = 3
def test_to_file_from_scope(self) -> None: engine = fl.FllImporter().from_string(str(SimpleDimmer.engine)) file_name = ("file-" + ''.join(random.choice(string.ascii_lowercase) for _ in range(5)) + ".fld") fl.FldExporter().to_file_from_scope( Path(file_name), engine, values=4, scope=fl.FldExporter.ScopeOfValues.EachVariable, active_variables=set(engine.input_variables)) self.assertTrue(Path(file_name).exists()) obtained = Path(file_name).read_text() Path(file_name).unlink() self.assertEqual("""\ Ambient Power 0.000 nan 0.333 0.659 0.667 0.341 1.000 nan """, obtained)
def test_from_string(self) -> None: engine = fl.FllImporter().from_string(BELL_FLL) self.assertEqual(BELL_FLL, str(engine))
def __init__(self): self.engine = fl.FllImporter().from_file('./TargetSpeed.fll')
def __init__(self): self.engine = fl.FllImporter().from_file('./Steering.fll')