Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I would like to convert logical relational expressions in disjunctive form, e.g.,

$$(x \lt -1) \lor (-1 \lt x \lt +1) \lor (x \gt +1)$$

into conjunctive form, e.g.,

$$(x \ne -1) \land (x \ne +1)$$

I have some machinery in place that converts a logical relational expressions in disjunctive form into a union of intervals:

ClearAll[mxInterval];                                                                             

mxInterval::unrecognized = "The expression `` is not an Inequality, Less, LessEqual, GreaterEqual\
 or Greater operator or the logical Or of one or more of the operators.";                         

mxInterval[HoldPattern[Inequality[valueLeft_, ropLeft_, var_, ropRight_, valueRight_]]] :=        
    mxInterval[ropLeft, valueLeft, valueRight, ropRight];                                         

mxInterval[(rop:(Less|LessEqual))[var_, value_]] :=                                               
    mxInterval[LessEqual, "-\[Infinity]", value, rop];                                            

mxInterval[(rop:(Greater|GreaterEqual))[var_, value_]] :=                                         
    mxInterval[rop, value, "\[Infinity]", GreaterEqual];                                          

mxInterval[HoldPattern[Or[x__]]] :=                                                               
    Or @@ Replace[HoldComplete[x], elem_ :> mxInterval[elem], {1}];                               

mxInterval[expr_] := (Message[mxInterval::unrecognized, expr]; Return $fail;)                     

mxIntervalSymbol[op_, side_] := Switch[                                                           
    op,                                                                                           
    Less|Greater, Switch[side, l, "[", r, "]"],                                                   
    LessEqual|GreaterEqual, Switch[side, l, "(", r, ")"]];                                        

mxInterval /: MakeBoxes[mxInterval[ropLeft : (Less|LessEqual|Greater|GreaterEqual),               
                               valueLeft_, valueRight_,                                       
                               ropRight : (Less|LessEqual|Greater|GreaterEqual)], form_] :=   
    RowBox[{mxIntervalSymbol[ropLeft, l], MakeBoxes[valueLeft, form], ",",                        
            MakeBoxes[valueRight, form], mxIntervalSymbol[ropRight, r]}];   

Using mxInterval on the sample expression produces a disjunction of intervals,

In[]: mxInterval[x < -1 || -1 < x < +1 || x > +1]

Out[]: Or[mxInterval[-\[Infinity],LessEqual,Less,-1],
          mxInterval[-1,Less,Less,+1],
          mxInterval[+1,Greater,GreaterEqual,\[Infinity]]

which display as:

$$(-\infty, -1] \cup [-1,+1] \cup [+1,+\infty)$$

or, as the number line: oops, which is actually of $(-\infty,-1] \cup [+1,+1\infty)$:

NumberLine

(Note: Maybe I should produce Union instead of Or here. Would that eliminate the needs for a MakeBoxes definition for Or[mxInterval ..]? The only use for that function is to get the $\cup$ operator instead of $\lor$ in the display).

What I would really like is the function mxInterval[Or[mxInterval ..], And] which would take the disjunctive form of intervals and produce the conjunctive form. And, of course, mxInterval[And[mxInterval ..], Or] that would do the reverse.

If I were using a more procedural language, I would sort and then iterate over the intervals constructing the result along the way. However, I feel like the best way to implement the function in Mathematica is to rely heavily on pattern matching, but I'm having trouble formulating a solution using that paradigm.

Or, maybe there is a Mathematica incantation that will do the conversion on the original logical relational expression? That would be sweet.

share|improve this question
3  
This works for your simple example. Might not generalize well though, I'm not sure. In[27]:= BooleanConvert[! Reduce[! ee], "CNF"] Out[27]= x != -1 && x != 1 –  Daniel Lichtblau Mar 9 '13 at 20:06
    
That works for my current test cases, but BooleanConvert seems to ignore the form specification for "DNF" and "CNF": BooleanConvert[!Reduce[!result]] produces the same result as BooleanConvert[!Reduce[!result], "DNF"] and BooleanConvert[!Reduce[!result], "CNF"]. Specifying "NAND" and "NOR" does produce the expected results. I'd like to try to understand why this produces the CNF form and add a few more test cases. –  RandomBits Mar 9 '13 at 20:35
    
I suspect "DNF" is a default form. From the point of view of basic logic, a statement of the form a AND b with (a,b) both atomic is already in DNF, trivially, as an OR with but one clause. obviously it is also in CNF. This may explain the behavior you note. –  Daniel Lichtblau Mar 9 '13 at 20:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.