Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
McLeopold committed Dec 31, 2011
0 parents commit dbb9164
Show file tree
Hide file tree
Showing 57 changed files with 2,761 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .project
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>PythonSkills</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>
10 changes: 10 additions & 0 deletions .pydevproject
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?>

<pydev_project>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
<path>/PythonSkills</path>
</pydev_pathproperty>
</pydev_project>
44 changes: 44 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
The core ideas used in this Moserware.Skills for Python project were described in
"TrueSkill (TM): A Bayesian Skill Rating System" available at
http://research.microsoft.com/apps/pubs/default.aspx?id=67956

The authors of the above paper have asked for a link to that article
as attribution in derived works.

Some concepts were based on sample F# code that was written by Ralf Herbrich
Copyright (c) 2007, 2008 Microsoft Research Ltd, available at
http://blogs.technet.com/apg/archive/2008/06/16/trueskill-in-f.aspx

This Python code was ported from the C# and PHP Moserware.Skills project at
http://github.com/moserware/Skills and at
http://github.com/moserware/PHPSkills

The Python code in the project is
Copyright (c) 2012 Scott Hamilton <mcleopold@gmail.com>

Both the PHP and C# in Moserware.Skills are
Copyright (c) 2010 Jeff Moser <jeff@moserware.com>

Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.

THIS SOFTWARE IS PROVIDED BY SCOTT HAMILTON ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SCOTT HAMILTON OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of Scott Hamilton.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
This is a Python port of the Moserware.Skills project that's available at

http://github.com/moserware/Skills

For more details on how the algorithm works, see

http://www.moserware.com/2010/03/computing-your-skill.html

For details on how to use this project, see the accompanying unit tests with this project
Empty file added Skills/Elo/__init__.py
Empty file.
45 changes: 45 additions & 0 deletions Skills/FactorGraphs/Factor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class FactorError(Exception):
pass

class Factor():
def __init__(self, name):
self.messages = []
self.variables = []

self.name = name
self.message_to_variable_binding = {}

def __str__(self):
return self.name if self.name is not None else self.__class__.__name__

def log_normalization(self):
return 0

def update_message_index(self, message_index):
try:
message = self.messages[message_index]
variable = self.message_to_variable_binding[message]
return self.update_message_variable(message, variable)
except IndexError:
raise FactorError("message_index is an invalid index")

def update_message_variable(self, message, variable):
raise NotImplementedError("update_message_variable is not implemented")

def reset_marginals(self):
for current_variable in self.message_to_variable_binding.values():
current_variable.reset_to_prior

def send_message_index(self, message_index):
try:
message = self.messages[message_index]
variable = self.message_to_variable_binding[message]
return self.send_message_variable(message, variable)
except IndexError:
raise FactorError("message_index is an invalid index")

def create_variable_to_message_binding_with_message(self, variable, message):
self.messages.append(message)
self.variables.append(variable)
self.message_to_variable_binding[message] = variable
return message
3 changes: 3 additions & 0 deletions Skills/FactorGraphs/FactorGraph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class FactorGraph():
def __init__(self):
self.variable_factory = None
27 changes: 27 additions & 0 deletions Skills/FactorGraphs/FactorGraphLayer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from Schedule import ScheduleSequence

class FactorGraphLayer():

def __init__(self, parent_graph):
self._local_factors = []
self.output_variables_groups = []
self.input_variables_groups = []
self.parent_factor_graph = parent_graph

def local_factors(self):
return self._local_factors

def schedule_sequence(self, items_to_sequence, name):
return ScheduleSequence(name, items_to_sequence)

def add_layer_factor(self, factor):
self._local_factors.append(factor)

def build_layer(self):
raise NotImplementedError("build_layer not implemented")

def create_prior_schedule(self):
return None

def create_posterior_schedule(self):
return None
19 changes: 19 additions & 0 deletions Skills/FactorGraphs/FactorList.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class FactorList(list):
'''
Helper class for computing the factor graph's normalization constant
'''

def log_normalization(self):
for current_factor in self:
current_factor.reset_marginals()

sum_log_z = 0.0
for f in self:
for j in range(len(f.messages)):
sum_log_z += f.send_message_index(j)

sum_log_s = 0
for current_factor in self:
sum_log_s += current_factor.log_normalization()

return sum_log_z + sum_log_s
8 changes: 8 additions & 0 deletions Skills/FactorGraphs/Message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Message():

def __init__(self, value=None, name=None):
self.name = name
self.value = value

def __str__(self):
return self.name
58 changes: 58 additions & 0 deletions Skills/FactorGraphs/Schedule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
class Schedule():
log = None # can be set globally for all instances

def __init__(self, name):
self.name = name

def __str__(self):
return self.name

def visit(self, depth= -1, max_depth=0):
raise NotImplementedError("visit not implemented")

class ScheduleStep(Schedule):
def __init__(self, name, factor, index):
Schedule.__init__(self, name)
self.factor = factor
self.index = index

def visit(self, depth= -1, max_depth=0):
delta = self.factor.update_message_index(self.index)
if self.log:
self.log("d %02d : %.4f step %s (%s=%s)" % (depth, delta, self.name, self.index, self.factor))
return delta

class ScheduleSequence(Schedule):
def __init__(self, name, schedules):
Schedule.__init__(self, name)
self.schedules = schedules

def visit(self, depth= -1, max_depth=0):
if self.log:
self.log("d %02d : sequence visit %s" % (depth, self.name))
max_delta = 0
for schedule in self.schedules:
current_visit = schedule.visit(depth + 1, max_depth)
max_delta = max(current_visit, max_delta)
if self.log:
self.log("d %02d : %.4f sequence %s" % (depth, max_delta, self.name))
return max_delta

class ScheduleLoop(Schedule):
def __init__(self, name, schedule_to_loop, max_delta):
Schedule.__init__(self, name)
self.schedule_to_loop = schedule_to_loop
self.max_delta = max_delta

def visit(self, depth= -1, max_depth=0):
if self.log:
self.log("d %02d : loop visit %s" % (depth, self.name))
total_iterations = 1
delta = self.schedule_to_loop.visit(depth + 1, max_depth)
while delta > self.max_delta:
delta = self.schedule_to_loop.visit(depth + 1, max_depth)
if self.log:
self.log("d %02d : %.4f loop %03d %s" % (depth, delta, total_iterations, self.name))
total_iterations += 1

return delta
30 changes: 30 additions & 0 deletions Skills/FactorGraphs/Variable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class VariableError(Exception):
pass

class Variable():

def __init__(self, name, prior):
self.name = "Variable[%s]" % name
self.prior = prior
self.reset_to_prior()

def __str__(self):
return self.name

def reset_to_prior(self):
self.value = self.prior

class DefaultVariable(Variable):
def __init__(self):
Variable.__init__(self, "Default", None)

def __setattr__(self, name, value):
if name == 'value':
raise VariableError("DefaultVariable attribute value can not be changed")
else:
super(DefaultVariable, self).__setattr(name, value)

class KeyedVariable(Variable):
def __init__(self, key, name, prior):
Variable.__init__(self, name, prior)
self.key = key
12 changes: 12 additions & 0 deletions Skills/FactorGraphs/VariableFactory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from Variable import Variable, KeyedVariable

class VariableFactory():

def __init__(self, variable_prior_initializer):
self.variable_prior_initializer = variable_prior_initializer

def create_basic_variable(self, name):
return Variable(name, self.variable_prior_initializer())

def create_keyed_variable(self, key, name):
return KeyedVariable(key, name, self.variable_prior_initializer())
Empty file added Skills/FactorGraphs/__init__.py
Empty file.
36 changes: 36 additions & 0 deletions Skills/GameInfo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from Rating import Rating

class GameInfoError(Exception):
pass

class GameInfo():
'''
Parameters about the game for calculating theTrueSkill.
'''

DEFAULT_INITIAL_MEAN = 25.0
DEFAULT_INITIAL_STANDARD_DEVIATION = DEFAULT_INITIAL_MEAN / 3
DEFAULT_BETA = DEFAULT_INITIAL_MEAN / 6
DEFAULT_DYNAMICS_FACTOR = DEFAULT_INITIAL_MEAN / 300
DEFAULT_DRAW_PROBABILITY = 0.10
DEFAULT_CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER = 3.0

def __init__(self, initial_mean=DEFAULT_INITIAL_MEAN,
stdev=DEFAULT_INITIAL_STANDARD_DEVIATION,
beta=DEFAULT_BETA,
dynamics_factor=DEFAULT_DYNAMICS_FACTOR,
draw_probability=DEFAULT_DRAW_PROBABILITY,
conservative_stdev_multiplier=DEFAULT_CONSERVATIVE_STANDARD_DEVIATION_MULTIPLIER):

try:
self.initial_mean = float(initial_mean)
self.initial_stdev = float(stdev)
self.beta = float(beta)
self.dynamics_factor = float(dynamics_factor)
self.draw_probability = float(draw_probability)
self.conservative_stdev_multiplier = float(conservative_stdev_multiplier)
except ValueError:
raise GameInfoError("GameInfo arguments must be numeric")

def default_rating(self):
return Rating(self.initial_mean, self.initial_stdev)
Loading

0 comments on commit dbb9164

Please sign in to comment.