How to match set-patterns against sets?
A set (in the mathematical sense) is a list of elements without repetition and order of elements does not matter. For example, we have a pattern set {3, 1} that should match sets {1, 3}, {1, 2, 3}, {1, 2, 3, 4} and so on. Note, that the list-length of the pattern is not relevant: any set that contains elements 3 and 1 should match the pattern. So far, this is simple subset testing - but there are two problems:
Since order does matter for the patternmatcher, one has to write e.g.
Cases[sets, {___, 3, ___, 1, ____}|{___, 1, ___, 3, ____}]which causes a combinatorial expansion for an increasing number of element-wise matches. Thus I usedMemberQinstead of structural patterns.I would like to use more complicated patterns, like: "Find all sets that contain 1 and 3 but not 2!".
I have a working solution, but it is neither effective nor elegant in my opinion. It involves a Boolean description of the pattern (And to include all listed elements, Or to include any listed element, Not to exclude an element), but I am not sure it is the right way to do it. The function simply wraps each element that apperas in the pattern into MemberQ, so the Boolean expression translates to a logical combination of MemberQ and Not@MemberQ calls.
setCases[sets_List, patt_] := Module[{elem = Union @@ sets},
Cases[sets, _?((patt /. x_ /; MemberQ[elem, x] :> MemberQ[#, x]) &), {1}]
];
Define a list of sets, and a list of patterns for testing:
sets = Subsets[{1, 2, 3, 4}];
patterns = {1, \[Not] 1, 1 \[And] \[Not] 2, 1 \[Or] \[Not] 2,
1 \[Or] 2 \[Or] 3, 1 \[And] 2 \[And] 3,
1 \[And] \[Not] 2 \[And] \[Not] 3, 1 \[Or] (2 \[And] \[Not] 3),
1 \[And] \[Not] (2 \[And] 3), 1 \[And] \[Not] (2 \[Or] 3),
1 \[And] \[Not] (2 \[Or] (3 \[And] \[Not] 4)),
\[Not] 1 \[And] \[Not] 2 \[And] \[Not] 3 \[And] \[Not] 4}
Grid[{#, setCases[sets, #]} & /@ patterns, Alignment -> Left,
Background -> {None, {{LightGray, White}}}, Spacings -> {1, 1}] // TraditionalForm

Let's examine one case closer, by displaying the ultimate pattern that is tested:
(1 \[Or] 2) \[And] \[Not] 3 /. x_Integer :> MemberQ[#, x]
(MemberQ[#1, 1] & || (MemberQ[#1, 2] &)) && ! (MemberQ[#1, 3] &)
As one can see, the function is far from being economic: alternatives could have been gathered under one MemberQ (MemberQ[#, 1]& || MemberQ[#, 2]& is equivalent to MemberQ[#, 1|2]&) and I think that Except should be used as well, though have no idea how. I am interested in robust, fast solutions.
Note: Do NOT try to simplify the logical patterns, as:
Simplify[And[1, 2]] ==> 2
Simplify[And[0, 1]] ==> False
TextSearch. It usesListforAnd,AlternativesforOrandExceptforNot. According toPrintDefinitionsspelunking, there is a full-blown query-set-algebra, check e.g.TextSearch^IndexSearch^PackagePrivate^compileQueryand...^exec:QNot,QUnion,QIntersection,QComplement,QStringare the specific functions. (backticks are replaced by^) – István Zachar Mar 09 '16 at 21:23