r"""
    Base method used for product of factor sets.

    Suppose :math:`\vec\phi_1` and :math:`\vec\phi_2` are two factor sets then their product is a another factors set
    :math:`\vec\phi_3 = \vec\phi_1 \cup \vec\phi_2`.

    Parameters
    ----------
    factorsets_list: FactorSet1, FactorSet2, ..., FactorSetn
        All the factor sets to be multiplied

    Returns
    -------
    Product of factorset in factorsets_list

    Examples
    --------
    >>> from pgmpy.factors import FactorSet
    >>> from pgmpy.factors.discrete import DiscreteFactor
    >>> from pgmpy.factors import factorset_product
    >>> phi1 = DiscreteFactor(['x1', 'x2', 'x3'], [2, 3, 2], range(12))
    >>> phi2 = DiscreteFactor(['x3', 'x4', 'x1'], [2, 2, 2], range(8))
    >>> factor_set1 = FactorSet(phi1, phi2)
    >>> phi3 = DiscreteFactor(['x5', 'x6', 'x7'], [2, 2, 2], range(8))
    >>> phi4 = DiscreteFactor(['x5', 'x7', 'x8'], [2, 2, 2], range(8))
    >>> factor_set2 = FactorSet(phi3, phi4)
    >>> factor_set3 = factorset_product(factor_set1, factor_set2)
    >>> print(factor_set3)
    set([<DiscreteFactor representing phi(x1:2, x2:3, x3:2) at 0x7fb3a1933e90>,
         <DiscreteFactor representing phi(x5:2, x7:2, x8:2) at 0x7fb3a1933f10>,
         <DiscreteFactor representing phi(x5:2, x6:2, x7:2) at 0x7fb3a1933f90>,
         <DiscreteFactor representing phi(x3:2, x4:2, x1:2) at 0x7fb3a1933e10>])

def factorset_product(*factorsets_list):
    r"""
    Base method used for product of factor sets.

    Suppose :math:`\vec\phi_1` and :math:`\vec\phi_2` are two factor sets then their product is a another factors set
    :math:`\vec\phi_3 = \vec\phi_1 \cup \vec\phi_2`.

    Parameters
    ----------
    factorsets_list: FactorSet1, FactorSet2, ..., FactorSetn
        All the factor sets to be multiplied

    Returns
    -------
    Product of factorset in factorsets_list

    Examples
    --------
    >>> from pgmpy.factors import FactorSet
    >>> from pgmpy.factors.discrete import DiscreteFactor
    >>> from pgmpy.factors import factorset_product
    >>> phi1 = DiscreteFactor(['x1', 'x2', 'x3'], [2, 3, 2], range(12))
    >>> phi2 = DiscreteFactor(['x3', 'x4', 'x1'], [2, 2, 2], range(8))
    >>> factor_set1 = FactorSet(phi1, phi2)
    >>> phi3 = DiscreteFactor(['x5', 'x6', 'x7'], [2, 2, 2], range(8))
    >>> phi4 = DiscreteFactor(['x5', 'x7', 'x8'], [2, 2, 2], range(8))
    >>> factor_set2 = FactorSet(phi3, phi4)
    >>> factor_set3 = factorset_product(factor_set1, factor_set2)
    >>> print(factor_set3)
    set([<DiscreteFactor representing phi(x1:2, x2:3, x3:2) at 0x7fb3a1933e90>,
         <DiscreteFactor representing phi(x5:2, x7:2, x8:2) at 0x7fb3a1933f10>,
         <DiscreteFactor representing phi(x5:2, x6:2, x7:2) at 0x7fb3a1933f90>,
         <DiscreteFactor representing phi(x3:2, x4:2, x1:2) at 0x7fb3a1933e10>])

    """
    if not all(isinstance(factorset, FactorSet) for factorset in factorsets_list):
        raise TypeError("Input parameters must be FactorSet instances")
    return reduce(lambda x, y: x.product(y, inplace=False), factorsets_list)