class_docstr: Train and use Online Latent Dirichlet Allocation model as presented in
  `'Online Learning for LDA' by Hoffman et al.`_
  
  Examples
  -------
  Initialize a model using a Gensim corpus
  
  .. sourcecode:: pycon
  
      >>> from gensim.test.utils import common_corpus
      >>>
      >>> lda = LdaModel(common_corpus, num_topics=10)
  
  You can then infer topic distributions on new, unseen documents.
  
  .. sourcecode:: pycon
  
      >>> doc_bow = [(1, 0.3), (2, 0.1), (0, 0.09)]
      >>> doc_lda = lda[doc_bow]
  
  The model can be updated (trained) with new documents.
  
  .. sourcecode:: pycon
  
      >>> # In practice (corpus =/= initial training corpus), but we use the same here for simplicity.
      >>> other_corpus = common_corpus
      >>>
      >>> lda.update(other_corpus)
  
  Model persistency is achieved through :meth:`~gensim.models.ldamodel.LdaModel.load` and
  :meth:`~gensim.models.ldamodel.LdaModel.save` methods.
class_docstr_tok: ["Train","and","use","Online","Latent","Dirichlet","Allocation","model","as","presented","in","`","'Online","Learning","for","LDA","'","by","Hoffman","et","al.","`","_","Examples","--","--","--","-","Initialize","a","model","using","a","Gensim","corpus","..","sourcecode",":",":","pycon",">",">",">","from","gensim.test.utils","import","common_corpus",">",">",">",">",">",">","lda","=","LdaModel","(","common_corpus",",","num_topics=10",")","You","can","then","infer","topic","distributions","on","new",",","unseen","documents",".","..","sourcecode",":",":","pycon",">",">",">","doc_bow","=","[","(","1",",","0.3",")",",","(","2",",","0.1",")",",","(","0",",","0.09",")","]",">",">",">","doc_lda","=","lda","[","doc_bow","]","The","model","can","be","updated","(","trained",")","with","new","documents",".","..","sourcecode",":",":","pycon",">",">",">","#","In","practice","(","corpus","=\/=","initial","training","corpus",")",",","but","we","use","the","same","here","for","simplicity",".",">",">",">","other_corpus","=","common_corpus",">",">",">",">",">",">","lda.update","(","other_corpus",")","Model","persistency","is","achieved","through",":","meth",":","`","~gensim.models.ldamodel.LdaModel.load","`","and",":","meth",":","`","~gensim.models.ldamodel.LdaModel.save","`","methods","."]
docstr: Parameters
  ----------
  corpus : iterable of list of (int, float), optional
      Stream of document vectors or sparse matrix of shape (`num_documents`, `num_terms`).
      If you have a CSC in-memory matrix, you can convert it to a
      streamed corpus with the help of gensim.matutils.Sparse2Corpus.
      If not given, the model is left untrained (presumably because you want to call
      :meth:`~gensim.models.ldamodel.LdaModel.update` manually).
  num_topics : int, optional
      The number of requested latent topics to be extracted from the training corpus.
  id2word : {dict of (int, str), :class:`gensim.corpora.dictionary.Dictionary`}
      Mapping from word IDs to words. It is used to determine the vocabulary size, as well as for
      debugging and topic printing.
  distributed : bool, optional
      Whether distributed computing should be used to accelerate training.
  chunksize :  int, optional
      Number of documents to be used in each training chunk.
  passes : int, optional
      Number of passes through the corpus during training.
  update_every : int, optional
      Number of documents to be iterated through for each update.
      Set to 0 for batch learning, > 1 for online iterative learning.
  alpha : {float, numpy.ndarray of float, list of float, str}, optional
      A-priori belief on document-topic distribution, this can be:
          * scalar for a symmetric prior over document-topic distribution,
          * 1D array of length equal to num_topics to denote an asymmetric user defined prior for each topic.
  
      Alternatively default prior selecting strategies can be employed by supplying a string:
          * 'symmetric': (default) Uses a fixed symmetric prior of `1.0 / num_topics`,
          * 'asymmetric': Uses a fixed normalized asymmetric prior of `1.0 / (topic_index + sqrt(num_topics))`,
          * 'auto': Learns an asymmetric prior from the corpus (not available if `distributed==True`).
  eta : {float, numpy.ndarray of float, list of float, str}, optional
      A-priori belief on topic-word distribution, this can be:
          * scalar for a symmetric prior over topic-word distribution,
          * 1D array of length equal to num_words to denote an asymmetric user defined prior for each word,
          * matrix of shape (num_topics, num_words) to assign a probability for each word-topic combination.
  
      Alternatively default prior selecting strategies can be employed by supplying a string:
          * 'symmetric': (default) Uses a fixed symmetric prior of `1.0 / num_topics`,
          * 'auto': Learns an asymmetric prior from the corpus.
  decay : float, optional
      A number between (0.5, 1] to weight what percentage of the previous lambda value is forgotten
      when each new document is examined.
      Corresponds to :math:`\kappa` from `'Online Learning for LDA' by Hoffman et al.`_
  offset : float, optional
      Hyper-parameter that controls how much we will slow down the first steps the first few iterations.
      Corresponds to :math:`\tau_0` from `'Online Learning for LDA' by Hoffman et al.`_
  eval_every : int, optional
      Log perplexity is estimated every that many updates. Setting this to one slows down training by ~2x.
  iterations : int, optional
      Maximum number of iterations through the corpus when inferring the topic distribution of a corpus.
  gamma_threshold : float, optional
      Minimum change in the value of the gamma parameters to continue iterating.
  minimum_probability : float, optional
      Topics with a probability lower than this threshold will be filtered out.
  random_state : {np.random.RandomState, int}, optional
      Either a randomState object or a seed to generate one. Useful for reproducibility.
  ns_conf : dict of (str, object), optional
      Key word parameters propagated to :func:`gensim.utils.getNS` to get a Pyro4 nameserver.
      Only used if `distributed` is set to True.
  minimum_phi_value : float, optional
      if `per_word_topics` is True, this represents a lower bound on the term probabilities.
  per_word_topics : bool
      If True, the model also computes a list of topics, sorted in descending order of most likely topics for
      each word, along with their phi values multiplied by the feature length (i.e. word count).
  callbacks : list of :class:`~gensim.models.callbacks.Callback`
      Metric callbacks to log and visualize evaluation metrics of the model during training.
  dtype : {numpy.float16, numpy.float32, numpy.float64}, optional
      Data-type to use during calculations inside model. All inputs are also converted.
docstr_tok: ["Parameters","--","--","--","--","--","corpus",":","iterable","of","list","of","(","int",",","float",")",",","optional","Stream","of","document","vectors","or","sparse","matrix","of","shape","(","`","num_documents","`",",","`","num_terms","`",")",".","If","you","have","a","CSC","in-memory","matrix",",","you","can","convert","it","to","a","streamed","corpus","with","the","help","of","gensim.matutils.Sparse2Corpus",".","If","not","given",",","the","model","is","left","untrained","(","presumably","because","you","want","to","call",":","meth",":","`","~gensim.models.ldamodel.LdaModel.update","`","manually",")",".","num_topics",":","int",",","optional","The","number","of","requested","latent","topics","to","be","extracted","from","the","training","corpus",".","id2word",":","{","dict","of","(","int",",","str",")",",",":","class",":","`","gensim.corpora.dictionary.Dictionary","`","}","Mapping","from","word","IDs","to","words",".","It","is","used","to","determine","the","vocabulary","size",",","as","well","as","for","debugging","and","topic","printing",".","distributed",":","bool",",","optional","Whether","distributed","computing","should","be","used","to","accelerate","training",".","chunksize",":","int",",","optional","Number","of","documents","to","be","used","in","each","training","chunk",".","passes",":","int",",","optional","Number","of","passes","through","the","corpus","during","training",".","update_every",":","int",",","optional","Number","of","documents","to","be","iterated","through","for","each","update",".","Set","to","0","for","batch","learning",",",">","1","for","online","iterative","learning",".","alpha",":","{","float",",","numpy.ndarray","of","float",",","list","of","float",",","str","}",",","optional","A-priori","belief","on","document-topic","distribution",",","this","can","be",":","*","scalar","for","a","symmetric","prior","over","document-topic","distribution",",","*","1D","array","of","length","equal","to","num_topics","to","denote","an","asymmetric","user","defined","prior","for","each","topic",".","Alternatively","default","prior","selecting","strategies","can","be","employed","by","supplying","a","string",":","*","'symmetric","'",":","(","default",")","Uses","a","fixed","symmetric","prior","of","`","1.0","\/","num_topics","`",",","*","'asymmetric","'",":","Uses","a","fixed","normalized","asymmetric","prior","of","`","1.0","\/","(","topic_index","+","sqrt","(","num_topics",")",")","`",",","*","'auto","'",":","Learns","an","asymmetric","prior","from","the","corpus","(","not","available","if","`","distributed==True","`",")",".","eta",":","{","float",",","numpy.ndarray","of","float",",","list","of","float",",","str","}",",","optional","A-priori","belief","on","topic-word","distribution",",","this","can","be",":","*","scalar","for","a","symmetric","prior","over","topic-word","distribution",",","*","1D","array","of","length","equal","to","num_words","to","denote","an","asymmetric","user","defined","prior","for","each","word",",","*","matrix","of","shape","(","num_topics",",","num_words",")","to","assign","a","probability","for","each","word-topic","combination",".","Alternatively","default","prior","selecting","strategies","can","be","employed","by","supplying","a","string",":","*","'symmetric","'",":","(","default",")","Uses","a","fixed","symmetric","prior","of","`","1.0","\/","num_topics","`",",","*","'auto","'",":","Learns","an","asymmetric","prior","from","the","corpus",".","decay",":","float",",","optional","A","number","between","(","0.5",",","1","]","to","weight","what","percentage","of","the","previous","lambda","value","is","forgotten","when","each","new","document","is","examined",".","Corresponds","to",":","math",":","`","\\kappa","`","from","`","'Online","Learning","for","LDA","'","by","Hoffman","et","al.","`","_","offset",":","float",",","optional","Hyper-parameter","that","controls","how","much","we","will","slow","down","the","first","steps","the","first","few","iterations",".","Corresponds","to",":","math",":","`","\\tau_0","`","from","`","'Online","Learning","for","LDA","'","by","Hoffman","et","al.","`","_","eval_every",":","int",",","optional","Log","perplexity","is","estimated","every","that","many","updates",".","Setting","this","to","one","slows","down","training","by","~2x",".","iterations",":","int",",","optional","Maximum","number","of","iterations","through","the","corpus","when","inferring","the","topic","distribution","of","a","corpus",".","gamma_threshold",":","float",",","optional","Minimum","change","in","the","value","of","the","gamma","parameters","to","continue","iterating",".","minimum_probability",":","float",",","optional","Topics","with","a","probability","lower","than","this","threshold","will","be","filtered","out",".","random_state",":","{","np.random.RandomState",",","int","}",",","optional","Either","a","randomState","object","or","a","seed","to","generate","one",".","Useful","for","reproducibility",".","ns_conf",":","dict","of","(","str",",","object",")",",","optional","Key","word","parameters","propagated","to",":","func",":","`","gensim.utils.getNS","`","to","get","a","Pyro4","nameserver",".","Only","used","if","`","distributed","`","is","set","to","True",".","minimum_phi_value",":","float",",","optional","if","`","per_word_topics","`","is","True",",","this","represents","a","lower","bound","on","the","term","probabilities",".","per_word_topics",":","bool","If","True",",","the","model","also","computes","a","list","of","topics",",","sorted","in","descending","order","of","most","likely","topics","for","each","word",",","along","with","their","phi","values","multiplied","by","the","feature","length","(","i.e",".","word","count",")",".","callbacks",":","list","of",":","class",":","`","~gensim.models.callbacks.Callback","`","Metric","callbacks","to","log","and","visualize","evaluation","metrics","of","the","model","during","training",".","dtype",":","{","numpy.float16",",","numpy.float32",",","numpy.float64","}",",","optional","Data-type","to","use","during","calculations","inside","model",".","All","inputs","are","also","converted","."]
code: def __init__(
      self,
      corpus=None,
      num_topics=100,
      id2word=None,
      distributed=False,
      chunksize=2000,
      passes=1,
      update_every=1,
      alpha="symmetric",
      eta=None,
      decay=0.5,
      offset=1.0,
      eval_every=10,
      iterations=50,
      gamma_threshold=0.001,
      minimum_probability=0.01,
      random_state=None,
      ns_conf=None,
      minimum_phi_value=0.01,
      per_word_topics=False,
      callbacks=None,
      dtype=np.float32,
  ):
      """
  
      Parameters
      ----------
      corpus : iterable of list of (int, float), optional
          Stream of document vectors or sparse matrix of shape (`num_documents`, `num_terms`).
          If you have a CSC in-memory matrix, you can convert it to a
          streamed corpus with the help of gensim.matutils.Sparse2Corpus.
          If not given, the model is left untrained (presumably because you want to call
          :meth:`~gensim.models.ldamodel.LdaModel.update` manually).
      num_topics : int, optional
          The number of requested latent topics to be extracted from the training corpus.
      id2word : {dict of (int, str), :class:`gensim.corpora.dictionary.Dictionary`}
          Mapping from word IDs to words. It is used to determine the vocabulary size, as well as for
          debugging and topic printing.
      distributed : bool, optional
          Whether distributed computing should be used to accelerate training.
      chunksize :  int, optional
          Number of documents to be used in each training chunk.
      passes : int, optional
          Number of passes through the corpus during training.
      update_every : int, optional
          Number of documents to be iterated through for each update.
          Set to 0 for batch learning, > 1 for online iterative learning.
      alpha : {float, numpy.ndarray of float, list of float, str}, optional
          A-priori belief on document-topic distribution, this can be:
              * scalar for a symmetric prior over document-topic distribution,
              * 1D array of length equal to num_topics to denote an asymmetric user defined prior for each topic.
  
          Alternatively default prior selecting strategies can be employed by supplying a string:
              * 'symmetric': (default) Uses a fixed symmetric prior of `1.0 / num_topics`,
              * 'asymmetric': Uses a fixed normalized asymmetric prior of `1.0 / (topic_index + sqrt(num_topics))`,
              * 'auto': Learns an asymmetric prior from the corpus (not available if `distributed==True`).
      eta : {float, numpy.ndarray of float, list of float, str}, optional
          A-priori belief on topic-word distribution, this can be:
              * scalar for a symmetric prior over topic-word distribution,
              * 1D array of length equal to num_words to denote an asymmetric user defined prior for each word,
              * matrix of shape (num_topics, num_words) to assign a probability for each word-topic combination.
  
          Alternatively default prior selecting strategies can be employed by supplying a string:
              * 'symmetric': (default) Uses a fixed symmetric prior of `1.0 / num_topics`,
              * 'auto': Learns an asymmetric prior from the corpus.
      decay : float, optional
          A number between (0.5, 1] to weight what percentage of the previous lambda value is forgotten
          when each new document is examined.
          Corresponds to :math:`\\kappa` from `'Online Learning for LDA' by Hoffman et al.`_
      offset : float, optional
          Hyper-parameter that controls how much we will slow down the first steps the first few iterations.
          Corresponds to :math:`\\tau_0` from `'Online Learning for LDA' by Hoffman et al.`_
      eval_every : int, optional
          Log perplexity is estimated every that many updates. Setting this to one slows down training by ~2x.
      iterations : int, optional
          Maximum number of iterations through the corpus when inferring the topic distribution of a corpus.
      gamma_threshold : float, optional
          Minimum change in the value of the gamma parameters to continue iterating.
      minimum_probability : float, optional
          Topics with a probability lower than this threshold will be filtered out.
      random_state : {np.random.RandomState, int}, optional
          Either a randomState object or a seed to generate one. Useful for reproducibility.
      ns_conf : dict of (str, object), optional
          Key word parameters propagated to :func:`gensim.utils.getNS` to get a Pyro4 nameserver.
          Only used if `distributed` is set to True.
      minimum_phi_value : float, optional
          if `per_word_topics` is True, this represents a lower bound on the term probabilities.
      per_word_topics : bool
          If True, the model also computes a list of topics, sorted in descending order of most likely topics for
          each word, along with their phi values multiplied by the feature length (i.e. word count).
      callbacks : list of :class:`~gensim.models.callbacks.Callback`
          Metric callbacks to log and visualize evaluation metrics of the model during training.
      dtype : {numpy.float16, numpy.float32, numpy.float64}, optional
          Data-type to use during calculations inside model. All inputs are also converted.
  
      """
      self.dtype = np.finfo(dtype).dtype
  
      # store user-supplied parameters
      self.id2word = id2word
      if corpus is None and self.id2word is None:
          raise ValueError(
              "at least one of corpus/id2word must be specified, to establish input space dimensionality"
          )
  
      if self.id2word is None:
          logger.warning(
              "no word id mapping provided; initializing from corpus, assuming identity"
          )
          self.id2word = utils.dict_from_corpus(corpus)
          self.num_terms = len(self.id2word)
      elif len(self.id2word) > 0:
          self.num_terms = 1 + max(self.id2word.keys())
      else:
          self.num_terms = 0
  
      if self.num_terms == 0:
          raise ValueError(
              "cannot compute LDA over an empty collection (no terms)"
          )
  
      self.distributed = bool(distributed)
      self.num_topics = int(num_topics)
      self.chunksize = chunksize
      self.decay = decay
      self.offset = offset
      self.minimum_probability = minimum_probability
      self.num_updates = 0
  
      self.passes = passes
      self.update_every = update_every
      self.eval_every = eval_every
      self.minimum_phi_value = minimum_phi_value
      self.per_word_topics = per_word_topics
      self.callbacks = callbacks
  
      self.alpha, self.optimize_alpha = self.init_dir_prior(
          alpha, "alpha"
      )
      assert self.alpha.shape == (
          self.num_topics,
      ), "Invalid alpha shape. Got shape %s, but expected (%d, )" % (
          str(self.alpha.shape),
          self.num_topics,
      )
  
      self.eta, self.optimize_eta = self.init_dir_prior(eta, "eta")
      assert self.eta.shape == (self.num_terms,) or self.eta.shape == (
          self.num_topics,
          self.num_terms,
      ), (
          "Invalid eta shape. Got shape %s, but expected (%d, 1) or (%d, %d)"
          % (
              str(self.eta.shape),
              self.num_terms,
              self.num_topics,
              self.num_terms,
          )
      )
  
      self.random_state = utils.get_random_state(random_state)
  
      # VB constants
      self.iterations = iterations
      self.gamma_threshold = gamma_threshold
  
      # set up distributed environment if necessary
      if not distributed:
          logger.info("using serial LDA version on this node")
          self.dispatcher = None
          self.numworkers = 1
      else:
          if self.optimize_alpha:
              raise NotImplementedError(
                  "auto-optimizing alpha not implemented in distributed LDA"
              )
          # set up distributed version
          try:
              import Pyro4
  
              if ns_conf is None:
                  ns_conf = {}
  
              with utils.getNS(**ns_conf) as ns:
                  from gensim.models.lda_dispatcher import (
                      LDA_DISPATCHER_PREFIX,
                  )
  
                  self.dispatcher = Pyro4.Proxy(
                      ns.list(prefix=LDA_DISPATCHER_PREFIX)[
                          LDA_DISPATCHER_PREFIX
                      ]
                  )
                  logger.debug(
                      "looking for dispatcher at %s"
                      % str(self.dispatcher._pyroUri)
                  )
                  self.dispatcher.initialize(
                      id2word=self.id2word,
                      num_topics=self.num_topics,
                      chunksize=chunksize,
                      alpha=alpha,
                      eta=eta,
                      distributed=False,
                  )
                  self.numworkers = len(self.dispatcher.getworkers())
                  logger.info(
                      "using distributed version with %i workers",
                      self.numworkers,
                  )
          except Exception as err:
              logger.error(
                  "failed to initialize distributed LDA (%s)", err
              )
              raise RuntimeError(
                  "failed to initialize distributed LDA (%s)" % err
              )
  
      # Initialize the variational distribution q(beta|lambda)
      self.state = LdaState(
          self.eta, (self.num_topics, self.num_terms), dtype=self.dtype
      )
      self.state.sstats[...] = self.random_state.gamma(
          100.0, 1.0 / 100.0, (self.num_topics, self.num_terms)
      )
      self.expElogbeta = np.exp(
          dirichlet_expectation(self.state.sstats)
      )
  
      # Check that we haven't accidentally fallen back to np.float64
      assert self.eta.dtype == self.dtype
      assert self.expElogbeta.dtype == self.dtype
  
      # if a training corpus was provided, start estimating the model right away
      if corpus is not None:
          use_numpy = self.dispatcher is not None
          start = time.time()
          self.update(corpus, chunks_as_numpy=use_numpy)
          self.add_lifecycle_event(
              "created",
              msg=f"trained {self} in {time.time() - start:.2f}s",
          )
  
imports: import logging
  import numbers
  import os
  import time
  from collections import defaultdict
  import numpy
  from scipy.special import gammaln, psi
  from scipy.special import polygamma
  from gensim import interfaces, utils, matutils
  from gensim.matutils import kullback_leibler, hellinger, jaccard_distance, jensen_shannon, dirichlet_expectation, logsumexp, mean_absolute_difference
  from gensim.models import basemodel, CoherenceModel
  from gensim.models.callbacks import Callback
label_desc: Use image node_id 1 to create a new LdaModel object from inherited base classes: interfaces, basemodel with example: obj = LdaModel(corpus, num_topics, id2word, distributed, chunksize, passes, update_every, alpha, eta, decay, offset, eval_every, iterations, gamma_threshold, minimum_probability, random_state, ns_conf, minimum_phi_value, per_word_topics, callbacks, dtype)