2

I am facing a situation, where a user is allowed to define some conditionals as follows:

x >= 2
x < 6
y >= 2
y > 2*x

where x and y are variables. Does a library exists in Java or Python that is able to compute the domain range for each variable (e.g. x in [2,6] and y in [2,12]), and then validates those expressions? For instance, adding the statement

x + y <= 2

should result in an error.

Best

labrassbandito
  • 535
  • 12
  • 25
  • Java *or* Python? You're using two languages? – Jonathan Lam Nov 17 '15 at 23:07
  • What operators do you allow? Be careful, it can become hard pretty easily to parse these expression. You might want to use some kind of external program to interact with (Mathematica or Maple). Use of scientific libraries might suit your needs (SciPy for python as example) but this will probably require you some work from your part. – orion78fr Nov 17 '15 at 23:13
  • 1
    Library recommendations are off-topic – Vince Nov 17 '15 at 23:16
  • 1
    When you say 'a user is allowed to define' - does that mean input text which is parsed? Or do you mean the user of your library should be able to define these predicates in code? – sprinter Nov 17 '15 at 23:27
  • @Jonathan preferrable Java – labrassbandito Nov 17 '15 at 23:39
  • @orion78fr support for relational operators and on each side could be a simple math expression (+,-,*,/) – labrassbandito Nov 17 '15 at 23:39
  • @sprinter the rules will be defined by a user in a text document. the final format is not yet defined. but it will likely just a string. – labrassbandito Nov 17 '15 at 23:41
  • @labrassbandito Ok then you need a proper parser and a custom expression library. Check out ANTLR for the parser. Given your needs for expressions are fairly simple I suggest a custom expression tree for that. – sprinter Nov 18 '15 at 00:15
  • @VinceEmigh I think the tone of the question makes clear that the request for a library recommendation is not the point of the question. While it could be better worded I read OP's question as 'what guidance can you give on a good approach?' – sprinter Nov 18 '15 at 00:34
  • @sprinter Then it would be considered a code request, seeing how there is no shown attempt/research effort. If it included those details, I wouldn't assume that this was a library request. It does not state a problem he is having (the purpose of the site). It states what he wants and nothing more – Vince Nov 18 '15 at 00:37
  • @VinceEmigh I agree that OP should have included current attempt. Comments on one of the answers makes clear that OP has had a go at an approach and realised it needed rethinking. Having said that I find 'suggest an approach' questions both the hardest to ask and the most interesting on SO. They often get rejected for good reason but they are the most interesting to answer - much more interesting than 'how do I write this tiny bit of code'. This question is poorly worded but is actually a very interesting question about best approach to a complex problem. – sprinter Nov 18 '15 at 00:40
  • @sprinter They get rejected because this is not [CodeReview](http://codereview.stackexchange.com). I understand that a lot of interesting questions get closed due to the rules, which sucks. But those rules also prevent trash, and I'm sure more trash has been prevented than gems have been closed. Attempting to refine the rules is what MetaStackoverflow is for. He should edit his attempts/research into his question. You cant blame me for assuming this was a code request. For all you know, this could be homework, which isn't bad, but should at least show attempts/research along with the problem. – Vince Nov 18 '15 at 00:44
  • @VinceEmigh I agree with you and I generally like the rules and vote to close heaps of questions myself. And I agree that the question was not well worded. – sprinter Nov 18 '15 at 00:50
  • @VinceEmigh As an aside, if this is homework then it's got a lot tougher since I was at college! – sprinter Nov 18 '15 at 00:50

2 Answers2

0

I guess you could do this manually. AFAIK, there is no built-in way to handle inequalities.

You could create a way to handle the limits, and then manually assign those limits based on your input inequalities.

This can create the inequalities. You can manipulate the limits and directions of multiple inequalities to make a system, and then use those systems to validate the equation.

public class Limit {
    public double limit;          // limit number
    public boolean isUpperLimit;  // essentially the direction
    public boolean includes;      // differentiates between <= and <
    public Limit(double limit, boolean isUpperLimit, boolean includes) {
        this.limit = limit;
        this.isUpperLimit = isUpperLimit;
        this.includes = includes;
    }
}
public class Inequality {
    public Limit limit;
    public String variable;
    public Inequality(String inequality) { // if inequality is 
        String variable = inequality.split(" ")[0];
        this.variable = variable;
        String operator = inequality.split(" ")[1];
        Double number = Double.parseDouble(inequality.split(" ")[2]);
        double limit = number;
        boolean isUpperLimit, includes;
        switch(operator) {
            case ">":
                isUpperLimit = false;
                includes = false;
                break;
            case ">=":
                isUpperLimit = false;
                includes = true;
                break;
            case "<":
                isUpperLimit = true;
                includes = false;
                break;
            case ">=:
                isUpperLimit = true;
                includes = true;
                break;
        }
        this.limit = new Limit(limit, isUpperLimit, includes);
    }
}

public class System {
    public Limit lowerLimit;
    public Limit upperLimit;
    public System(Inequality ie1, Inequality ie2) {
        if(ie1.limit.isUpperLimit == ie2.limit.isUpperLimit) { // if same direction
            if(ie1.limit.isUpperLimit == true) {
                this.upperLimit = (ie1.limit.limit >= ie2.limit.limit) ? ie1.limit : ie2.limit;
            } else {
                this.upperLimit = (ie2.limit.limit >= ie1.limit.limit) ? ie1.limit : ie2.limit;
            }
        }
    }
}

Code is untested

If you have systems set, then now you can use their limits to determine if the last equation is possible or not.

Jonathan Lam
  • 16,831
  • 17
  • 68
  • 94
  • Thanks for the answer. I had already started with manually checking the domain range of my variables, but got the impression that the evaluation will become cumbersome when expressions might become more complex. I will think about this once more. – labrassbandito Nov 17 '15 at 23:45
  • @labrassbandito Sorry the code is so long and obfuscated. There might be an easier way (see the other answer, but I don't know how it works), but this was the easiest way I could think of. But I'm just an amateur teen enthusiast taking time off HW to stack up rep points who knows very little about programming in general and trying my best to help people with my limited knowledge =). – Jonathan Lam Nov 17 '15 at 23:48
0

It's unclear in your question whether you are talking about parsing text expressions or for a library that allows predicates to be defined.

If you are referring to the latter, Java 8 makes defining the predicates fairly easy. Your predicates could be represented as:

List<BiFunction<Integer, Integer, Boolean>> conditionals;

And then set as:

conditionals.add((x, y) -> x >= 2);
conditionals.add((x, y) -> x < 6);
conditionals.add((x, y) -> y > 2 * x);

And so on.

Then testing against a defined range for x and y could look like:

private boolean anyMatch(int xMin, int xMax, int yMin, int yMax) {
    IntStream.rangeClosed(xMin, xMax).anyMatch(x ->
        IntStream.rangeClosed(yMin, yMax).anyMatch(y ->
            conditionals.stream().allMatch(c -> c.apply(x, y))));
}

At the moment this is assuming two variables. If you want to extend to cover any number it's still possible with the built-in classes by representing the values of the variables as a map:

List<Function<Map<String, Integer>, Boolean>> conditionals;
conditionals.add(vars -> vars.get("x") >= 2);
conditionals.add(vars -> vars.get("y") > 2 * vars.get("x"));

This design could be used fairly easily to exclude adding predicates that are incompatible over a given range.

If you want to do something more complicated that retains information about allowed ranges without iterating over a specified domain then I think you'll need a custom class for that.

sprinter
  • 27,148
  • 6
  • 47
  • 78
  • This looks interesting. The BitFunction is new to me. I am not sure yet, if Java 8 will be used in-house. I have to check that as well. – labrassbandito Nov 17 '15 at 23:47
  • @labrassbandito You can use the same approach in Java 7 but you need to create anonymous implementations of the interfaces. However given your comment above about having to parse the string my answer is not much use to you. – sprinter Nov 17 '15 at 23:50