docs: def _update_beliefs(self, sending_clique, recieving_clique, operation):
          """
          This is belief-update method.
  
          Parameters
          ----------
          sending_clique: node (as the operation is on junction tree, node should be a tuple)
              Node sending the message
          recieving_clique: node (as the operation is on junction tree, node should be a tuple)
              Node recieving the message
          operation: str ('marginalize' | 'maximize')
              The operation to do for passing messages between nodes.
  
          Takes belief of one clique and uses it to update the belief of the
          neighboring ones.
          """
          sepset = frozenset(sending_clique).intersection(frozenset(recieving_clique))
          sepset_key = frozenset((sending_clique, recieving_clique))
  
          # \sigma_{i \rightarrow j} = \sum_{C_i - S_{i, j}} \beta_i
          # marginalize the clique over the sepset
          sigma = getattr(self.clique_beliefs[sending_clique], operation)(list(frozenset(sending_clique) - sepset),
                                                                          inplace=False)
  
          # \beta_j = \beta_j * \frac{\sigma_{i \rightarrow j}}{\mu_{i, j}}
          self.clique_beliefs[recieving_clique] *= (sigma / self.sepset_beliefs[sepset_key]
                                                    if self.sepset_beliefs[sepset_key] else sigma)
  
          # \mu_{i, j} = \sigma_{i \rightarrow j}
          self.sepset_beliefs[sepset_key] = sigma