6

Updated Algorithm: There was a major flaw in my original presentation of the algorithm which could have impacted the results. I apologize for the same. The correction has been posted underneath.


The original algorithm posted had a major flaw in its working. I tried my best but could not get the desired accuracy in presenting the algorithm in pseudo code and/or Set Theory notation. I am thus posting python code, which has been tested and produces the desired results.

Note that my question, however, remains the same: What is the time complexity of the algorithm (assuming that powersets are already generated)?

# mps is a set of powersets; below is a sample (test case)
mps = [
        [       [], [1], [2], [1,2]     ],
        [       [], [3], [4], [3,4]     ],
        [       [], [5], [6], [5,6]     ]
      ]


# Core algorithm
# enumerate(mps) may not be required in languages like C which support indexed loops
len = mps.__len__()
for idx, ps in enumerate(mps):
    if idx > len - 2:
            break;
    mps[idx + 1] = merge(mps[idx], mps[idx+1])   # merge is defined below


# Takes two powersets and merges them
def merge (psa, psb):
    fs = []
    for a in psa:
            for b in psb:
                    fs.append(list(set(a) | set(b)))
    return fs

Output: mps[-1] #Last item of the list

Running the above example will result in listing out the powerset of $\{1,2,3,4,5,6\}$.

Kaveh
  • 22,661
  • 4
  • 53
  • 113
WeaklyTyped
  • 201
  • 1
  • 6

1 Answers1

3

EDIT: Since your new algorithm is slightly different, I present a new complexity analysis. I change the notation slightly of power-sets $P_a$ and $P_b$ to $P_1$ and $P_2$. Your algorithm generates a power-set $P = P(S_1 \cup S_2 \cup \cdots \cup S_n)$ where $P(S_i)=P_i$ given the power-sets $P_1, P_2, ..., P_n$.
In the body of the loop it performs the merge of two subsets $P_1$ and $P_2$.

What is the complexity of $\mathtt{merge}(P_1, P_2)$?

Define $|a|=\mathtt{len}(a)$ for a list $a$. The complexity of $\mathtt{set}(a) \mid \mathtt{set}(b)$ is $\mathcal{O}(|a|+|b|)$ according to Python Wiki for the union of two sets. The conversion $\mathtt{list}(\mathtt{set}(a) \mid \mathtt{set}(b))$ is asymptotically not worse than $\mathcal{O}(|a|+|b|)$, I guess it is either linear or sublinear depending how python implements it. Appending is constant, but since you are appending the whole list it is linear in terms of one list element as the whole list object will need to be copied in the memory, again $\mathcal{O}(|a|+|b|)$ . Thus the complexity of the loop body in a merge function is at most $\mathcal{O}(3(|a|+|b|)$ which is asymptotically equivalent to $\mathcal{O}(|a|+|b|)$.

The loop body in a merge function will be executed $|P_1||P_2|$ times. Thus the overall complexity of the merge function is $\mathcal{O}(|P_1||P_2|(|a|+|b|))$. Notice $a$, $b$ are elements of power-sets. Thus their lengths follow a binomial distribution. Therefore on average $|a|=0.5\log_2(|P_1|)$ and $|b|=0.5\log_2(|P_2|)$. This gives us

\begin{align} \mathcal{O}(|P_1||P_2|(|a|+|b|))&=\mathcal{O}(|P_1||P_2|(0.5\log_2(|P_1|)+0.5\log_2(|P_2|))\\ &=\mathcal{O}(0.5|P_1||P_2|(\log_2(|P_1|)+\log_2(|P_2|))\\ &=\mathcal{O}(0.5|P_1||P_2|(\log_2(|P_1||P_2|))\\ &=\mathcal{O}(|P_1||P_2|(\log_2(|P_1||P_2|)) \end{align} for the complexity of a merge algorithm for two power-sets $P_1$ and $P_2$.

Notice that the merge of $P_i$ and $P_{i+1}$ replaces $P_{i+1}$ for a power-set $\mathtt{merge}(P_{i}$,$P_{i+1})$ which is of length $2^{\log_2|P_i|+\log_2|P_{i+1}|}=|P_i||P_{i+1}|$.

After the first the first execution of the loop body in the main algorithm you will have executed $\mathcal{O}(|P_1||P_2|(\log_2(|P_1||P_2|))$ steps. $P_2$ has changed to $P_2'$ with the length $|P_1||P_2|$. After the second execution you will get another $\mathcal{O}(|P_2'||P_3|\log_2(|P_2'||P_3|))$ steps which is $\mathcal{O}(|P_1||P_2||P_3|\log_2(|P_1||P_2||P_3|))$ And then by the induction you finally get the complexity of the last step of the loop \begin{align} \mathcal{O}(|P_1||P_2|\cdots|P_n|\log_2(|P_1||P_2|\cdots|P_n|))&=\mathcal{O}(\Pi_{i=1}^n|P_i|\log_2(\Pi_{i=1}^n|P_i|))\\ &=\mathcal{O}(\Pi_{i=1}^n|P_i|\Sigma_{i=1}^n\log_2|P_i|). \end{align}

The complexity of the whole program is the sum of these complexities.

xskxzr
  • 7,613
  • 5
  • 24
  • 47
Dávid Natingga
  • 603
  • 4
  • 8