Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

286 add comments to the contraintsystem #289

Merged
merged 57 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
1043d7e
evaluation is not part of releases so it should not be in src.
smythi93 Jan 29, 2025
046772e
added comments to search
smythi93 Jan 29, 2025
18bb734
added comments to search
smythi93 Jan 29, 2025
5c8f41f
added comments to search
smythi93 Jan 29, 2025
b5409b6
New: output generated tree as grammar
andreas-zeller Jan 25, 2025
e5bd161
Typo
andreas-zeller Jan 25, 2025
4e3bb73
New: "parse" command
andreas-zeller Jan 25, 2025
ea6e08e
Code cleanup
andreas-zeller Jan 25, 2025
dda0432
In "parse", also check constraints
andreas-zeller Jan 25, 2025
a4a820e
New: fandango parse: report location if parsing fails
andreas-zeller Jan 26, 2025
c1e0cf2
New: fandango parse: support binary inputs
andreas-zeller Jan 26, 2025
829d102
Fix: handle bytes inputs during parse
andreas-zeller Jan 26, 2025
1e68548
New: fandango parse: even more precise error locations
andreas-zeller Jan 26, 2025
c8026c8
New: fandango parse: allow checking prefixes
andreas-zeller Jan 26, 2025
265c080
Fix: report errors at position 0 properly
andreas-zeller Jan 26, 2025
b48f78c
New: can also check constraints for incomplete inputs
andreas-zeller Jan 26, 2025
d44ca12
No more ; at end of rules
andreas-zeller Jan 26, 2025
c9e7967
Can now (almost) parse bits.fan
andreas-zeller Jan 26, 2025
d0a35ea
New: proper parsing of bits
andreas-zeller Jan 26, 2025
c811ac1
Code cleanup
andreas-zeller Jan 26, 2025
bff2a68
Take requirements.txt out
andreas-zeller Jan 26, 2025
17732c9
Took out parse_table() test
andreas-zeller Jan 26, 2025
7e50b4a
New: if some .py source file changed,
andreas-zeller Jan 26, 2025
7a5b430
New: fandango parse: Don't show unused algorithm settings in help
andreas-zeller Jan 26, 2025
b5a3c1e
Fixes for CI tests
andreas-zeller Jan 26, 2025
669b859
Reformatting
andreas-zeller Jan 26, 2025
8137884
New: --validate flag checks after fuzzing if files can be parsed
andreas-zeller Jan 27, 2025
a72c478
New: fuzz: also validate that parse() returns a correct input
andreas-zeller Jan 27, 2025
2deb7d9
New: extended validation of fuzz() vs parse()
andreas-zeller Jan 27, 2025
cb7c9c1
Fix: `-n` option was ignored
andreas-zeller Jan 27, 2025
163ca2a
Fix: use shutil.rmtree() to remove temp dir
andreas-zeller Jan 27, 2025
eed151f
Removed temp files
andreas-zeller Jan 27, 2025
300d242
Moved gif stuff to docs
andreas-zeller Jan 28, 2025
638192f
Add "Automatically generated" message at top
andreas-zeller Jan 28, 2025
ba26472
Fix: support for parsing bits in binary inputs (bytes)
andreas-zeller Jan 28, 2025
d3afc75
We can now parse GIF files
andreas-zeller Jan 28, 2025
3691d7a
Doc fix
andreas-zeller Jan 28, 2025
77005a4
Fix: Only issue separator _between_ individuals, not at end
andreas-zeller Jan 28, 2025
eeb0ad1
Started documenting GIF steps
andreas-zeller Jan 28, 2025
20b4806
Fix: adjust to CLI no longer outputting separators ony between indivi…
andreas-zeller Jan 28, 2025
11fbf26
New method `parse_forest()` allows to track _all_ parsing alternatives
andreas-zeller Jan 28, 2025
2b00f10
New method `parse_forest()` allows to track _all_ parsing alternatives
andreas-zeller Jan 28, 2025
56cd55f
New: parsing works as soon as size for RGB is set
andreas-zeller Jan 28, 2025
e37d285
Fix: proper separation of binary vs. non-binary inputs
andreas-zeller Jan 28, 2025
8bd6dcf
New: determine file mode (text / binary) from grammar (or derivation …
andreas-zeller Jan 28, 2025
d5dbed3
Fix: output in multiple dirs failed
andreas-zeller Jan 28, 2025
597c8f3
Workaround for str() conversions
andreas-zeller Jan 28, 2025
31c3834
Fix: 'b' key in fandango shell would invoke completion (???)
andreas-zeller Jan 28, 2025
5216710
Doc update
andreas-zeller Jan 28, 2025
27db81c
fix: refactor dependencies
joszamama Jan 29, 2025
1277cca
fix: evaluation works again
joszamama Jan 29, 2025
8baee94
fix: 1 hour evaluation
joszamama Jan 29, 2025
45a97b4
feat: release 0.1.1
joszamama Jan 29, 2025
55ee4c9
merge
smythi93 Jan 29, 2025
2b42ee9
updated makefile and workflow
smythi93 Jan 29, 2025
3697b0b
updated makefile and workflow
smythi93 Jan 29, 2025
b152d16
updated workflow to make install and run two steps
smythi93 Jan 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,18 @@ jobs:
pip install pygraphviz

# Step 5: Install Python dependencies using make and run tests
- name: Install dependencies with Makefile and run tests
- name: Install dependencies with Makefile
run: |
python -m pip install --upgrade pip # Upgrade pip to the latest version
make install-test # Install dependencies using the Makefile
make tests # Run the tests

# Step 6: Cache installed packages for system dependencies
# Step 6: Run tests using pytest
- name: Run tests with pytest
run: |
make tests # Run the tests

# Step 7: Cache installed packages for system dependencies
- name: Cache pygraphviz dependencies
uses: actions/cache@v3
with:
Expand Down
File renamed without changes.
File renamed without changes.
294 changes: 274 additions & 20 deletions src/fandango/constraints/base.py

Large diffs are not rendered by default.

112 changes: 111 additions & 1 deletion src/fandango/constraints/fitness.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
The `fitness` module provides the `Fitness` class and its subclasses `ValueFitness` and `ConstraintFitness`.
"""

import abc
import enum
import itertools
Expand All @@ -9,6 +13,10 @@


class Comparison(enum.Enum):
"""
Enum class for comparison operations.
"""

EQUAL = "=="
NOT_EQUAL = "!="
GREATER = ">"
Expand All @@ -18,17 +26,33 @@ class Comparison(enum.Enum):


class ComparisonSide(enum.Enum):
"""
Enum class for comparison side.
"""

LEFT = "left"
RIGHT = "right"


class FailingTree:
"""
Class to represent a failing tree, i.e., a tree that does not satisfy a given constraint.
"""

def __init__(
self,
tree: DerivationTree,
cause: "GeneticBase",
suggestions: Optional[List[Tuple[Comparison, Any, ComparisonSide]]] = None,
):
"""
Initialize the FailingTree with the given tree, cause, and suggestions.

:param DerivationTree tree: The tree that failed to satisfy the constraint.
:param GeneticBase cause: The cause of the failure.
:param Optional[List[Tuple[Comparison, Any, ComparisonSide]]] suggestions: The list of suggestions to
which causes the cause to fail.
"""
self.tree = tree
self.cause = cause
self.suggestions = suggestions or []
Expand All @@ -47,12 +71,26 @@ def __str__(self):


class Fitness(abc.ABC):
"""
Abstract class to represent the fitness of a tree.
"""

def __init__(self, success: bool, failing_trees: List[FailingTree] = None):
"""
Initialize the Fitness with the given success and failing trees.

:param bool success: The success of the fitness.
:param Optional[List[FailingTree]] failing_trees: The list of failing trees.
"""
self.success = success
self.failing_trees = failing_trees or []

@abc.abstractmethod
def fitness(self) -> float:
"""
Abstract method to calculate the fitness of the tree.
:return float: The fitness of the tree.
"""
pass

@abc.abstractmethod
Expand All @@ -61,13 +99,29 @@ def __copy__(self) -> "Fitness":


class ValueFitness(Fitness):
"""
Class to represent the fitness of a tree based on calculated values.
The fitness is calculated as the average of the values.
This class contrast the `ConstraintFitness` class, which calculates the fitness based on the number of
constraints satisfied.
"""

def __init__(
self, values: List[float] = None, failing_trees: List[FailingTree] = None
):
"""
Initialize the ValueFitness with the given values and failing trees.
:param Optional[List[float]] values: The list of values.
:param Optional[List[FailingTree]] failing_trees: The list of failing trees.
"""
super().__init__(True, failing_trees)
self.values = values or []

def fitness(self) -> float:
"""
Calculate the fitness of the tree as the average of the values.
:return float: The fitness of the tree.
"""
if self.values:
return sum(self.values) / len(self.values)
else:
Expand All @@ -78,18 +132,36 @@ def __copy__(self) -> Fitness:


class ConstraintFitness(Fitness):
"""
Class to represent the fitness of a tree based on constraints.
The fitness is calculated as the number of constraints solved by the tree divided by the total number of
constraints.
"""

def __init__(
self,
solved: int,
total: int,
success: bool,
failing_trees: List[FailingTree] = None,
):
"""
Initialize the ConstraintFitness with the given solved, total, success, and failing trees.
:param int solved: The number of constraints solved by the tree.
:param int total: The total number of constraints.
:param bool success: The success of the fitness.
:param Optional[List[FailingTree]] failing_trees: The list of failing trees.
"""
super().__init__(success, failing_trees)
self.solved = solved
self.total = total

def fitness(self) -> float:
"""
Calculate the fitness of the tree as the number of constraints solved by the tree divided by the total number of
constraints.
:return float: The fitness of the tree.
"""
if self.total:
return self.solved / self.total
else:
Expand All @@ -105,17 +177,31 @@ def __copy__(self) -> Fitness:


class GeneticBase(abc.ABC):
"""
Abstract class to represent a genetic base.
"""

def __init__(
self,
searches: Optional[Dict[str, NonTerminalSearch]] = None,
local_variables: Optional[Dict[str, Any]] = None,
global_variables: Optional[Dict[str, Any]] = None,
):
"""
Initialize the GeneticBase with the given searches, local variables, and global variables.
:param Optional[Dict[str, NonTerminalSearch]] searches: The dictionary of searches.
:param Optional[Dict[str, Any]] local_variables: The dictionary of local variables.
:param Optional[Dict[str, Any]] global_variables: The dictionary of global variables.
"""
self.searches = searches or dict()
self.local_variables = local_variables or dict()
self.global_variables = global_variables or dict()

def get_access_points(self):
"""
Get the access points of the genetic base, i.e., the non-terminal that are considered in this genetic base.
:return List[NonTerminal]: The list of access points.
"""
return sum(
[search.get_access_points() for search in self.searches.values()], []
)
Expand All @@ -126,6 +212,12 @@ def fitness(
tree: DerivationTree,
scope: Optional[Dict[NonTerminal, DerivationTree]] = None,
) -> Fitness:
"""
Abstract method to calculate the fitness of the tree.
:param DerivationTree tree: The tree to calculate the fitness.
:param Optional[Dict[NonTerminal, DerivationTree]] scope: The scope of non-terminals matching to trees.
:return Fitness: The fitness of the tree.
"""
raise NotImplementedError("Fitness function not implemented")

@staticmethod
Expand All @@ -140,6 +232,13 @@ def combinations(
tree: DerivationTree,
scope: Optional[Dict[NonTerminal, DerivationTree]] = None,
):
"""
Get all possible combinations of trees that satisfy the searches.
:param DerivationTree tree: The tree to calculate the fitness.
:param Optional[Dict[NonTerminal, DerivationTree]] scope: The scope of non-terminals matching to trees.
:return List[List[Tuple[str, DerivationTree]]]: The list of combinations of trees that fill all non-terminals
in the genetic base.
"""
nodes: List[List[Tuple[str, DerivationTree]]] = []
for name, search in self.searches.items():
nodes.append(
Expand All @@ -151,10 +250,21 @@ def check(
self,
tree: DerivationTree,
scope: Optional[Dict[NonTerminal, DerivationTree]] = None,
):
) -> bool:
"""
Check if the tree satisfies the genetic base.
:param DerivationTree tree: The tree to check.
:param Optional[Dict[NonTerminal, DerivationTree]] scope: The scope of non-terminals matching to trees.
:return bool: True if the tree satisfies the genetic base, False otherwise.
"""
return self.fitness(tree, scope).success

def get_failing_nodes(self, tree: DerivationTree):
"""
Get the failing nodes of the tree.
:param DerivationTree tree: The tree to check.
:return List[FailingTree]: The list of failing trees
"""
return self.fitness(tree).failing_trees

@abc.abstractmethod
Expand Down
Loading