MathGroup Archive 2005

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: pairs and subsets challenge

  • To: mathgroup at smc.vnet.net
  • Subject: [mg59383] Re: pairs and subsets challenge
  • From: Maxim <ab_def at prontomail.com>
  • Date: Sun, 7 Aug 2005 03:47:30 -0400 (EDT)
  • References: <dchnkq$7pe$1@smc.vnet.net> <dcuv93$e2f$1@smc.vnet.net>
  • Sender: owner-wri-mathgroup at wolfram.com

On Fri, 5 Aug 2005 06:00:03 +0000 (UTC), Carl K. Woll  
<carlw at u.washington.edu> wrote:

> "Daniel Reeves" wrote:
>> Here's an interesting problem:
>>
>> Given a set N = {1,...,n}.
>> And given a set P of pairs from N, ie, a subset of KSubsets[N,2].
>> List each _maximal_ subset X of N such that KSubsets[X,2] is a
>>  subset of P.
>> Maximal means if X is listed, don't list any subsets of X.
>>
>> Brute force solutions are not hard to write.  This should work for n up  
>> to
>> 40 and |P| around 500.
>>
>> Simple example:
>>
>> N = {1,2,3,4,5};
>> P = {{1,2},{1,3},{1,4},{2,3},{2,4},{3,4},{3,5},{4,5}};
>>
>> output:
>>
>> {{1,2},{1,3},{1,4},{2,3},{2,4},{3,4},{3,5},{4,5},
>> {3,4,5}, {1,2,3,4}}
>>
>>
>> (no prize this time but I think it'll be fun!)
>>
>
> Here's one attempt. Basically, I start with the first element, and get a
> list of the elements it is paired with. Then, I take the first element of
> this list and see what elements it is paired with and form a new list of
> common elements. Proceed recursively until there are no more common
> elements. Store the subset of elements chosen, and backtrack. This  
> algorithm
> produces a list of all of the maximal subsets, but it also produces a  
> bunch
> (but not all) of nonmaximal subsets. I use another function (prune) to  
> prune
> the nonmaximal subsets from the list.
>
> I store the pairs information in a nonsymmetric sparse array. Here is the
> code:
>
> maximalsubs[pairs_] := Module[{},
> len = Max[pairs];
> mat = SparseArray[Thread[Sort /@ pairs -> 1], {len, len}];
> rng = Range[len];
> cur = Table[0, {len}];
> subs = Reap[Do[
> index = 1;
> cur[[index++]] = i;
> getsubs[Pick[rng, mat[[i]], 1]], {i, len}]][[2, 1]];
> prune[subs]
> ]
>
> getsubs[common_] := Module[{},
> Do[
> cur[[index++]] = common[[i]];
> getsubs[Intersection[Pick[rng, mat[[common[[i]]]], 1], common]];
> index--;, {i, Length[common]}]]
>
> getsubs[{}] := Module[{},
> Sow[Take[cur, index - 1]]]
>
> prune[n_] := Module[{}, p = Reverse@Union[Plus @@@ (2^(n - 1))];
> ans = Fold[addmem, {First@p}, Rest@p];
> Flatten@Position[Reverse@IntegerDigits[#, 2], 1] & /@ ans]
>
> addmem[x_, a_] := If[Min@BitAnd[a, BitNot[x]] == 0, x, Append[x, a]]
>
> For your example, we have:
>
> In[10]:=
> maximalsubs[{{1,2},{1,3},{1,4},{2,3},{2,4},{3,4},{3,5},{4,5}}]
>
> Out[10]=
> {{3,4,5},{1,2,3,4}}
>
> For a list of ~500 pairs with indices ranging to 40, it took ~3 seconds  
> to
> generate the list of nonmaximal subsets, and another ~40 seconds to prune
> this list. Pruning the nonmaximal subsets takes most of the time.
>
> Here is a test case for ~500 pairs:
>
> SeedRandom[1];
> pairs = DeleteCases[
> Union@Table[
> Sort[{Random[Integer, {1, 40}], Random[Integer, {1, 40}]}], {900}], {i_,
> i_}];
>
> In[15]:=
> Length[pairs]
> Out[15]=
> 518
>
> Applying maximalsubs to the above pairs:
> In[25]:=
> ans=maximalsubs[pairs];//Timing
> Out[25]=
> {45.454 Second,Null}
>
> The number of maximal subsets:
> In[26]:=
> Length[ans]
> Out[26]=
> 1115
>
> The number of nonmaximal subsets generated:
> In[27]:=
> Length[subs]
> Out[27]=
> 20258
>
> It would be nice to avoid generating these nonmaximal subsets, but I
> couldn't think of a good algorithm for that. Pruning nonmaximal subsets  
> from
> a list of substs is also a nice exercise. I thought I had posted the  
> above
> code for prune to mathgroup before, but apparently it never made it.  
> Perhaps
> we should revisit the pruning exercise to see if a better prune function  
> can
> be found.
>
>> --
>> http://ai.eecs.umich.edu/people/dreeves  - -  google://"Daniel Reeves"
>>
>> Optimist: The glass is half full.
>> Pessimist: The glass is half empty.
>> Engineer: The glass is too big.
>>
>
> Carl Woll
> Wolfram Research
>
>

Here's an optimized version. We can check that a given set is a solution  
by verifying that there isn't a vertex adjacent to all the vertices in the  
set.

<<discretemath`
cliques[P_] := Module[
     {G, LLadj, stack, cur, sol, qp, sp, ans = {}},
     G = FromUnorderedPairs[P];
     LLadj = ToAdjacencyLists[G];
     stack = Table[{}, {V[G] + 1}];
     sol = qp = Table[0, {V[G] + 1}];
     stack[[sp = 1]] = Range[V[G]]; qp[[sp]] = 1;
     While[True,
       If[qp[[sp]] > Length@ stack[[sp]],
         If[sp-- == 1,
           Break[],
           qp[[sp]]++; Continue[]
       ]];
       sol[[sp]] = stack[[sp, qp[[sp]]]];
       cur = Take[sol, sp++];
       stack[[sp]] = Intersection @@ LLadj[[cur]];
       qp[[sp]] = 1;
       If[stack[[sp]] === {}, AppendTo[ans, cur]];
       stack[[sp]] = Select[stack[[sp]], # > Max@ cur&]
     ];
     ans
]

In[8]:=
SeedRandom[1]
P = DeleteCases[
   Union[Sort /@ Array[Random[Integer, {1, 40}]&, {900, 2}]],
   {i_, i_}];
(ans = maximalsubs[P];) // Timing
(ans2 = cliques[P];) // Timing
Sort@ans === Sort@ans2

Out[10]=
{16.609 Second, Null}

Out[11]=
{1.86 Second, Null}

Out[12]=
True

Maxim Rytin
m.r at inbox.ru


  • Prev by Date: Re: Need portable code to open Notation palette.
  • Next by Date: Re: Some bugs in Mathematica
  • Previous by thread: Re: pairs and subsets challenge
  • Next by thread: Set default options for a function