import copy




class DistributionSymbol:
    """
    Abstract base class for type 1 symbol (a distribution over states).
    """

    def integrate_out(self,
                      variable_list):
        raise NotImplementedError("Called abstract base class method DistributionSymbol::integrate_out.")

    @property
    def mask(self):
        raise NotImplementedError("Called abstract base class method DistributionSymbol::mask.")

    def distribution_and(self,
                         *distribution_symbols):
        raise NotImplementedError("Called abstract base class method DistributionSymbol::distribution_and.")

    def sample(self,
               n_samples=100):
        raise NotImplementedError("Called abstract base class method DistributionSymbol::get_samples.")

    def kl_divergence(self,
                      distribution_symbol,
                      n_samples=100):
        raise NotImplementedError("Called abstract base class method DistributionSymbol::kl_divergence.")

    def probability_in_set(self,
                           conditional_distribution):
        raise NotImplementedError("Called abstract base class method DistributionSymbol::probability_in_set.")

    def score(self, state):
        raise NotImplementedError("Called abstract base class method DistributionSymbol::score.")

    def score_samples(self, X):
        """
        Evaluate the density model on the data.
        """
        raise NotImplementedError("Called abstract base class method DistributionSymbol::score_samples.")


    @staticmethod
    def conjoin(distribution_symbols):
        conjunction = copy.copy(distribution_symbols[0])
        if len(distribution_symbols) > 1:
            conjunction = conjunction.distribution_and(*distribution_symbols[1:])

        # if len(conjunction.id) > 40:
        #     conjunction.id = conjunction.id[:40]
        return conjunction
