# Path: stationary/utils/edges.py
# def edges_to_edge_dict(edges):
#     """
#     Converts a list of edges to a transition dictionary taking (source, target)
#     to the transition between the states.
# 
#     Parameters
#     ----------
#     edges: list of tuples
#         Transition probabilities of the form [(source, target, transition
#         probability
# 
#     Returns
#     -------
#     edges, maps 2-tuples of nodes to floats
#     """
# 
#     edge_dict = dict()
#     for e1, e2, v in edges:
#         edge_dict[(e1, e2)] = v
#     return edge_dict
# 
# Path: stationary/utils/graph.py
# class Graph(object):
#     """Directed graph object intended for the graph associated to a Markov process.
#     Gives easy access to the neighbors of a particular state needed for various
#     calculations.
# 
#     Vertices can be any hashable / immutable python object.
#     """
# 
#     def __init__(self, edges=None):
#         self.out_mapping = defaultdict(lambda: defaultdict(float))
#         self.in_mapping = defaultdict(lambda: defaultdict(float))
#         if edges:
#             self.add_edges(edges)
# 
#     def add_vertex(self, label):
#         self._vertices.add(label)
# 
#     def add_edge(self, source, target, weight=1.):
#         self.out_mapping[source][target] = weight
#         self.in_mapping[target][source] = weight
# 
#     def add_edges(self, edges):
#         try:
#             for source, target, weight in edges:
#                 self.add_edge(source, target, weight)
#         except ValueError:
#             for source, target in edges:
#                 self.add_edge(source, target, 1.0)
# 
#     def vertices(self):
#         """Returns the set of vertices of the graph."""
#         return self.out_mapping.keys()
# 
#     def out_dict(self, source):
#         """Returns a dictionary of the outgoing edges of source with weights."""
#         return self.out_mapping[source]
# 
#     def out_vertices(self, source):
#         """Returns a list of the outgoing vertices."""
#         return self.out_mapping[source].keys()
# 
#     def in_dict(self, target):
#         """Returns a dictionary of the incoming edges of source with weights."""
#         return self.in_mapping[target]
# 
#     def normalize_weights(self):
#         """Normalizes the weights coming out of each vertex to be probability
#         distributions."""
#         # new_edges = []
#         for source in self.out_mapping.keys():
#             total = float(sum(self.out_mapping[source].values()))
#             for target, weight in self.out_mapping.items():
#                 self.out_mapping[target] = weight / total
# 
#     def right_multiply(self, d):
#         """
#         Multiply by a vector (specified as a dict on the vertices) by 
#         viewing the graph as a sparse matrix, i.e.
#         return G*d
#         """
#         s = defaultdict(float)
#         for k in d.keys():
#             for k2, v2 in self.out_dict(k).items():
#                 s[k] += d[k2] * v2
#         return s
# 
#     def left_multiply(self, d):
#         """
#         Multiply by a vector (specified as a dict on the vertices) by 
#         viewing the graph as a sparse matrix, i.e.
#         return d*G
#         """
#         s = defaultdict(float)
#         for k in d.keys():
#             for k2, v2 in self.in_dict(k).items():
#                 s[k] += d[k2] * v2
#         return s
# 
#     def __getitem__(self, k):
#         """Returns the dictionary of outgoing edges. You can access the weight
#         of an edge with g[source][target]."""
#         return self.out_mapping[k]
# 
# Path: stationary/utils/math_helpers.py
# def slice_dictionary(d, N, slice_index=0, slice_value=0):
# def squared_error(d1, d2):
# def squared_error_dict(d1, d2):
# def multiply_vectors(a, b):
# def dot_product(a, b):
# def normalize(x):
# def normalize_dictionary(x):
# def inc_factorial(x, n):
# def factorial(i):
# def log_inc_factorial(x,n):
# def log_factorial(i):
# def simplex_generator(N, d=2):
# def one_step_generator(d):
# def one_step_indicies_generator(d):
# def kl_divergence(p, q):
# def kl_divergence_dict(p, q):
# def q_divergence(q):
#         def d(x, y):
#         def d(x, y):
#     def d(x, y):
# def shannon_entropy(p):
# def binary_entropy(p):


from collections import Callable
from numpy import log, exp
from stationary.utils.edges import edges_to_edge_dict
from stationary.utils.graph import Graph
from stationary.utils.math_helpers import (
    simplex_generator, logsumexp, kl_divergence, kl_divergence_dict)
import itertools
        # Take a path from initial to state.
        seq = [initial_state]
        e = list(seq[-1])
        for i in range(0, num_players):
            while e[i] < state[i]:
                for j in range(0, num_players):
                    if e[j] > state[j]:
                        break
                e[j] = e[j] - 1
                e[i] = e[i] + 1
                seq.append(tuple(e))
            while e[i] > state[i]:
                for j in range(0, num_players):
                    if e[j] < state[j]:
                        break
                e[j] = e[j] + 1
                e[i] = e[i] - 1
                seq.append(tuple(e))
        if logspace:
            s = 0.
        else:
            s = 1.
        for index in range(len(seq)-1):
            e, f = seq[index], seq[index+1]
            if logspace:
                s += log(edges[(e, f)]) - log(edges[(f, e)])
            else:
                s *= edges[(e, f)] / edges[(f, e)]
        d[state] = s
    if logspace:

# Path: stationary/utils/edges.py
# def edges_to_edge_dict(edges):
#     """
#     Converts a list of edges to a transition dictionary taking (source, target)
#     to the transition between the states.
# 
#     Parameters
#     ----------
#     edges: list of tuples
#         Transition probabilities of the form [(source, target, transition
#         probability
# 
#     Returns
#     -------
#     edges, maps 2-tuples of nodes to floats
#     """
# 
#     edge_dict = dict()
#     for e1, e2, v in edges:
#         edge_dict[(e1, e2)] = v
#     return edge_dict
# 
# Path: stationary/utils/graph.py
# class Graph(object):
#     """Directed graph object intended for the graph associated to a Markov process.
#     Gives easy access to the neighbors of a particular state needed for various
#     calculations.
# 
#     Vertices can be any hashable / immutable python object.
#     """
# 
#     def __init__(self, edges=None):
#         self.out_mapping = defaultdict(lambda: defaultdict(float))
#         self.in_mapping = defaultdict(lambda: defaultdict(float))
#         if edges:
#             self.add_edges(edges)
# 
#     def add_vertex(self, label):
#         self._vertices.add(label)
# 
#     def add_edge(self, source, target, weight=1.):
#         self.out_mapping[source][target] = weight
#         self.in_mapping[target][source] = weight
# 
#     def add_edges(self, edges):
#         try:
#             for source, target, weight in edges:
#                 self.add_edge(source, target, weight)
#         except ValueError:
#             for source, target in edges:
#                 self.add_edge(source, target, 1.0)
# 
#     def vertices(self):
#         """Returns the set of vertices of the graph."""
#         return self.out_mapping.keys()
# 
#     def out_dict(self, source):
#         """Returns a dictionary of the outgoing edges of source with weights."""
#         return self.out_mapping[source]
# 
#     def out_vertices(self, source):
#         """Returns a list of the outgoing vertices."""
#         return self.out_mapping[source].keys()
# 
#     def in_dict(self, target):
#         """Returns a dictionary of the incoming edges of source with weights."""
#         return self.in_mapping[target]
# 
#     def normalize_weights(self):
#         """Normalizes the weights coming out of each vertex to be probability
#         distributions."""
#         # new_edges = []
#         for source in self.out_mapping.keys():
#             total = float(sum(self.out_mapping[source].values()))
#             for target, weight in self.out_mapping.items():
#                 self.out_mapping[target] = weight / total
# 
#     def right_multiply(self, d):
#         """
#         Multiply by a vector (specified as a dict on the vertices) by 
#         viewing the graph as a sparse matrix, i.e.
#         return G*d
#         """
#         s = defaultdict(float)
#         for k in d.keys():
#             for k2, v2 in self.out_dict(k).items():
#                 s[k] += d[k2] * v2
#         return s
# 
#     def left_multiply(self, d):
#         """
#         Multiply by a vector (specified as a dict on the vertices) by 
#         viewing the graph as a sparse matrix, i.e.
#         return d*G
#         """
#         s = defaultdict(float)
#         for k in d.keys():
#             for k2, v2 in self.in_dict(k).items():
#                 s[k] += d[k2] * v2
#         return s
# 
#     def __getitem__(self, k):
#         """Returns the dictionary of outgoing edges. You can access the weight
#         of an edge with g[source][target]."""
#         return self.out_mapping[k]
# 
# Path: stationary/utils/math_helpers.py
# def slice_dictionary(d, N, slice_index=0, slice_value=0):
# def squared_error(d1, d2):
# def squared_error_dict(d1, d2):
# def multiply_vectors(a, b):
# def dot_product(a, b):
# def normalize(x):
# def normalize_dictionary(x):
# def inc_factorial(x, n):
# def factorial(i):
# def log_inc_factorial(x,n):
# def log_factorial(i):
# def simplex_generator(N, d=2):
# def one_step_generator(d):
# def one_step_indicies_generator(d):
# def kl_divergence(p, q):
# def kl_divergence_dict(p, q):
# def q_divergence(q):
#         def d(x, y):
#         def d(x, y):
#     def d(x, y):
# def shannon_entropy(p):
# def binary_entropy(p):


# Path: stationary/stationary_.py
from collections import Callable
from numpy import log, exp
from stationary.utils.edges import edges_to_edge_dict
from stationary.utils.graph import Graph
from stationary.utils.math_helpers import (
    simplex_generator, logsumexp, kl_divergence, kl_divergence_dict)
import itertools

        # Take a path from initial to state.
        seq = [initial_state]
        e = list(seq[-1])
        for i in range(0, num_players):
            while e[i] < state[i]:
                for j in range(0, num_players):
                    if e[j] > state[j]:
                        break
                e[j] = e[j] - 1
                e[i] = e[i] + 1
                seq.append(tuple(e))
            while e[i] > state[i]:
                for j in range(0, num_players):
                    if e[j] < state[j]:
                        break
                e[j] = e[j] + 1
                e[i] = e[i] - 1
                seq.append(tuple(e))
        if logspace:
            s = 0.
        else:
            s = 1.
        for index in range(len(seq)-1):
            e, f = seq[index], seq[index+1]
            if logspace:
                s += log(edges[(e, f)]) - log(edges[(f, e)])
            else:
                s *= edges[(e, f)] / edges[(f, e)]
        d[state] = s
    if logspace:

        s0 = logsumexp([v for v in d.values()])