Cplex Java add expr(sum) to objective function - java

I've got the following objective function:
minimize sum (trueck[k] - time[k]) for all k (1..n).
I tried to set it up like this:
IloLinearNumExpr obj = cplex.linearNumExpr();
for(int k=0; k<grossK.length; k++){
obj.addTerm(1.0, cplex.sum(trueck[k], cplex.negative(time[k])));
}
cplex.addMinimize(obj);
The eclipse error message for the 4th line is:
"The method addTerm(double, IloNumVar) in the type IloLinearNumExpr is not applicable for the arguments (double, IloNumExpr)"
I guess the method "addTerm" is wrong but I can't find a solution.
Thanks in advance.

Don't use cplex.sum inside addTerm. You just need to separate out the two terms in your Objective function, since they both are summed over k.
Minimize sum (trueck[k] - time[k]) for all k (1..n)
Is the same as Min *sum_over_k* (trueck[k]) - *sum_over_k* (time[k])
This way, addTerm can handle it. (The code below is untested, but it gives you the idea of what you should try.)
IloLinearNumExpr obj = cplex.linearNumExpr();
for(int k=0; k<grossK.length; k++){
obj.addTerm(1.0, trueck[k]);
obj.addTerm(-1.0, time[k]);
}
cplex.addMinimize(obj);
Hope that helps.

The addTerm method is expecting a coefficient and a variable. It is not expecting a complex expression (e.g. A sum) or a specific numeric value as that second argument. It may be that you have a logic issue with what you are trying to pass in, so you may want to consider updating your question with more detail about what you want to accomplish if this doesn't clear things up for you. In other words, the term you are trying to enter is not compatible with the linear expression that you are using.

Related

I'm new to java and CPLEX. Struggling with summations and arrays

I'm trying to write a code in Java with CPLEX but I have a problem. I'm new to CPLEX and Java as well.
I've studied for a few days and I could understand very simple CPLEX examples but I have to deal with something much more difficult now.
I was trying to write expressions like 1000*(k-Sigma y^k(k from 1)) but I couldn't make it work so I googled for this topic but I couldn't find a way to figure this out.
What I understood so far is I need an array like this
IloNumVar[] y = cplex.numVarArray(?, ?, Double.MAX_VALUE?);
I read the manual from the IBM website but I still don't understand what variables I should put inside brackets.
And I need a for loop for the summation so I wrote like
for(int k = 1; k <= bus; k++) {
objective.addTerm(1000, k-y[k]);
}
Of course it's not working. I guess something's wrong with 'k' but have no idea how to fix this.
Please take a look at the following page:
CPLEX Java API
You can see the following method header:
IloNumVar[] numVarArray(int n, double lb, double ub)
where the params are:
n - number of variables
lb - lower bound
ub - upper bound
If you use it like this:
IloNumVar[] y = cplex.numVarArray(5, 0, Double.MAX_VALUE);
you are going to create an array of 5 elements (variables). Each of them has to be a non-negative number.
Please specify more clearly the 2nd part of your question.

Why is it bad to change for loop counter in Java?

I often heard that it's bad to modify the loop counter in the body of a for loop. The following (bad) example shows what I am talking about.
for (int i=0; i<10; i++) {
i++;
}
I know that this would be allowed within while loops but could anybody explain why this is a bad practice in Java resp. even a problem in any programming language.
Two reasons why this is bad:
Readability. for( a; b; c ) { d; } is a shorthand for a; while( b ) { d; c; } explicitly for the case where you are iterating over a list. It is not strictly needed in the language. The whole point of having it is to imply intent: "I want to iterate over an entire list" or "I want to iterate over part of a list in sequence, then abort when I find something" at most.
If you add an additional increment, that will surprise other people encountering your code. If your c above says ++x or whatever, people will simply assume it loops over all items, just to then find "surprise! not always!".
OTOH, if you use a while loop, people only see the condition, and are alerted that this will be a more complex loop where the increment will not be constant.
Optimiziation. Given the above statement of intent, some optimizers will generate different code for a for statement than a while statement. Although none of them should generate wrong code, they might apply an optimization that has worse performance characteristics for non-sequential access than for sequential access.
And by "worse performance characteristics" I mean they may tell the CPU to cache the wrong code path and slow down your execution by a fraction of a cycle because data may have to be loaded into the CPU again after having needlessly been flushed.
Just look at what happens with this code:
1 for (int i=0; i<10; i++) {
2 i++;
3 }
Initially line 1 i=0.
Line 2 increments i, which now equals 1.
End of loop, so i++ takes effect, now i=2.
And so on ...
So if you really wanted to do something like this, you could have wrote it like:
for (int i=0; i<10; i+=2) {
}
Which gets the same result. It's not necessarily bad code, but it doesn't make sense to code like that, and it's very hard to troubleshoot.
Mainly because most of the programmers use it that way, so it is more readable for everyone as mentioned by #AntonH.
Side note: trying as in other language (like C if memory serves) to write:
for(int i =0; i< 10; i){
printf("%d", i);
i++;
}
This code compiles and run. In Java, the equivalent:
for(int i =0; i< 10; i){
System.out.println("%d", i);
i++;
}
Edited thanks to #David Wallace:This yields a compilation error, it is mandatory to have an assignement in the statement part of the for loop.

Elements in a Vector that start with a given letter/number

I am trying to find on a Vector how many indexes start with a given letter or number.
I've tried vector.indexOf("A"); and vector.lastIndexOf("A"); but of course they are "useless" for what I am trying to do because those try to find a position that only have "A" and nothing else.
I wanted to know if there is a Java method to do this or if I need to do it "by myself", if so, a little guiding on the how-to process would be thanked.
If you do not want to (or can) use streams or lambdas you can also use this little loop here:
int count=0;
for (int i = 0; i < vec.size(); i++) {
count = vec.get(i).charAt(0)=='A' ? count+1 : count;
}
No big thing, just checking each element if it starts with A and then counting up.
In Java8 you can use Streams to access functional-style operations such as filter() and count(). Use the stream() method to get a Stream on your collection.

participal Eigenvalues Java (JAMA)

I just ported my code from MATLAB to Java, and I need the eigen decomposition of a matrix, specifically I only need the first k values not the full decomposition.
However in JAMA, the eigen-decomposition class computes the full eigen decomposition. I tried to modify it, but it throws some errors. Is there another similar library?
In MATLAB, the function in question is eigs(k,A)
So it's just returning the array of all the eigenvalues. You want to return an array with just the first k values of the array. There are many ways to do this in Java. One is to convert the array to an ArrayList, get a subList of that list, and convert back to an array.
double[] mySubArray = new double[k];
for (int i=0; i < k; i++) {
subArray[i] = myFullArray[i];
}
By the way, this is the library he is referring to: http://math.nist.gov/javanumerics/jama/doc/
In the case you cannot find any existing codes, I guess you should refer to this thesis or maybe this paper.
Maybe you can try another package named EigenDecomposition in http://commons.apache.org/proper/commons-math/javadocs/api-3.6/org/apache/commons/math3/linear/EigenDecomposition.html, there are some methods like getImagEigenvalue(int i), you can get the i-th eigenvalue by this.

How do you (get around) dynamically naming variables?

I'm not sure if I'm using the right nomenclature, so I'll try to make my question as specific as possible. That said, I imagine this problem comes up all the time, and there are probably several different ways to deal with it.
Let's say I have an array (vector) called main of 1000 random years between 1980 and 2000 and that I want to make 20 separate arrays (vectors) out of it. These arrays would be named array1980, array1981, etc., would also have length 1000 but would contain 1s where the index in the name was equal to the corresponding element in main and 0s elsewhere. In other words:
for(int i=0; i<1000; i++){
if(main[i]==1980){
array1980[i]=1;
} else {
array1980[i]=0;
}
Of course, I don't want to have to write twenty of these, so it'd be good if I could create new variable names inside a loop. The problem is that you can't generally assign variable names to expressions with operators, e.g.,
String("array"+ j)=... # returns an error
I'm currently using Matlab the most, but I can also do a little in Java, c++ and python, and I'm trying to get an idea for how people go about solving this problem in general. Ideally, I'd like to be able to manipulate the individual variables (or sub-arrays) in some way that the year remains in the variable name (or array index) to reduce the chance for error and to make things easier to deal with in general.
I'd appreciate any help.
boolean main[][] = new boolean[1000][20];
for (int i=0; i < 1000; i++) {
array[i][main[i]-1980] = true;
}
In many cases a map will be a good solution, but here you could use a 2-dim array of booleans, since the size is known before (0-20) and continuous, and numerable.
Some languages will initialize an array of booleans to false for every element, so you would just need to set the values to true, to which main[i] points.
since main[i] returns numbers from 1980 to 2000, 1980-main[i] will return 1980-1980=0 to 2000-1980=20. To find your values, you have to add 1980 to the second index, of course.
The general solution to this is to not create variables with dynamic names, but to instead create a map. Exactly how that's done will vary by language.
For Java, it's worth looking at the map section of the Sun collections tutorial for a start.
Don Roby's answer is correct, but i would like to complete it.
You can use maps for this purpose, and it would look something like this:
Map<Integer,ArrayList<Integer>> yearMap = new HashMap<Integer,ArrayList<Integer>>();
yearMap.put(1980,new ArrayList<Integer>());
for (int i = 0; i < 1000; i++){
yearMap.get(1980).add(0);
}
yearMap.get(1980).set(999,1);
System.out.println(yearMap.get(1980).get(999));
But there is probably a better way to solve the problem that you have. You should not ask how to use X to solve Y, but how to solve Y.
So, what is it, that you are trying to solve?

Categories