# Path: gelato/specs/base.py
# class DistSpec(SpecVar):
#     """Spec based on pymc3 distributions
# 
#     All specs support lazy evaluation, see Usage
# 
#     Parameters
#     ----------
#     distcls : pymc3.Distribution
#     args : args for `distcls`
#     kwargs : kwargs for `distcls`
# 
#     Usage
#     -----
#     >>> spec = DistSpec(Normal, mu=0, sd=DistSpec(Lognormal, 0, 1))
#     >>> spec += (NormalSpec() + LaplaceSpec()) / 100 - NormalSpec()
#     >>> with Model():
#     ...     prior_expr = spec((10, 10), name='silly_prior')
# 
#     """
#     def __init__(self, distcls, *args, **kwargs):
#         if not isinstance(distcls, type) and issubclass(distcls, pm.Distribution):
#             raise ValueError('We can deal with pymc3 '
#                              'distributions only, got {!r} instead'
#                              .format(distcls))
#         self.testval = kwargs.pop('testval', None)
#         self.tag = kwargs.get('tag', 'default')
#         self.args = args
#         self.kwargs = kwargs
#         self.distcls = distcls
# 
#     def __call__(self, shape, name=None, memo=None):
#         memo, shape = self._prepare(memo, shape)
#         if name is None:
#             name = self.auto()
#         shape, tag = self._get_shape(shape)
#         if id(self) ^ hash(tag) in memo:
#             return memo[id(self) ^ hash(tag)]
#         model = pm.modelcontext(None)
#         called_args = self._call_args(self.args, name, shape, memo)
#         called_kwargs = self._call_kwargs(self.kwargs, name, shape, memo)
#         called_kwargs.update(shape=shape['default'])
#         val = model.Var(
#             name, self.distcls.dist(
#                 *called_args,
#                 dtype=theano.config.floatX,
#                 **called_kwargs
#             ),
#         )
#         if self.testval is None:
#             val.tag.test_value = get_default_testval()(shape['default']).astype(val.dtype)
#         elif isinstance(self.testval, str) and self.testval == 'random':
#             val.tag.test_value = val.random(size=shape['default']).astype(val.dtype)
#         else:
#             val.tag.test_value = self.testval(shape['default']).astype(val.dtype)
#         memo[id(self) ^ hash(tag)] = val
#         return memo[id(self) ^ hash(tag)]
# 
#     def __repr__(self):
#         if self._shape != -1:
#             sh = '; '+str(self._shape)
#         else:
#             sh = ''
#         template = '<{cls}: {args!r}; {kwargs!r}'+sh+'>'
#         return template.format(cls=self.distcls.__name__,
#                                args=self.args,
#                                kwargs=self.kwargs)
# 
# def get_default_testval():
#     return _default_testval
# 
# def smart_init(shape):
#     if len(shape) > 1:
#         return init.GlorotUniform()(shape)
#     else:
#         return init.Normal()(shape)


import copy
import pymc3 as pm
from lasagne import init
from gelato.specs.base import DistSpec, get_default_testval, smart_init
    'WaldSpec',
    'ParetoSpec',
    'InverseGammaSpec',
    'ExGaussianSpec',
    'VonMisesSpec',
    'SkewNormalSpec',
    # 'HalfStudentTSpec',
    # 'NormalMixtureSpec'
]

_default_spec = DistSpec(pm.Normal, mu=0, sd=10, testval=smart_init)


def get_default_spec(testval=None):
    # to avoid init collision
    cp = copy.deepcopy(_default_spec)
    if testval is None and cp.testval is None:
        cp.testval = get_default_testval()
    elif testval is not None:
        cp.testval = testval
    else:
        pass
    return cp


def set_default_spec(spec):
    global _default_spec
    _default_spec = spec



# Path: gelato/specs/base.py
# class DistSpec(SpecVar):
#     """Spec based on pymc3 distributions
# 
#     All specs support lazy evaluation, see Usage
# 
#     Parameters
#     ----------
#     distcls : pymc3.Distribution
#     args : args for `distcls`
#     kwargs : kwargs for `distcls`
# 
#     Usage
#     -----
#     >>> spec = DistSpec(Normal, mu=0, sd=DistSpec(Lognormal, 0, 1))
#     >>> spec += (NormalSpec() + LaplaceSpec()) / 100 - NormalSpec()
#     >>> with Model():
#     ...     prior_expr = spec((10, 10), name='silly_prior')
# 
#     """
#     def __init__(self, distcls, *args, **kwargs):
#         if not isinstance(distcls, type) and issubclass(distcls, pm.Distribution):
#             raise ValueError('We can deal with pymc3 '
#                              'distributions only, got {!r} instead'
#                              .format(distcls))
#         self.testval = kwargs.pop('testval', None)
#         self.tag = kwargs.get('tag', 'default')
#         self.args = args
#         self.kwargs = kwargs
#         self.distcls = distcls
# 
#     def __call__(self, shape, name=None, memo=None):
#         memo, shape = self._prepare(memo, shape)
#         if name is None:
#             name = self.auto()
#         shape, tag = self._get_shape(shape)
#         if id(self) ^ hash(tag) in memo:
#             return memo[id(self) ^ hash(tag)]
#         model = pm.modelcontext(None)
#         called_args = self._call_args(self.args, name, shape, memo)
#         called_kwargs = self._call_kwargs(self.kwargs, name, shape, memo)
#         called_kwargs.update(shape=shape['default'])
#         val = model.Var(
#             name, self.distcls.dist(
#                 *called_args,
#                 dtype=theano.config.floatX,
#                 **called_kwargs
#             ),
#         )
#         if self.testval is None:
#             val.tag.test_value = get_default_testval()(shape['default']).astype(val.dtype)
#         elif isinstance(self.testval, str) and self.testval == 'random':
#             val.tag.test_value = val.random(size=shape['default']).astype(val.dtype)
#         else:
#             val.tag.test_value = self.testval(shape['default']).astype(val.dtype)
#         memo[id(self) ^ hash(tag)] = val
#         return memo[id(self) ^ hash(tag)]
# 
#     def __repr__(self):
#         if self._shape != -1:
#             sh = '; '+str(self._shape)
#         else:
#             sh = ''
#         template = '<{cls}: {args!r}; {kwargs!r}'+sh+'>'
#         return template.format(cls=self.distcls.__name__,
#                                args=self.args,
#                                kwargs=self.kwargs)
# 
# def get_default_testval():
#     return _default_testval
# 
# def smart_init(shape):
#     if len(shape) > 1:
#         return init.GlorotUniform()(shape)
#     else:
#         return init.Normal()(shape)


# Path: gelato/specs/dist.py
import copy
import pymc3 as pm
from lasagne import init
from gelato.specs.base import DistSpec, get_default_testval, smart_init

    'WaldSpec',
    'ParetoSpec',
    'InverseGammaSpec',
    'ExGaussianSpec',
    'VonMisesSpec',
    'SkewNormalSpec',
    # 'HalfStudentTSpec',
    # 'NormalMixtureSpec'
]

_default_spec = DistSpec(pm.Normal, mu=0, sd=10, testval=smart_init)


def get_default_spec(testval=None):
    # to avoid init collision
    cp = copy.deepcopy(_default_spec)
    if testval is None and cp.testval is None:
        cp.testval = get_default_testval()
    elif testval is not None:
        cp.testval = testval
    else:
        pass
    return cp


def set_default_spec(spec):
    global _default_spec
    _default_spec = spec



class PartialSpec(DistSpec):