# Path: vampyre/solver/base.py
# class Solver(object):
#     """
#     Base class for solver
#     
#     :param hist_list:  String list of variables to save the history of.  
#        These will be saved in the :code:`hist_dict` dictionary
#     """    
#     def __init__(self, hist_list):
#         self.hist_list = hist_list
#         self.init_hist()
#         
#     def init_hist(self):
#         """
#         Initializes the history dictionary.
#         
#         This should be called any time :code:`hist_list` has been changed
#         """        
#         # Initialize the dictionary with an empty list for each item
#         self.hist_dict = {}
#         for attr in self.hist_list:
#             self.hist_dict[attr] = []
#             
#             
#     def save_hist(self):
#         """
#         Save the items in the history dictionary
#         
#         For each item :code:`attr` in :code:`self.hist_list`, the method
#         will make a copy of :code:`self.attr` and append it to the list,
#         :code:`self.hist_list['attr']`.  If :code:`self.attr` implements
#         a :code:`copy()` method, it will run that method to perform a deep
#         copy.  Otherwise, it will simply perform a shallow copy.
#         """
#         for attr in self.hist_list:
#             val = getattr(self,attr)
#             if hasattr(val,'copy'):
#                 if callable(val.copy):
#                     val = val.copy()                    
#             self.hist_dict[attr].append(val)


import numpy as np
import vampyre.common as common
import vampyre.estim as estim
import vampyre.trans as trans
from vampyre.solver.base import Solver
# Import other subpackages

# Import methods and classes from the same vampyre sub-package

class MLVampAdmm(Solver):
    """
    Mulit-layer VAMP solver
    
    The VAMP solver performs estimation on a penalty function of the form:
    
    :math:`f(z) = f_0(z_0) + \\sum_\\ell=1^{L-1} f_\\ell(z_\ell,z_{\\ell+1}) + f_L(z_L)`
    
    where :math:`f_\\ell(\\cdot)` are the estimators for each 'layer'.
    
    :param est_list:  List of estimators for the variables.  There should be
       :math:`L+1` estimators in the list
    :param msg_hdl_list:  List of message handlers where 
        :code:`msg_hdl_list[i]` is used for any message incoming to variable
        :math:`z_i`.  There should be :math:`L` elements in the list.
    :param hist_list:  List of attributes to save the history of during the
       course of the iterations.
    :param nit:  Maximum number of iterations          
    :param comp_cost:  Compute cost
    :param prt_period:  Print summary every :code:`prt_period` iterations.
       When :code:`prt_period==0`, there is no printing.
    :param rvar_fix:  Fixed variances.  Value of :code:`None` means the 
       variances are updated adaptively.
    """
    def __init__(self, est_list, msg_hdl_list=[], hist_list=[], nit=10,\
        comp_cost=False,prt_period=0):

# Path: vampyre/solver/base.py
# class Solver(object):
#     """
#     Base class for solver
#     
#     :param hist_list:  String list of variables to save the history of.  
#        These will be saved in the :code:`hist_dict` dictionary
#     """    
#     def __init__(self, hist_list):
#         self.hist_list = hist_list
#         self.init_hist()
#         
#     def init_hist(self):
#         """
#         Initializes the history dictionary.
#         
#         This should be called any time :code:`hist_list` has been changed
#         """        
#         # Initialize the dictionary with an empty list for each item
#         self.hist_dict = {}
#         for attr in self.hist_list:
#             self.hist_dict[attr] = []
#             
#             
#     def save_hist(self):
#         """
#         Save the items in the history dictionary
#         
#         For each item :code:`attr` in :code:`self.hist_list`, the method
#         will make a copy of :code:`self.attr` and append it to the list,
#         :code:`self.hist_list['attr']`.  If :code:`self.attr` implements
#         a :code:`copy()` method, it will run that method to perform a deep
#         copy.  Otherwise, it will simply perform a shallow copy.
#         """
#         for attr in self.hist_list:
#             val = getattr(self,attr)
#             if hasattr(val,'copy'):
#                 if callable(val.copy):
#                     val = val.copy()                    
#             self.hist_dict[attr].append(val)


# Path: vampyre/solver/mlvamp_admm.py
import numpy as np
import vampyre.common as common
import vampyre.estim as estim
import vampyre.trans as trans
from vampyre.solver.base import Solver

# Import other subpackages

# Import methods and classes from the same vampyre sub-package

class MLVampAdmm(Solver):
    """
    Mulit-layer VAMP solver
    
    The VAMP solver performs estimation on a penalty function of the form:
    
    :math:`f(z) = f_0(z_0) + \\sum_\\ell=1^{L-1} f_\\ell(z_\ell,z_{\\ell+1}) + f_L(z_L)`
    
    where :math:`f_\\ell(\\cdot)` are the estimators for each 'layer'.
    
    :param est_list:  List of estimators for the variables.  There should be
       :math:`L+1` estimators in the list
    :param msg_hdl_list:  List of message handlers where 
        :code:`msg_hdl_list[i]` is used for any message incoming to variable
        :math:`z_i`.  There should be :math:`L` elements in the list.
    :param hist_list:  List of attributes to save the history of during the
       course of the iterations.
    :param nit:  Maximum number of iterations          
    :param comp_cost:  Compute cost
    :param prt_period:  Print summary every :code:`prt_period` iterations.
       When :code:`prt_period==0`, there is no printing.
    :param rvar_fix:  Fixed variances.  Value of :code:`None` means the 
       variances are updated adaptively.
    """
    def __init__(self, est_list, msg_hdl_list=[], hist_list=[], nit=10,\
        comp_cost=False,prt_period=0):

        Solver.__init__(self,hist_list)