# Path: csc/divisi/ccipca.py
# class CCIPCA(object):
#     """A Candid Covariance-free Incremental Principal Component Analysis implementation"""
# 
#     def __init__(self, k, ev=None, i=0, bootstrap=20, amnesia=3.0, remembrance=100000.0, auto_baseline=True):
#         """Construct a CCIPCA computation with k initial eigenvectors ev at iteration i, using simple averaging until the iteration given by bootstrap, afterward using CCIPCA given amnesic parameter amnesia, rememberance parameter remembrance, and a weight vector and subspace criteria for simultaneous vector presentation"""
#         if ev is not None: self._v = ev
#         else: self._v = [zerovec() for iter in xrange(k)]
# 
#         self._k = k
#         self._amnesia = amnesia
#         self._iteration = i
#         self._bootstrap = bootstrap
#         self._remembrance = remembrance
#         self._auto_baseline = auto_baseline
# 
#     def compute_attractor(self, k, u, v_hat=None):
#         """Compute the attractor vector for eigenvector k with vector u"""
# 
#         if k == 0: return u
#         if v_hat is None: v_hat = self._v[k].hat()
#         partial = u * (u * v_hat)
#         return partial
# 
#     def update_eigenvector(self, k, u, learn=False):
#         """Update eigenvector k with vector u, returning pair
#         containing magnitude of eigenvector component and residue vector"""
#         if learn:
#             # Handle elementary cases
#             if self._iteration < k:
#                 return 0.0, zerovec()
# 
#             if self._iteration == k:
#                 self._v[k] = make_sparse_labeled_tensor(1, initial=u)
#                 mag = self._v[k].norm()
#                 return mag, zerovec()
# 
#             # Compute weighting factors
#             n = min(self._iteration, self._remembrance)
#             if n < self._bootstrap:
#                 w_old = float(n - 1) / n
#                 w_new = 1.0 / n
#             else:
#                 l = self._amnesia
#                 w_old = float(n - l) / n
#                 w_new = float(l) / n
# 
#             # Compute the attractor
#             attractor = self.compute_attractor(k, u)
# 
#             # Approach attractor
#             self._v[k] *= w_old
#             self._v[k] += attractor * w_new
# 
#         # Calculate component magnitudes
#         v_hat = self._v[k].hat()
#         if k == 0:
#             if self._auto_baseline: base_mag = self._v[k].norm()
#             else: base_mag = 0.0
#         else: base_mag = u * v_hat
# 
#         u_residue = u - (v_hat * base_mag)
#         if k == 0:
#             logger.debug('e0: %s' % str(self._v[k]))
#             logger.debug('u: %s' % str(u))
#             if learn:
#                 logger.debug('attractor: %s' % str(attractor))
#             logger.debug('residue: %s' % str(u_residue))
#             logger.debug('')
#         return base_mag, u_residue
# 
#     def iteration(self, u, learn=False):
#         """Train the eigenvector table with new vector u"""
#         print "iteration = ", self._iteration
#         mags = []
#         u_copy = make_sparse_labeled_tensor(1, initial=u)   # copy
#         for k in xrange(min(self._k, self._iteration+1)):
#             mag, new_u = self.update_eigenvector(k, u_copy, learn)
#             u_copy = new_u
#             mags.append(mag)
#         if learn:
#             self._iteration += 1
#             self._v[1:] = sorted(self._v[1:], reverse=True, key=lambda v: v.norm())
#         return mags
# 
#     def reconstruct(self, weights):
#         # Create a linear combination of the eigenvectors
#         sum = zerovec()
#         for index, w in enumerate(weights):
#             sum += self._v[index].hat() * w
#         return sum
# 
#     def smooth(self, u, k_max=None, learn=False):
#         mags = self.iteration(u, learn)
#         if k_max is not None:
#             mags = mags[:k_max]
#         vec = self.reconstruct(mags)
#         if not learn:
#             logger.debug("decomp: %s" % str(mags))
#         return vec
# 
# def zerovec():
#     return make_sparse_labeled_tensor(1)
# 
# Path: csc/divisi/labeled_view.py
# def make_dense_labeled_tensor(data, labels):
#     return LabeledView(DenseTensor(data), labels)


from csc.divisi.ccipca import CCIPCA, zerovec
from csc.divisi.labeled_view import make_dense_labeled_tensor
from random import random
from math import sqrt
import numpy

VEC_LEN = 16
VEC_COUNT = 4
ITERS = 1024
MAG_MAX = 100.0
K=6

# Prepare test vectors
vecs = [numpy.array([random() for i in range(VEC_LEN)]) for j in range(VEC_COUNT)]

# Path: csc/divisi/ccipca.py
# class CCIPCA(object):
#     """A Candid Covariance-free Incremental Principal Component Analysis implementation"""
# 
#     def __init__(self, k, ev=None, i=0, bootstrap=20, amnesia=3.0, remembrance=100000.0, auto_baseline=True):
#         """Construct a CCIPCA computation with k initial eigenvectors ev at iteration i, using simple averaging until the iteration given by bootstrap, afterward using CCIPCA given amnesic parameter amnesia, rememberance parameter remembrance, and a weight vector and subspace criteria for simultaneous vector presentation"""
#         if ev is not None: self._v = ev
#         else: self._v = [zerovec() for iter in xrange(k)]
# 
#         self._k = k
#         self._amnesia = amnesia
#         self._iteration = i
#         self._bootstrap = bootstrap
#         self._remembrance = remembrance
#         self._auto_baseline = auto_baseline
# 
#     def compute_attractor(self, k, u, v_hat=None):
#         """Compute the attractor vector for eigenvector k with vector u"""
# 
#         if k == 0: return u
#         if v_hat is None: v_hat = self._v[k].hat()
#         partial = u * (u * v_hat)
#         return partial
# 
#     def update_eigenvector(self, k, u, learn=False):
#         """Update eigenvector k with vector u, returning pair
#         containing magnitude of eigenvector component and residue vector"""
#         if learn:
#             # Handle elementary cases
#             if self._iteration < k:
#                 return 0.0, zerovec()
# 
#             if self._iteration == k:
#                 self._v[k] = make_sparse_labeled_tensor(1, initial=u)
#                 mag = self._v[k].norm()
#                 return mag, zerovec()
# 
#             # Compute weighting factors
#             n = min(self._iteration, self._remembrance)
#             if n < self._bootstrap:
#                 w_old = float(n - 1) / n
#                 w_new = 1.0 / n
#             else:
#                 l = self._amnesia
#                 w_old = float(n - l) / n
#                 w_new = float(l) / n
# 
#             # Compute the attractor
#             attractor = self.compute_attractor(k, u)
# 
#             # Approach attractor
#             self._v[k] *= w_old
#             self._v[k] += attractor * w_new
# 
#         # Calculate component magnitudes
#         v_hat = self._v[k].hat()
#         if k == 0:
#             if self._auto_baseline: base_mag = self._v[k].norm()
#             else: base_mag = 0.0
#         else: base_mag = u * v_hat
# 
#         u_residue = u - (v_hat * base_mag)
#         if k == 0:
#             logger.debug('e0: %s' % str(self._v[k]))
#             logger.debug('u: %s' % str(u))
#             if learn:
#                 logger.debug('attractor: %s' % str(attractor))
#             logger.debug('residue: %s' % str(u_residue))
#             logger.debug('')
#         return base_mag, u_residue
# 
#     def iteration(self, u, learn=False):
#         """Train the eigenvector table with new vector u"""
#         print "iteration = ", self._iteration
#         mags = []
#         u_copy = make_sparse_labeled_tensor(1, initial=u)   # copy
#         for k in xrange(min(self._k, self._iteration+1)):
#             mag, new_u = self.update_eigenvector(k, u_copy, learn)
#             u_copy = new_u
#             mags.append(mag)
#         if learn:
#             self._iteration += 1
#             self._v[1:] = sorted(self._v[1:], reverse=True, key=lambda v: v.norm())
#         return mags
# 
#     def reconstruct(self, weights):
#         # Create a linear combination of the eigenvectors
#         sum = zerovec()
#         for index, w in enumerate(weights):
#             sum += self._v[index].hat() * w
#         return sum
# 
#     def smooth(self, u, k_max=None, learn=False):
#         mags = self.iteration(u, learn)
#         if k_max is not None:
#             mags = mags[:k_max]
#         vec = self.reconstruct(mags)
#         if not learn:
#             logger.debug("decomp: %s" % str(mags))
#         return vec
# 
# def zerovec():
#     return make_sparse_labeled_tensor(1)
# 
# Path: csc/divisi/labeled_view.py
# def make_dense_labeled_tensor(data, labels):
#     return LabeledView(DenseTensor(data), labels)


# Path: doc/demo/ccipca_demo.py
from csc.divisi.ccipca import CCIPCA, zerovec
from csc.divisi.labeled_view import make_dense_labeled_tensor
from random import random
from math import sqrt
import numpy


VEC_LEN = 16
VEC_COUNT = 4
ITERS = 1024
MAG_MAX = 100.0
K=6

# Prepare test vectors
vecs = [numpy.array([random() for i in range(VEC_LEN)]) for j in range(VEC_COUNT)]

vecs = [make_dense_labeled_tensor(v, None).to_sparse() for v in vecs]