State and Actions formalism. How to implement +,-,= operators between different classes

Viewed 47

I have a problem with a set of states. To move from a state to another I need to do a set of actions. I'm trying to implement State and Actions classes in a way that the following comparisons returns true:

state1 + actions == state2
state2 - actions == state1
state2 - state1 == actions

I wrote a test case for my implementation that is the following:

class State:
    pass

class Actions:
    pass

starting_state ={'a':'1',
                 'b':'2'}

some_actions = {'a': 'remove 1',
                'b' : 'remove 2,add #',
                'c' : 'add 5'}
inverse_actions = {'a': 'add 1',
                   'b' : 'remove #,add 2',
                   'c' : 'remove 5'}
final_state = {'b':'#',
               'c':'5'}

state1 = State(starting_state)

actions = Actions(some_actions)

state2= state1 + actions

assert State(final_state)==state2
assert Actions(inverse_actions)== -actions
assert state2 - actions == state1
assert state2 - state1 == actions

My questions are:

  • There is nothing pre-built that can help me to implement the State and Actions classes?
  • If not, how can I implement the + and - operations between different classes? There is a way to avoid circular dependencies?

Thank you for the help!

2 Answers

You can use operator overloading for this. Here is an example:

class A:
    def __init__(self, a):
        self.a = a 

    def __add__(self, other):
        return A(self.a+other.a)

    def __str__(self):
        return str(self.a)
i = A(1)
j = A(1)
l = i+j
assert str(l) == "2"

You can find the list of operators here which you can overload according to your needs: https://docs.python.org/3/library/operator.html

As Marin suggested, you need to use operator overloading. Here is a simple example that works for + and == operators:

class State:
    def __init__(self, s):
        self.state = s

    def __add__(self, other):
        d = self.state.copy()
        if isinstance(other, State):
            d.update(other.state)
        elif isinstance(other, Actions):
            for var, actions in other.actions.items():
                for action in actions.split(","):
                    statement, value = action.split()
                    if statement == "remove":
                        if d.pop(var, None) is None:
                            print("Cannot remove", value, ", not in state")
                    elif statement == "add":
                        d[var] = value
        else:
            return NotImplemented
        return State(d)

    def __eq__(self, other):
        if isinstance(other, State):
            return self.state == other.state
        elif isinstance(other, dict):
            return self.state == other
        else:
            return NotImplemented


class Actions:
    def __init__(self, a):
        self.actions = a


starting_state = {'a': '1',
                  'b': '2'}

some_actions = {'a': 'remove 1',
                'b': 'remove 2,add #',
                'c': 'add 5'}
inverse_actions = {'a': 'add 1',
                   'b': 'remove #,add 2',
                   'c': 'remove 5'}
final_state = {'b': '#',
               'c': '5'}

state1 = State(starting_state)

actions = Actions(some_actions)

state2 = state1 + actions

assert State(final_state) == state2
assert state1 + actions == final_state
# assert Actions(inverse_actions) == -actions
# assert state2 - actions == state1
# assert state2 - state1 == actions

You need to overload __sub__ and __neg__ to get final result.

Related