text: # -*- coding: utf-8 -*-
  # New BSD License
  #
  # Copyright (c) 2007–2018 The scikit-learn developers.
  # All rights reserved.
  #
  #
  # Redistribution and use in source and binary forms, with or without
  # modification, are permitted provided that the following conditions are met:
  #
  #   a. Redistributions of source code must retain the above copyright notice,
  #      this list of conditions and the following disclaimer.
  #   b. Redistributions in binary form must reproduce the above copyright
  #      notice, this list of conditions and the following disclaimer in the
  #      documentation and/or other materials provided with the distribution.
  #   c. Neither the name of the Scikit-learn Developers  nor the names of
  #      its contributors may be used to endorse or promote products
  #      derived from this software without specific prior written
  #      permission.
  #
  #
  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
  # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  # DAMAGE.
  """Base estimator class from sklearn."""
  
  from collections import defaultdict  # pylint: disable=wrong-import-order
  
  import numpy
  
  try:
      from inspect import signature  # pylint: disable=wrong-import-order
  except ImportError:
      from cleanset.funcsigs import signature
  
  
  class BaseEstimator:
      """Base class for estimators from sklearn.
  
      The class is consistent with sklearn estimator API:
  
      All estimator objects expose a ``fit`` method that takes a dataset
      (usually a 2-d array):
  
      >>> estimator.fit(data)
  
      **Estimator parameters**: All the parameters of an estimator can be set
      when it is instantiated or by modifying the corresponding attribute::
  
      >>> estimator = Estimator(param1=1, param2=2)
      >>> estimator.param1
      1
  
      **Estimated parameters**: When data is fitted with an estimator,
      parameters are estimated from the data at hand. All the estimated
      parameters are attributes of the estimator object ending by an
      underscore::
  
      >>> estimator.estimated_param_ #doctest: +SKIP
      """
  
      @classmethod
      def _get_param_names(cls):
          """Get parameter names for the estimator"""
          # fetch the constructor or the original constructor before
          # deprecation wrapping if any
          init = getattr(cls.__init__, 'deprecated_original', cls.__init__)
          if init is object.__init__:
              # No explicit constructor to introspect
              return []
  
          # introspect the constructor arguments to find the model parameters
          # to represent
          init_signature = signature(init)
          # Consider the constructor parameters excluding 'self'
          parameters = [
              p for p in init_signature.parameters.values()
              if p.name != 'self' and p.kind != p.VAR_KEYWORD
          ]
          for p in parameters:
              if p.kind == p.VAR_POSITIONAL:
                  raise RuntimeError('scikit-learn estimators should always '
                                     'specify their parameters in the signature'
                                     ' of their __init__ (no varargs).'
                                     " %s with constructor %s doesn't "
                                     ' follow this convention.' %
                                     (cls, init_signature))
          # Extract and sort argument names excluding 'self'
          return sorted([p.name for p in parameters])
  
      def get_params(self, deep=True):
          """Get parameters for this estimator.
          Parameters
          ----------
          deep : boolean, optional
              If True, will return the parameters for this estimator and
              contained subobjects that are estimators.
          Returns
          -------
          params : mapping of string to any
              Parameter names mapped to their values.
          """
          out = dict()
          for key in self._get_param_names():
              value = getattr(self, key, None)
              if deep and hasattr(value, 'get_params'):
                  deep_items = value.get_params().items()
                  out.update((key + '__' + k, val) for k, val in deep_items)
              out[key] = value
          return out
  
      def set_params(self, **params):
          """Set the parameters of this estimator.
          The method works on simple estimators as well as on nested objects
          (such as pipelines). The latter have parameters of the form
          ``<component>__<parameter>`` so that it's possible to update each
          component of a nested object.
          Returns
          -------
          self
          """
          if not params:
              # Simple optimization to gain speed (inspect is slow)
              return self
          valid_params = self.get_params(deep=True)
  
          nested_params = defaultdict(dict)  # grouped by prefix
          for key, value in params.items():
              key, delim, sub_key = key.partition('__')
              if key not in valid_params:
                  raise ValueError('Invalid parameter %s for estimator %s. '
                                   'Check the list of available parameters '
                                   'with `estimator.get_params().keys()`.' %
                                   (key, self))
  
              if delim:
                  nested_params[key][sub_key] = value
              else:
                  setattr(self, key, value)
                  valid_params[key] = value
  
          for key, sub_params in nested_params.items():
              valid_params[key].set_params(**sub_params)
  
          return self
  
      def __repr__(self):
          class_name = self.__class__.__name__
          return '%s(%s)' % (
              class_name,
              _pprint(
                  self.get_params(deep=False),
                  offset=len(class_name),
              ),
          )
  
      def __getstate__(self):
          try:
              state = super().__getstate__()
          except AttributeError:
              state = self.__dict__.copy()
          return state
  
      def __setstate__(self, state):
          try:
              super().__setstate__(state)
          except AttributeError:
              self.__dict__.update(state)
  
  
  class TransformerMixin:  # pylint: disable=too-few-public-methods
      """Mixin class for all transformers in scikit-learn."""
  
      def fit_transform(self, X, y=None, **fit_params):
          """Fit to data, then transform it.
          Fits transformer to X and y with optional parameters fit_params
          and returns a transformed version of X.
          Parameters
          ----------
          X : numpy array of shape [n_samples, n_features]
              Training set.
          y : numpy array of shape [n_samples]
              Target values.
          Returns
          -------
          X_new : numpy array of shape [n_samples, n_features_new]
              Transformed array.
          """
          # non-optimized default implementation; override when a better
          # method is possible for a given clustering algorithm
          if y is None:
              # fit method of arity 1 (unsupervised transformation)
              return self.fit(X, **fit_params).transform(X)
  
          # fit method of arity 2 (supervised transformation)
          return self.fit(X, y, **fit_params).transform(X)
  
  
  def _pprint(params, offset=0, printer=repr):
      """Pretty print the dictionary 'params'
      Parameters
      ----------
      params : dict
          The dictionary to pretty print
      offset : int
          The offset in characters to add at the begin of each line.
      printer : callable
          The function to convert entries to strings, typically
          the builtin str or repr
      """
      # Do a multi-line justified repr:
      options = numpy.get_printoptions()
      numpy.set_printoptions(precision=5, threshold=64, edgeitems=2)
      params_list = list()
      this_line_length = offset
      line_sep = ',\n' + (1 + offset // 2) * ' '
      for i, (k, v) in enumerate(sorted(params.items())):
          if isinstance(v, float):
              # use str for representing floating point numbers
              # this way we get consistent representation across
              # architectures and versions.
              this_repr = '%s=%s' % (k, str(v))
          else:
              # use repr of the rest
              this_repr = '%s=%s' % (k, printer(v))
          if len(this_repr) > 500:
              this_repr = this_repr[:300] + '...' + this_repr[-100:]
          if i > 0:
              if this_line_length + len(this_repr) >= 75 or '\n' in this_repr:
                  params_list.append(line_sep)
                  this_line_length = len(line_sep)
              else:
                  params_list.append(', ')
                  this_line_length += 2
          params_list.append(this_repr)
          this_line_length += len(this_repr)
  
      numpy.set_printoptions(**options)
      lines = ''.join(params_list)
      # Strip trailing space to avoid nightmare in doctests
      lines = '\n'.join(l.rstrip(' ') for l in lines.split('\n'))
      return lines
  