Set of sets:
ABCD
ABCE
AEF
DFG
ABFG
arbitrary set:
BG
Internally, this is all stored a integers, which I'll write out here in binary:
ABCDEFG
1111000
1110100
1000110
0001011
1100011
arbitrary set:
0100001
I'm going to keep using the letters in the rest of the post, though, they're easier to read.
####
A: (ABCD, ABCE, AEF, ABFG)
B: (ABCD, ABCE, ABFG)
C: (ABCD, ABCE)
D: (ABCD, DFG)
E: (ABCE, AEF)
F: (AEF, DFG, ABFG)
G: (DFG, ABFG)
Then, with our arbitrary set, BG, we just look at the sets in the B slot and the G slot.
B: (ABCD, ABCE, ABFG)
G: (DFG, ABFG)
If there's a superset, it's gotta be in one of those two slots. The next trick is that we only look at the smaller of the two lists, to try and minimize our work as much as possible:
G: (DFG, ABFG)
So now we only need to check and see if BG is a subset of DFG or ABFG. That's 2 checks instead of 5. Progress.
##
##
ABCDEFG
1111000
1110100
1000110
0001011
1100011
arbitrary set:
0100001
Now, I'll transpose the matrix, since I think it makes it easier to explain.
SSSSS
eeeee
ttttt
12345
+-----
A|11101
B|11001
C|11000
D|10010
E|01100
F|00111
G|00011
So instead of listing the sets horizontally, I list them vertically. Each horizontal row is an element. Internally, each of those horizontal numbers there is stored as a new integer. So instead of storing "1111000" for the set "ABCD", I store "11101" for the set of all sets taht contain "A".
##
##
SSSSS
eeeee
ttttt
12345
+-----
A|11101
B|11001
C|11000
D|10010
E|01100
F|00111
G|00011
Arbitrary set is BG. So take the B row and the G row.
SSSSS
eeeee
ttttt
12345
+-----
B|11001
G|00011
##
##
my %dispatch = ();
sub and_maker {
my $num_args = shift;
return $dispatch{$num_args} if $dispatch{$num_args};
my $built = join '&', map {'$_[' . $_ . ']'} (0..$num_args - 1);
return $dispatch{$num_args} = eval "sub { $built }";
}
Call as:
my $func = and_maker(3);
my $results1 = $func->(1,2,3); # 3 args
my $results2 = $func->(5,6,7); # 3 args
my $func2 = and_maker(5);
my $$results3 = $func2->(12,13,14,15,16); # 5 args