Conditional expression algebra in C#
I am working on a small part of a matching system that uses boolean conditional expressions.
These conditional expressions are contrained to a single variable and a single operator (with an edge case of an Inclusive Between).
I am interested in:
- Equal To "="
- Greater than ">"
- Greater Than Or Equal To ">="
- Less Than "<"
- Less Than Or Equal To "<="
- Inclusive Between ">= AND <="
I have a requirement to compare two conditional expressions and evaluate:
1) Is there an overlap of possible values?
Does "X > 1000" overlap with "X > 999"? Yes.
2) If there is an overlap, return the overlap:
The overlap of "X > 1000" with "X > 999" is "X > 1000"
3) Is a conditional expression constrained by another?
"X < 999" is constrained by "X < 1000" ; "X &l开发者_如何学Ct; 1001" is not constrained by "X < 1000"
What I have done so far is build up a truth table of all possible combinations and return the results, but I was wondering if there was an easier way to calculate these?
Any Theory / Reference material / C# libraries out there?
I haven't heard of any, but you can easily do without them if you represent the constraints as intervals:
x > 1000 becomes (1000, double.Infinity)
x == 1000 becomes [1000, 1000]
etc.
This way you need only one class
class Constraint
{
double Lower; bool isLowerStrict;
double Upper; bool isUpperStrict;
bool isIn(double d)
{
return (isLowerStrict ? Lower < d : Lower <= d) &&
(isUpperStrict ? Upper > d : Upper >= d);
}
Constraint intersect(Constraint other)
{
Constraint result = new Constraint();
if (Lower > other.Lower)
{
result.Lower = Lower;
result.isLowerStrict = isLowerStrict;
}
else if (Lower < other.Lower)
{
result.Lower = other.Lower;
result.isLowerStrict = other.isLowerStrict;
}
else
{
result.Lower = Lower;
result.IsLowerStrict = isLowerStrict || other.isLowerStrict;
}
// the same for upper
return result;
}
public bool isEmpty()
{
if (Lower > Upper) return true;
if (Lower == Upper && (isLowerStrict || isUpperStrict)) return true;
return false;
}
public bool Equals(Constraint other)
{
if (isEmpty()) return other.isEmpty();
return (Lower == other.Lower) && (Upper = other.Upper) &&
(isLowerStrict == other.IsLowerStrict) &&
(isUpperStrict == other.isUpperStrict);
}
// construction:
static Constraint GreaterThan(double d)
{
return new Constraint()
{
Lower = d,
isLowerStrict = true,
Upper = double.PositiveInfinity,
isUpperStrict = false
};
}
static Constraint IsEqualTo(double d)
{
return new Constraint()
{
Lower = d,
isLowerStrict = false,
Upper = d,
isUpperStrict = false
};
}
// etc.
}
With this code, you can answer the questions:
1) overlap: a.Intersect(b).isEmpty()
2) intersect: a.Intersect(b)
3) constrain: a.Intersect(b).Equals(a)
EDIT:
As @CodeInChaos suggests, you should consider replacing double with decimal. Mind that decimal lacks infinite values, so you should use decimal.MaxValue and decimal.MinValue instead.
I had written some sample code fast. Hope it makes sense:
enum SygnType
{
More, Less, Equal
}
public class Representation
{
public SignType sign;
public int value;
}
public class Range
{
public bool infinityNegative;
public bool infinityPositive;
public int minValue;
public int maxValue;
public Range(List<Representation> values)
{
infinityNegative=true;
infinityPositive=true;
foreach(var value in values)
{
if (value.sign==SignType.More)
{
infinityNegative=false;
if (value>minValue)
minValue=value;
}
else if (value.sign==SignType.Less)
{
infinityPositive=false;
if (value<maxValue)
maxValue=value;
}
else if (value.sign==SignType.Equal)
{
infinityPositive=infinityNegative=false;
minValue=maxValue=value;
break;
}
}
}
public bool Overlaps(Range checkRange)
{
if (checkRange.infinityPositive)
return CompareUpperLevelValue(checkRange); //this method should compare upper value overlapping
else if (checkRange.infinityNegative)
return CompareLowerLevelValue(checkRange); //this method should compare lower value overlapping
else
return CompareInterval(checkRange); //this method should compare interval
}
public bool CompareUpperLevelValue(Range checkRange)
{
if (checkRange.maxValue<maxValue)
return true;
else
return false
}
public bool CompareLowerLevelValue(Range checkRange)
{
if (checkRange.minValue>minValue)
return true;
else
return false
}
public bool CompareInterval(Range checkRange)
{
if ((checkRange.minValue>minValue)&&(checkRange.maxValue<maxValue))
return true;
else
return false;
}
}
精彩评论