class_docstr: Low dimensional projection of a term-document matrix.
  
  This is the class taking care of the 'core math': interfacing with corpora, splitting large corpora into chunks
  and merging them etc. This done through the higher-level :class:`~gensim.models.lsimodel.LsiModel` class.
  
  Notes
  -----
  The projection can be later updated by merging it with another :class:`~gensim.models.lsimodel.Projection`
  via  :meth:`~gensim.models.lsimodel.Projection.merge`. This is how incremental training actually happens.
class_docstr_tok: ["Low","dimensional","projection","of","a","term-document","matrix",".","This","is","the","class","taking","care","of","the","'core","math","'",":","interfacing","with","corpora",",","splitting","large","corpora","into","chunks","and","merging","them","etc",".","This","done","through","the","higher-level",":","class",":","`","~gensim.models.lsimodel.LsiModel","`","class",".","Notes","--","--","-","The","projection","can","be","later","updated","by","merging","it","with","another",":","class",":","`","~gensim.models.lsimodel.Projection","`","via",":","meth",":","`","~gensim.models.lsimodel.Projection.merge","`",".","This","is","how","incremental","training","actually","happens","."]
docstr: Merge current :class:`~gensim.models.lsimodel.Projection` instance with another.
  
  Warnings
  --------
  The content of `other` is destroyed in the process, so pass this function a copy of `other`
  if you need it further. The `other` :class:`~gensim.models.lsimodel.Projection` is expected to contain
  the same number of features.
  
  Parameters
  ----------
  other : :class:`~gensim.models.lsimodel.Projection`
      The Projection object to be merged into the current one. It will be destroyed after merging.
  decay : float, optional
      Weight of existing observations relatively to new ones.
      Setting `decay` < 1.0 causes re-orientation towards new data trends in the input document stream,
      by giving less emphasis to old observations. This allows LSA to gradually "forget" old observations
      (documents) and give more preference to new ones.
docstr_tok: ["Merge","current",":","class",":","`","~gensim.models.lsimodel.Projection","`","instance","with","another",".","Warnings","--","--","--","--","The","content","of","`","other","`","is","destroyed","in","the","process",",","so","pass","this","function","a","copy","of","`","other","`","if","you","need","it","further",".","The","`","other","`",":","class",":","`","~gensim.models.lsimodel.Projection","`","is","expected","to","contain","the","same","number","of","features",".","Parameters","--","--","--","--","--","other",":",":","class",":","`","~gensim.models.lsimodel.Projection","`","The","Projection","object","to","be","merged","into","the","current","one",".","It","will","be","destroyed","after","merging",".","decay",":","float",",","optional","Weight","of","existing","observations","relatively","to","new","ones",".","Setting","`","decay","`","<","1.0","causes","re-orientation","towards","new","data","trends","in","the","input","document","stream",",","by","giving","less","emphasis","to","old","observations",".","This","allows","LSA","to","gradually","``","forget","''","old","observations","(","documents",")","and","give","more","preference","to","new","ones","."]
code: def merge(self, other, decay=1.0):
      """Merge current :class:`~gensim.models.lsimodel.Projection` instance with another.
  
      Warnings
      --------
      The content of `other` is destroyed in the process, so pass this function a copy of `other`
      if you need it further. The `other` :class:`~gensim.models.lsimodel.Projection` is expected to contain
      the same number of features.
  
      Parameters
      ----------
      other : :class:`~gensim.models.lsimodel.Projection`
          The Projection object to be merged into the current one. It will be destroyed after merging.
      decay : float, optional
          Weight of existing observations relatively to new ones.
          Setting `decay` < 1.0 causes re-orientation towards new data trends in the input document stream,
          by giving less emphasis to old observations. This allows LSA to gradually "forget" old observations
          (documents) and give more preference to new ones.
  
      """
      if other.u is None:
          # the other projection is empty => do nothing
          return
      if self.u is None:
          # we are empty => result of merge is the other projection, whatever it is
          self.u = other.u.copy()
          self.s = other.s.copy()
          return
      if self.m != other.m:
          raise ValueError(
              "vector space mismatch: update is using %s features, expected %s"
              % (other.m, self.m)
          )
      logger.info(
          "merging projections: %s + %s",
          str(self.u.shape),
          str(other.u.shape),
      )
      m, n1, n2 = self.u.shape[0], self.u.shape[1], other.u.shape[1]
      # TODO Maybe keep the bases as elementary reflectors, without
      # forming explicit matrices with ORGQR.
      # The only operation we ever need is basis^T*basis ond basis*component.
      # But how to do that in scipy? And is it fast(er)?
  
      # find component of u2 orthogonal to u1
      logger.debug("constructing orthogonal component")
      self.u = asfarray(self.u, "self.u")
      c = np.dot(self.u.T, other.u)
      self.u = ascarray(self.u, "self.u")
      other.u -= np.dot(self.u, c)
  
      other.u = [
          other.u
      ]  # do some reference magic and call qr_destroy, to save RAM
      q, r = matutils.qr_destroy(other.u)  # q, r = QR(component)
      assert not other.u
  
      # find the rotation that diagonalizes r
      k = np.bmat(
          [
              [np.diag(decay * self.s), np.multiply(c, other.s)],
              [
                  matutils.pad(
                      np.array([]).reshape(0, 0), min(m, n2), n1
                  ),
                  np.multiply(r, other.s),
              ],
          ]
      )
      logger.debug("computing SVD of %s dense matrix", k.shape)
      try:
          # in np < 1.1.0, running SVD sometimes results in "LinAlgError: SVD did not converge'.
          # for these early versions of np, catch the error and try to compute
          # SVD again, but over k*k^T.
          # see http://www.mail-archive.com/np-discussion@scipy.org/msg07224.html and
          # bug ticket http://projects.scipy.org/np/ticket/706
          # sdoering: replaced np's linalg.svd with scipy's linalg.svd:
  
          # TODO *ugly overkill*!! only need first self.k SVD factors... but there is no LAPACK wrapper
          # for partial svd/eigendecomp in np :( //sdoering: maybe there is one in scipy?
          u_k, s_k, _ = scipy.linalg.svd(k, full_matrices=False)
      except scipy.linalg.LinAlgError:
          logger.error("SVD(A) failed; trying SVD(A * A^T)")
          # if this fails too, give up with an exception
          u_k, s_k, _ = scipy.linalg.svd(
              np.dot(k, k.T), full_matrices=False
          )
          s_k = np.sqrt(
              s_k
          )  # go back from eigen values to singular values
  
      k = clip_spectrum(s_k**2, self.k)
      u1_k, u2_k, s_k = (
          np.array(u_k[:n1, :k]),
          np.array(u_k[n1:, :k]),
          s_k[:k],
      )
  
      # update & rotate current basis U = [U, U']*[U1_k, U2_k]
      logger.debug("updating orthonormal basis U")
      self.s = s_k
      self.u = ascarray(self.u, "self.u")
      self.u = np.dot(self.u, u1_k)
  
      q = ascarray(q, "q")
      q = np.dot(q, u2_k)
      self.u += q
  
      # make each column of U start with a non-negative number (to force canonical decomposition)
      if self.u.shape[0] > 0:
          for i in range(self.u.shape[1]):
              if self.u[0, i] < 0.0:
                  self.u[:, i] *= -1.0
  
imports: import logging
  import sys
  import time
  import numpy
  import scipy.linalg
  import scipy.sparse
  from scipy.sparse import sparsetools
  from gensim import interfaces, matutils, utils
  from gensim.models import basemodel
  from gensim.utils import is_empty
label_desc: Use image node_id 3 for calling the Projection obj's underlying member method code with example usage: obj.merge(other, decay) without return types