# Path: pystruct/inference/inference_methods.py
# def inference_dispatch(unary_potentials, pairwise_potentials, edges,
#                        inference_method, return_energy=False, **kwargs):
#     """
#     Computes the maximizing assignment of a pairwise discrete energy function.
# 
#     Wrapper function to dispatch between inference method by string.
# 
#     Parameters
#     ----------
#     unary_potentials : nd-array, shape (n_nodes, n_states)
#         Unary potentials of energy function.
# 
#     pairwise_potentials : nd-array, shape (n_states, n_states) 
#                         or (n_states, n_states, n_edges).
#         Pairwise potentials of energy function.
#         If the first case, edge potentials are assumed to be the same for all 
#         edges.
#         In the second case, the sequence needs to correspond to the edges.
# 
#     edges : nd-array, shape (n_edges, 2)
#         Graph edges for pairwise potentials, given as pair of node indices. As
#         pairwise potentials are not assumed to be symmetric, the direction of
#         the edge matters.
# 
#     inference_method : string
#         Possible choices currently are:
#             * 'qpbo' for QPBO alpha-expansion (fast but approximate).
#             * 'lp' for build-in lp relaxation via cvxopt (slow).
#             * 'ad3' for AD^3 subgradient based dual solution of LP.
#             * 'ogm' for OpenGM wrappers.
#             * 'max-product' for max-product message passing.
#             * 'unary' for using unary potentials only.
# 
#         It is also possible to pass a tuple (string, dict) where the dict
#         contains additional keyword arguments, like
#         ``('ad3', {'branch_and_bound': True})``.
# 
#     relaxed : bool (default=False)
#         Whether to return a relaxed solution (when appropriate)
#         or round to the nearest integer solution. Only used for 'lp' and 'ad3'
#         inference methods.
# 
#     return_energy : bool (default=False)
#         Additionally return the energy of the returned solution (according to
#         the solver).  If relaxed=False, this is the energy of the relaxed, not
#         the rounded solution.
# 
#     Returns
#     -------
#     labels : nd-array
#         Approximate (usually) MAP variable assignment.
#         If relaxed=True, this is a tuple of unary and pairwise "marginals"
#         from the LP relaxation.
#     """
#     if isinstance(inference_method, tuple):
#         additional_kwargs = inference_method[1]
#         inference_method = inference_method[0]
#         # append additional_kwargs, but take care not to modify the dicts we
#         # got
#         kwargs = kwargs.copy()
#         kwargs.update(additional_kwargs)
#     if inference_method == "qpbo":
#         return inference_qpbo(unary_potentials, pairwise_potentials, edges,
#                               **kwargs)
#     elif inference_method == "lp":
#         return inference_lp(unary_potentials, pairwise_potentials, edges,
#                             return_energy=return_energy, **kwargs)
#     elif inference_method == "ad3":
#         return inference_ad3(unary_potentials, pairwise_potentials, edges,
#                              return_energy=return_energy, **kwargs)
#     elif inference_method == "ad3+":
#         return inference_ad3plus(unary_potentials, pairwise_potentials, edges,
#                              return_energy=return_energy, **kwargs)
#     elif inference_method == "ogm":
#         return inference_ogm(unary_potentials, pairwise_potentials, edges,
#                              return_energy=return_energy, **kwargs)
#     elif inference_method == "unary":
#         return inference_unaries(unary_potentials, pairwise_potentials, edges,
#                                  **kwargs)
#     elif inference_method == "max-product":
#         return inference_max_product(unary_potentials, pairwise_potentials,
#                                      edges, **kwargs)
#     else:
#         raise ValueError("inference_method must be 'max-product', 'lp', 'ad3',"
#                          " 'qpbo' or 'ogm', got %s" % inference_method)
# 
# Path: pystruct/inference/common.py
# def compute_energy(unary_potentials, pairwise_potentials, edges, labels):
#     """Compute energy of labels for given energy function.
# 
#     Convenience function with same interface as inference functions to easily
#     compare solutions.
# 
#     Parameters
#     ----------
#     unary_potentials : nd-array
#         Unary potentials of energy function.
# 
#     pairwise_potentials : nd-array
#         Pairwise potentials of energy function.
# 
#     edges : nd-array
#         Edges of energy function.
# 
#     labels : nd-array
#         Variable assignment to evaluate.
# 
#     Returns
#     -------
#     energy : float
#         Energy of assignment.
#     """
# 
#     n_states, pairwise_potentials = \
#         _validate_params(unary_potentials, pairwise_potentials, edges)
#     energy = np.sum(unary_potentials[np.arange(len(labels)), labels])
#     for edge, pw in zip(edges, pairwise_potentials):
#         energy += pw[labels[edge[0]], labels[edge[1]]]
#     return energy


import numpy as np
import matplotlib.pyplot as plt
from time import time
from pystruct.inference import inference_dispatch, compute_energy
from pystruct.utils import make_grid_edges

Simple comparison of inference times on a Potts model (smoothing)
on a 2d grid of random noise of 5 classes.

The plots show the label results together with energies (lower is better)
and inference time.
The results are quite representative of the algorithms in general.
AD3 is quite fast and gives good results (identical to lp), while
the general purpose lp solver is too slow for practical purposes.
QPBO is somewhat worse than the other methods, but significantly faster.
Our implementation of max-product message passing is not competative with
the high quality solutions found by AD3.
"""




size = 20
n_states = 5

rnd = np.random.RandomState(2)
x = rnd.normal(size=(size, size, n_states))
pairwise = np.eye(n_states)
edges = make_grid_edges(x)
unaries = x.reshape(-1, n_states)

fig, ax = plt.subplots(1, 5, figsize=(20, 5))
for a, inference_method in zip(ax, ['ad3', 'qpbo', 'max-product',
                                    ('max-product', {'max_iter': 10}), 'lp']):
    start = time()

# Path: pystruct/inference/inference_methods.py
# def inference_dispatch(unary_potentials, pairwise_potentials, edges,
#                        inference_method, return_energy=False, **kwargs):
#     """
#     Computes the maximizing assignment of a pairwise discrete energy function.
# 
#     Wrapper function to dispatch between inference method by string.
# 
#     Parameters
#     ----------
#     unary_potentials : nd-array, shape (n_nodes, n_states)
#         Unary potentials of energy function.
# 
#     pairwise_potentials : nd-array, shape (n_states, n_states) 
#                         or (n_states, n_states, n_edges).
#         Pairwise potentials of energy function.
#         If the first case, edge potentials are assumed to be the same for all 
#         edges.
#         In the second case, the sequence needs to correspond to the edges.
# 
#     edges : nd-array, shape (n_edges, 2)
#         Graph edges for pairwise potentials, given as pair of node indices. As
#         pairwise potentials are not assumed to be symmetric, the direction of
#         the edge matters.
# 
#     inference_method : string
#         Possible choices currently are:
#             * 'qpbo' for QPBO alpha-expansion (fast but approximate).
#             * 'lp' for build-in lp relaxation via cvxopt (slow).
#             * 'ad3' for AD^3 subgradient based dual solution of LP.
#             * 'ogm' for OpenGM wrappers.
#             * 'max-product' for max-product message passing.
#             * 'unary' for using unary potentials only.
# 
#         It is also possible to pass a tuple (string, dict) where the dict
#         contains additional keyword arguments, like
#         ``('ad3', {'branch_and_bound': True})``.
# 
#     relaxed : bool (default=False)
#         Whether to return a relaxed solution (when appropriate)
#         or round to the nearest integer solution. Only used for 'lp' and 'ad3'
#         inference methods.
# 
#     return_energy : bool (default=False)
#         Additionally return the energy of the returned solution (according to
#         the solver).  If relaxed=False, this is the energy of the relaxed, not
#         the rounded solution.
# 
#     Returns
#     -------
#     labels : nd-array
#         Approximate (usually) MAP variable assignment.
#         If relaxed=True, this is a tuple of unary and pairwise "marginals"
#         from the LP relaxation.
#     """
#     if isinstance(inference_method, tuple):
#         additional_kwargs = inference_method[1]
#         inference_method = inference_method[0]
#         # append additional_kwargs, but take care not to modify the dicts we
#         # got
#         kwargs = kwargs.copy()
#         kwargs.update(additional_kwargs)
#     if inference_method == "qpbo":
#         return inference_qpbo(unary_potentials, pairwise_potentials, edges,
#                               **kwargs)
#     elif inference_method == "lp":
#         return inference_lp(unary_potentials, pairwise_potentials, edges,
#                             return_energy=return_energy, **kwargs)
#     elif inference_method == "ad3":
#         return inference_ad3(unary_potentials, pairwise_potentials, edges,
#                              return_energy=return_energy, **kwargs)
#     elif inference_method == "ad3+":
#         return inference_ad3plus(unary_potentials, pairwise_potentials, edges,
#                              return_energy=return_energy, **kwargs)
#     elif inference_method == "ogm":
#         return inference_ogm(unary_potentials, pairwise_potentials, edges,
#                              return_energy=return_energy, **kwargs)
#     elif inference_method == "unary":
#         return inference_unaries(unary_potentials, pairwise_potentials, edges,
#                                  **kwargs)
#     elif inference_method == "max-product":
#         return inference_max_product(unary_potentials, pairwise_potentials,
#                                      edges, **kwargs)
#     else:
#         raise ValueError("inference_method must be 'max-product', 'lp', 'ad3',"
#                          " 'qpbo' or 'ogm', got %s" % inference_method)
# 
# Path: pystruct/inference/common.py
# def compute_energy(unary_potentials, pairwise_potentials, edges, labels):
#     """Compute energy of labels for given energy function.
# 
#     Convenience function with same interface as inference functions to easily
#     compare solutions.
# 
#     Parameters
#     ----------
#     unary_potentials : nd-array
#         Unary potentials of energy function.
# 
#     pairwise_potentials : nd-array
#         Pairwise potentials of energy function.
# 
#     edges : nd-array
#         Edges of energy function.
# 
#     labels : nd-array
#         Variable assignment to evaluate.
# 
#     Returns
#     -------
#     energy : float
#         Energy of assignment.
#     """
# 
#     n_states, pairwise_potentials = \
#         _validate_params(unary_potentials, pairwise_potentials, edges)
#     energy = np.sum(unary_potentials[np.arange(len(labels)), labels])
#     for edge, pw in zip(edges, pairwise_potentials):
#         energy += pw[labels[edge[0]], labels[edge[1]]]
#     return energy


# Path: examples/plot_potts_model.py
import numpy as np
import matplotlib.pyplot as plt
from time import time
from pystruct.inference import inference_dispatch, compute_energy
from pystruct.utils import make_grid_edges


Simple comparison of inference times on a Potts model (smoothing)
on a 2d grid of random noise of 5 classes.

The plots show the label results together with energies (lower is better)
and inference time.
The results are quite representative of the algorithms in general.
AD3 is quite fast and gives good results (identical to lp), while
the general purpose lp solver is too slow for practical purposes.
QPBO is somewhat worse than the other methods, but significantly faster.
Our implementation of max-product message passing is not competative with
the high quality solutions found by AD3.
"""




size = 20
n_states = 5

rnd = np.random.RandomState(2)
x = rnd.normal(size=(size, size, n_states))
pairwise = np.eye(n_states)
edges = make_grid_edges(x)
unaries = x.reshape(-1, n_states)

fig, ax = plt.subplots(1, 5, figsize=(20, 5))
for a, inference_method in zip(ax, ['ad3', 'qpbo', 'max-product',
                                    ('max-product', {'max_iter': 10}), 'lp']):
    start = time()

    y = inference_dispatch(unaries, pairwise, edges,