Skip to content

Commit

Permalink
Start code refactor
Browse files Browse the repository at this point in the history
- reify actions
- separate node's tree data from state
  • Loading branch information
Rui Rei committed Jan 17, 2017
1 parent 634e9fc commit 821be05
Show file tree
Hide file tree
Showing 9 changed files with 538 additions and 4 deletions.
4 changes: 0 additions & 4 deletions src/rr/opt/mcts/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
from pkgutil import extend_path


__path__ = extend_path(__path__, __name__)
Empty file added src/rr/opt/mcts/action.py
Empty file.
38 changes: 38 additions & 0 deletions src/rr/opt/mcts/expansion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import random


class TreeNodeExpansion(object):
"""Lazy generator of child nodes.
This object creates a copy of a given parent node and applies the next (unexpanded) branch in
its branch list on demand. When the parent node has been completely expanded, the 'next()'
method will return None and the 'is_finished' flag is set to true.
"""
def __init__(self, node):
self.node = node
self.actions_iter = None
self.actions_buff = None
self.is_started = False
self.is_finished = False

def start(self):
if self.is_started:
raise ValueError("multiple attempts to start node expansion")
self.actions_iter = iter(self.node.actions())
self.is_started = True
self._advance_branch()

def next(self):
if self.is_finished:
raise ValueError("node expansion is already finished")
child = self.node.copy()
child.apply(self.actions_buff)
self._advance_branch()
return child

def _advance_branch(self):
try:
self.actions_buff = next(self.actions_iter)
except StopIteration:
self.actions_buff = None
self.is_finished = True
53 changes: 53 additions & 0 deletions src/rr/opt/mcts/infeasible.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
INF = float("inf")


class Infeasible(object):
"""
Infeasible objects can be compared with other objects (such as floats), but always compare as
greater (*i.e.* worse in a minimization sense) than those objects. Among infeasible objects,
they compare by value, meaning that they can be used to represent different degrees of
infeasibility.
To inform the MCTS framework that a solution is infeasible, set an :class:`Infeasible` object
as the solution's ``value`` attribute, like so:
.. code-block:: python
class MyNode(mcts.TreeNode):
# (...)
def simulate(self):
# (...)
infeas = len(self.unassigned_vars)
if infeas > 0:
return mcts.Solution(value=mcts.Infeasible(infeas))
# (...)
# (...)
"""
def __init__(self, infeas=+INF):
self.infeas = infeas

def __str__(self):
return "{}({})".format(type(self).__name__, self.infeas)

def __repr__(self):
return "<{} @{:x}>".format(self, id(self))

def __eq__(self, obj):
return isinstance(obj, Infeasible) and self.infeas == obj.infeas

def __ne__(self, obj):
return not isinstance(obj, Infeasible) or self.infeas != obj.infeas

def __gt__(self, obj):
return not isinstance(obj, Infeasible) or self.infeas > obj.infeas

def __ge__(self, obj):
return not isinstance(obj, Infeasible) or self.infeas >= obj.infeas

def __lt__(self, obj):
return isinstance(obj, Infeasible) and self.infeas < obj.infeas

def __le__(self, obj):
return isinstance(obj, Infeasible) and self.infeas <= obj.infeas

0 comments on commit 821be05

Please sign in to comment.