Skip to content

Commit

Permalink
[python] Use logger instead of print
Browse files Browse the repository at this point in the history
  • Loading branch information
pluegh committed Jan 25, 2022
1 parent 5f705e9 commit a995062
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 41 deletions.
30 changes: 30 additions & 0 deletions pypmc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,33 @@

# import these submodules by default
from . import mix_adapt, density, sampler, tools

_log_to_stdout = False
def log_to_stdout(verbose=False):
'''
Turn on logging and add a handler which prints to stderr, if not active
yet.
:param verbose:
Bool; if ``True``, output non-critical status information
'''
global _log_to_stdout
import logging
import sys
logger = logging.getLogger(__name__)

if verbose:
logger.setLevel(logging.INFO)
else:
logger.setLevel(logging.WARNING)

if not _log_to_stdout:
formatter = logging.Formatter('[%(levelname)s] %(message)s')
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(formatter)
logger.addHandler(handler)
_log_to_stdout = True

log_to_stdout()
23 changes: 11 additions & 12 deletions pypmc/mix_adapt/hierarchical.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import numpy as np
import scipy.linalg as linalg

import logging
logger = logging.getLogger(__name__)

class Hierarchical(object):
"""Hierarchical clustering as described in [GR04]_.
Expand Down Expand Up @@ -64,8 +67,8 @@ def _cleanup(self, kill, verbose):

self.nout -= len(removed_indices)

if verbose and removed_indices:
print('Removing %s' % removed_indices)
if removed_indices:
logger.info('Removing %s' % removed_indices)

for j in removed_indices:
self.inv_map.pop(j[0])
Expand Down Expand Up @@ -180,8 +183,7 @@ def run(self, eps=1e-4, kill=True, max_steps=50, verbose=False):
old_distance = np.finfo(np.float64).max
new_distance = np.finfo(np.float64).max

if verbose:
print('Starting hierarchical clustering with %d components.' % len(self.g.components))
logger.info('Starting hierarchical clustering with %d components.' % len(self.g.components))
converged = False
for step in range(1, max_steps + 1):
self._cleanup(kill, verbose)
Expand All @@ -191,29 +193,26 @@ def run(self, eps=1e-4, kill=True, max_steps=50, verbose=False):
new_distance = self._distance()
assert new_distance >= 0, 'Found non-positive distance %d' % new_distance

if verbose:
print('Distance in step %d: %g' % (step, new_distance))
logger.info('Distance in step %d: %g' % (step, new_distance))
if new_distance == old_distance:
converged = True
if verbose:
print('Exact minimum found after %d steps' % step)
logger.info('Exact minimum found after %d steps' % step)
break

rel_change = (old_distance - new_distance) / old_distance
assert not (rel_change < -1e-13), 'distance increased'

if rel_change < eps and not converged and step > 0:
converged = True
if verbose and new_distance != old_distance:
print('Close enough to local minimum after %d steps' % step)
if new_distance != old_distance:
logger.info('Close enough to local minimum after %d steps' % step)
break

# save distance for comparison in next step
old_distance = new_distance

self._cleanup(kill, verbose)
if verbose:
print('%d components remain.' % len(self.g.components))
logger.info('%d components remain.' % len(self.g.components))

if converged:
return step
Expand Down
18 changes: 9 additions & 9 deletions pypmc/mix_adapt/pmc.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ from pypmc.tools._linalg cimport bilinear_sym
from libc.math cimport exp, log
cimport numpy as _np

import logging
logger = logging.getLogger(__name__)

cdef _np.ndarray[double, ndim=2] calculate_rho_rb(_np.ndarray[double, ndim=2] samples,
density, live_components):
Expand Down Expand Up @@ -111,7 +113,7 @@ def _prepare_pmc_update(_np.ndarray[double, ndim=2] samples, weights, latent, mi
density.weights[k] = 0.
# when a component is pruned, the other weights must be renormalized
need_renormalize = True
print("Component %i died because of too few (%i) samples." %(k, count[k]))
logger.warning("Component %i died because of too few (%i) samples." %(k, count[k]))

return density, rho, weight_normalization, live_components, need_renormalize

Expand Down Expand Up @@ -232,7 +234,7 @@ def gaussian_pmc(_np.ndarray[double, ndim=2] samples not None, density,
try:
component.update(mu[k], cov[k])
except _np.linalg.LinAlgError:
print("Could not update component %i --> weight is set to zero." %k)
logger.warning("Could not update component %i --> weight is set to zero." %k)
component.update(old_mu, old_sigma)
density.weights[k] = 0.
# when a component is pruned, the other weights must be renormalized
Expand Down Expand Up @@ -440,17 +442,15 @@ class PMC(object):
# recompute bound in 1st step
else:
old_bound = self.log_likelihood()
if verbose:
print('New bound=%g, K=%i' % (old_bound,len(self.density)))
logger.info('New bound=%g, K=%i' % (old_bound,len(self.density)))

self.pmc(self.samples, self.density, self.weights, self.latent, self.rb, mincount=self.mincount, copy=False, **self.additional_args)
bound = self.log_likelihood()

if verbose:
print('After update %d: bound=%.15g, K=%i, component_weights=%s' % (i, bound, len(self.density), self.density.weights))
logger.info('After update %d: bound=%.15g, K=%i, component_weights=%s' % (i, bound, len(self.density), self.density.weights))

if bound < old_bound:
print('WARNING: bound decreased from %g to %g' % (old_bound, bound))
logger.warning('Bound decreased from %g to %g' % (old_bound, bound))

# exact convergence
if bound == old_bound:
Expand Down Expand Up @@ -695,7 +695,7 @@ def student_t_pmc(_np.ndarray[double, ndim=2] samples not None, density, weights
try:
new_dof[k] = _find_root(nu_condition, mindof, maxdof, maxiter=dof_solver_steps)
except RuntimeError: # occurs if not converged
print("WARNING: ``dof`` solver for component %i did not converge." % k)
logger.warning("``dof`` solver for component %i did not converge." % k)
new_dof[k] = density.components[k].dof
except ValueError as error:
# check if nu_condition has the same sign at mindof and maxdof
Expand Down Expand Up @@ -727,7 +727,7 @@ def student_t_pmc(_np.ndarray[double, ndim=2] samples not None, density, weights
try:
component.update(mu[k], cov[k], new_dof[k])
except _np.linalg.LinAlgError:
print("Could not update component %i --> weight is set to zero." % k)
logger.warning("Could not update component %i --> weight is set to zero." % k)
component.update(old_mu, old_sigma, old_dof)
density.weights[k] = 0.
# when a component is pruned, the other weights must be renormalized
Expand Down
20 changes: 10 additions & 10 deletions pypmc/mix_adapt/variational.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ cimport numpy as _np
from libc.math cimport exp, log
from pypmc.tools._linalg cimport bilinear_sym, chol_inv_det

import logging
logger = logging.getLogger(__name__)

DTYPE = _np.float64
ctypedef double DTYPE_t

Expand Down Expand Up @@ -161,13 +164,13 @@ class GaussianInference(object):
# because in that case \frac{\alpha_k - 1}{normalization} > 0
pi = self.alpha[k] - 1.
if pi <= 0:
print("Skipped component %i because of zero weight" %k)
logger.warning("Skipped component %i because of zero weight" %k)
skipped.append(k)
continue

# Gauss-Wishart mode
if self.nu[k] <= self.dim:
print("WARNING: Gauss-Wishart mode of component %i is not defined" %k)
logger.warning("Gauss-Wishart mode of component %i is not defined" %k)
skipped.append(k)
continue

Expand All @@ -176,16 +179,15 @@ class GaussianInference(object):
cov = chol_inv_det(W)[1]
components.append(Gauss(self.m[k], cov))
except Exception as error:
print("ERROR: Could not create component %i." %k)
print("The error was:", repr(error) )
logger.error("Could not create component %i. The error was: %s" %(k, repr(error)))
skipped.append(k)
continue

# relative weight properly normalized
weights.append(pi)

if skipped:
print("The following components have been skipped:", skipped)
logger.warning("The following components have been skipped:", skipped)

return MixtureDensity(components, weights)

Expand Down Expand Up @@ -324,17 +326,15 @@ class GaussianInference(object):
old_bound = bound
else:
old_bound = self.likelihood_bound()
if verbose:
print('New bound=%g, K=%d, N_k=%s' % (old_bound, self.K, self.N_comp))
logger.info('New bound=%g, K=%d, N_k=%s' % (old_bound, self.K, self.N_comp))

self.update()
bound = self.likelihood_bound()

if verbose:
print('After update %d: bound=%.15g, K=%d, N_k=%s' % (i, bound, self.K, self.N_comp))
logger.info('After update %d: bound=%.15g, K=%d, N_k=%s' % (i, bound, self.K, self.N_comp))

if bound < old_bound:
print('WARNING: bound decreased from %g to %g' % (old_bound, bound))
logger.warning('Bound decreased from %g to %g' % (old_bound, bound))

# exact convergence
if bound == old_bound:
Expand Down
9 changes: 6 additions & 3 deletions pypmc/sampler/markov_chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
from ..tools.indicator import merge_function_with_indicator as _indmerge
from ..tools._doc import _inherit_docstring

import logging
logger = logging.getLogger(__name__)

class MarkovChain(object):
r"""A Markov chain to generate samples from the target density.
Expand Down Expand Up @@ -375,15 +378,15 @@ def adapt(self):
try:
self.proposal.update(scaled_sigma)
except _np.linalg.LinAlgError:
print("WARNING: Markov chain self adaptation failed; trying diagonalization ... ", end='')
logger.warning("Markov chain self adaptation failed; trying diagonalization")
# try to insert offdiagonal elements only
diagonal_matrix = _np.zeros_like(scaled_sigma)
_np.fill_diagonal(diagonal_matrix, _np.diag(scaled_sigma))
try:
self.proposal.update(diagonal_matrix)
print('success')
logger.warning('Diagonalization succeeded')
except _np.linalg.LinAlgError:
print('fail')
logger.warning('Diagonalization failed')
# just scale the old covariance matrix if everything else fails
self.proposal.update(self.proposal.sigma / self.covar_scale_multiplier)

Expand Down
14 changes: 7 additions & 7 deletions pypmc/tools/_partition.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
from ..density.gauss import Gauss
from ..density.mixture import MixtureDensity

import logging
logger = logging.getLogger(__name__)

def partition(N, k):
'''Distribute ``N`` into ``k`` parts such that each part
takes the value ``N//k`` or ``N//k + 1`` where ``//`` denotes integer
Expand Down Expand Up @@ -65,25 +68,22 @@ def patch_data(data, L=100, try_diag=True, verbose=False):
this_comp = Gauss(mean, cov)
components.append(this_comp)
except _np.linalg.LinAlgError as error1:
if verbose:
print("Could not form Gauss from patch %i. Reason: %s" % (i, repr(error1)))
logger.info("Could not form Gauss from patch %i. Reason: %s" % (i, repr(error1)))
if try_diag:
cov = _np.diag(_np.diag(cov))
try:
this_comp = Gauss(mean, cov)
components.append(this_comp)
if verbose:
print('Diagonal covariance attempt succeeded.')
logger.info('Diagonal covariance attempt succeeded.')
except _np.linalg.LinAlgError as error2:
skipped.append(i)
if verbose:
print("Diagonal covariance attempt failed. Reason: %s" % repr(error2))
logger.info("Diagonal covariance attempt failed. Reason: %s" % repr(error2))
else: # if not try_diag
skipped.append(i)

# print skipped components if any
if skipped:
print("WARNING: Could not form Gaussians from: %s" % skipped)
logger.warning("Could not form Gaussians from: %s" % skipped)

# create and return mixture
return MixtureDensity(components)

0 comments on commit a995062

Please sign in to comment.