Skip to content

Commit

Permalink
Extend project with the following functions:
Browse files Browse the repository at this point in the history
+ totaly revised
more information soon

v2021.12.2
  • Loading branch information
LukasWestholt committed Dec 10, 2021
1 parent fd4eab7 commit 4f2d8dc
Show file tree
Hide file tree
Showing 44 changed files with 1,770 additions and 822 deletions.
1 change: 1 addition & 0 deletions .idea/SetSolver1.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 24 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,52 @@ This script is solving set problems by brute-force. See [HOWTO](#HOWTO).
# HOWTO
Use python3.10 or newer. Download it [here](https://www.python.org/downloads/).

```
```shell
"python.exe" -m pip install SetSolver1
```

First import the module:
```
```python
import SetSolver1
```

Now you can use the method:
```
SetSolver1.search(const_sets: dict[str, set[frozenset | int | tuple] | MathSet], result: set[frozenset | int | tuple] | MathSet, not_allowed: list = None, identity: Identity = None) -> list[MathSet] | None
SetSolver1.search(const_dict: dict[str, set[frozenset | int | tuple] | MathSet] | ConstDictType,
result: set[frozenset | int | tuple] | MathSet | ResultType,
not_allowed: list[MODE] = None,
identity: RelationMathSet | None = None,
overflow: int = 30,
range_int: int = 20,
do_print: bool = True) -> ResultWay | None
```

Where `const_sets` is a dictionary for the predefined constants and `result` is the wanted solution.
With the method `search` you can find the probably shortest way to this solution by the predefined constants
and normal set operations. With this method you will get a list of valid ways (mostly one way) back.
Where `const_dict` is a dictionary for the predefined constants and `result` is the wanted solution.
With the method `search` you can find probably the shortest way to this solution by the predefined constants
and normal set operations. With this method you will get an ResultWay object back.

Little example:
```
[little example](/examples/sets/exercice2.py):
```python
import SetSolver1

# Here you set your predefined constants.
# Please make sure that you do not assign a variable letter twice.
# Python dictionaries will otherwise only store the last value and overwrite the previous ones.
const_sets: dict[str, set[frozenset | int]] = {
"A": {frozenset({2, frozenset()}), frozenset({5})},
"B": {frozenset(), frozenset({3}), frozenset({5})}
}
const_dict = SetSolver1.SimpleMathSetConstDictType(
{
"A": {frozenset({2, frozenset()}), frozenset({5})}, # string "[[2, []],[5]]" is allowed too
"B": {frozenset(), frozenset({3}), frozenset({5})}
}
)

# Here you set your wanted solution.
result = {frozenset(), frozenset({3}), frozenset({5}), frozenset({frozenset()})}
result = SetSolver1.SimpleMathSetResultType({frozenset(), frozenset({3}), frozenset({5}), frozenset({frozenset()})})

output = SetSolver1.search(const_sets, result)
output = SetSolver1.search(const_dict, result)
```


See German examples [here](beispiele.md) with outputs.
More examples are [here](/examples)
See German examples explanation [here](beispiele.md) with outputs.

# Requirements

Expand Down
183 changes: 164 additions & 19 deletions SetSolver1/MODE.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,164 @@
# tuple of index, used_vars, priority
UNION = 0, (1, 2), 1
COMPLEMENT_X = 1, (1, 2), 1
COMPLEMENT_Y = 2, (2, 1), 1
INTERSECTION = 3, (1, 2), 2
COMPOSITION_X = 4, (1, 2), 3
COMPOSITION_Y = 5, (2, 1), 3
POWER_SET_X = 6, (1,), 4
POWER_SET_Y = 7, (2,), 4
CONVERSE_RELATION_X = 8, (1,), 3
CONVERSE_RELATION_Y = 9, (2,), 3
REFLEXIVE_CLOSURE_X = 10, (1,), 2
REFLEXIVE_CLOSURE_Y = 11, (2,), 2
TRANSITIVE_CLOSURE_X = 12, (1,), 2
TRANSITIVE_CLOSURE_Y = 13, (2,), 2

CHOOSE_BY_INDEX = (UNION, COMPLEMENT_X, COMPLEMENT_Y, INTERSECTION, COMPOSITION_X, COMPOSITION_Y, POWER_SET_X,
POWER_SET_Y, CONVERSE_RELATION_X, CONVERSE_RELATION_Y, REFLEXIVE_CLOSURE_X, REFLEXIVE_CLOSURE_Y,
TRANSITIVE_CLOSURE_X, TRANSITIVE_CLOSURE_Y)
#!/usr/bin/env python3
# coding: utf-8


class MODE:
_value: tuple[tuple[int], int, int]
_print_str: str

def __init__(self, used_vars, priority, is_commutative, print_str):
"""
Constructor method
:type used_vars: tuple[int]
:type priority: int
:type is_commutative: int
:type print_str: str
"""
self._value = (used_vars, priority, is_commutative)
self._print_str = print_str

def __getitem__(self, item):
"""
__getitem__ method
:type item: int
:rtype: int | tuple
"""
return self._value[item]

def __lt__(self, other):
if type(other) == self.__class__:
return self[1] < other[1]

def __repr__(self):
return list(GET_BY_KEY.keys())[list(GET_BY_KEY.values()).index(self)]

def format(self, x, y):
"""
returns format _print_str with x and y
:type x: str
:type y: str
:rtype: str
"""
return self._print_str.format(x=x, y=y)

def is_multi_mode(self):
return self[0] == (1, 2)

def is_single_mode(self):
return not self.is_multi_mode()


CONST = MODE(
used_vars=tuple(),
priority=1,
is_commutative=1,
print_str='{x}'
)
IDENTITY = MODE(
used_vars=tuple(),
priority=1,
is_commutative=1,
print_str=''
)
TEMPORARY_CREATED = MODE(
used_vars=tuple(),
priority=1,
is_commutative=1,
print_str=''
)
UNION = MODE(
used_vars=(1, 2),
priority=1,
is_commutative=1,
print_str='({x}+{y})'
)
COMPLEMENT = MODE(
used_vars=(1, 2),
priority=1,
is_commutative=0,
print_str='({x}-{y})'
)
INTERSECTION = MODE(
used_vars=(1, 2),
priority=2,
is_commutative=1,
print_str='({x}&{y})'
)
COMPOSITION = MODE(
used_vars=(1, 2),
priority=3,
is_commutative=0,
print_str='({x}.{y})'
)
POWER_SET = MODE(
used_vars=(1,),
priority=4,
is_commutative=1,
print_str='pow({x})'
)
SYMMETRIC_DIFFERENCE = MODE(
used_vars=(1, 2),
priority=99, # TODO
is_commutative=1,
print_str='({x}sym{y})'
)
CONVERSE_RELATION = MODE(
used_vars=(1,),
priority=3,
is_commutative=1,
print_str='inverse({x})'
)
REFLEXIVE_CLOSURE = MODE(
used_vars=(1,),
priority=2,
is_commutative=1,
print_str='reflexive_cl({x})'
)
TRANSITIVE_CLOSURE = MODE(
used_vars=(1,),
priority=2,
is_commutative=1,
print_str='transitive_cl({x})'
)
MULTISET_DISJOINT_UNION = MODE(
used_vars=(1, 2),
priority=2,
is_commutative=1,
print_str='({x}+{y})'
)
MULTISET_DIFFERENCE = MODE(
used_vars=(1, 2),
priority=2,
is_commutative=0,
print_str='({x}-{y})'
)

GET_BY_KEY = {
"CONST": CONST,
"IDENTITY": IDENTITY,
"TEMPORARY_CREATED": TEMPORARY_CREATED,
"union": UNION,
"complement": COMPLEMENT,
"intersection": INTERSECTION,
"composition": COMPOSITION,
"power_set": POWER_SET,
"symmetric_difference": SYMMETRIC_DIFFERENCE,
"converse_relation": CONVERSE_RELATION,
"reflexive_closure": REFLEXIVE_CLOSURE,
"transitive_closure": TRANSITIVE_CLOSURE,
"disjoint_union": MULTISET_DISJOINT_UNION,
"multi_set_difference": MULTISET_DIFFERENCE
}

CHOOSE_BY_INDEX = [UNION, COMPLEMENT, INTERSECTION, COMPOSITION, POWER_SET, CONVERSE_RELATION, REFLEXIVE_CLOSURE,
TRANSITIVE_CLOSURE, MULTISET_DISJOINT_UNION, MULTISET_DIFFERENCE]
SORTED_CHOOSE_BY_INDEX = sorted(CHOOSE_BY_INDEX)

DEFAULT_NOT_ALLOWED = [COMPOSITION, CONVERSE_RELATION, REFLEXIVE_CLOSURE, TRANSITIVE_CLOSURE, MULTISET_DISJOINT_UNION,
MULTISET_DIFFERENCE]
NOT_ALLOWED_EVERYTHING = CHOOSE_BY_INDEX

RESULT = TEMPORARY_CREATED
TEMPORARY_CREATED_WAY = (TEMPORARY_CREATED, None, None)
CONST_WAY = (CONST, None, None)
IDENTITY_WAY = (IDENTITY, None, None)
126 changes: 126 additions & 0 deletions SetSolver1/MathSet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#!/usr/bin/env python3
# coding: utf-8

from __future__ import annotations

from SetSolver1.MODE import MODE, TEMPORARY_CREATED, CONST, CONST_WAY
from SetSolver1.TinyMathSet import TinyMathSet


class MathSet:
"""
BaseClass BaseSet
"""
def __init__(self, value, way):
"""
Constructor method
:type value: any
:type way: (MODE, any, any)
"""
self.value = value
self.way = way

def __repr__(self):
return "{0}({1})".format(type(self).__name__, self.__dict__)

def __str__(self):
return str(self.value)

def __hash__(self):
# Default: hash(x)==id(x)/16
# https://stackoverflow.com/a/11324771
# https://docs.python.org/3/glossary.html#term-hashable
return hash(self.value)

def __eq__(self, other):
if isinstance(other, self.__class__):
return self.value == other.value
print("NotImplemented Equality Compare")
return NotImplemented

def __len__(self):
"""
:rtype: int
"""
return len(self.value)

def correct_way(self):
"""
Helper method to set correct way to consts
"""
if self.way == CONST_WAY:
self.way = (CONST, self, None)

def walk_way(self, going_by=None):
"""
Walk through the way and count steps
:param going_by: value adding per step of way
:type going_by: int
:raises ValueError:
:return: steps of way
:rtype: int
"""
mode = self.way[0]
if mode == TEMPORARY_CREATED:
raise ValueError("MODE.TEMPORARY_CREATED not allowed here")
if mode == CONST:
return 0
lt = list()
for i in mode[0]:
if self.way[i] is not None:
lt.append(self.way[i].walk_way(going_by))
return sum(lt) + (going_by if going_by is not None else mode[1])

def sort_key(self):
"""
ascending order so: 2 is before 5
:rtype: (int, int)
"""
# TODO ist there a way to sort by second key only if needed?
return self.walk_way(going_by=1), self.walk_way()

def deep_len(self):
return sum(el.deep_len() if type(el) == TinyMathSet else 1 for el in self.value)

def total_deep_len(self):
return sum(el.total_deep_len()+1 if type(el) == TinyMathSet else 1 for el in self.value)

def is_empty(self):
"""
Is MathSet empty?
:rtype: bool
"""
return len(self.value) == 0

def union(self, y):
raise RuntimeError("this operation is not allowed")

def complement(self, y):
raise RuntimeError("this operation is not allowed")

def intersection(self, y):
raise RuntimeError("this operation is not allowed")

def power_set(self):
raise RuntimeError("this operation is not allowed")

def symmetric_difference(self, y):
raise RuntimeError("this operation is not allowed")

def composition(self, y):
raise RuntimeError("this operation is not allowed")

def converse_relation(self):
raise RuntimeError("this operation is not allowed")

def reflexive_closure(self):
raise RuntimeError("this operation is not allowed")

def transitive_closure(self):
raise RuntimeError("this operation is not allowed")

def disjoint_union(self, y):
raise RuntimeError("this operation is not allowed")

def multi_set_difference(self, y):
raise RuntimeError("this operation is not allowed")

0 comments on commit 4f2d8dc

Please sign in to comment.