3

Я пытаюсь реализовать ILP с использованием CPLEX Java и долгое время сталкивался с проблемой. Вот несколько переменных НРП:cplex boolVarArray, дающий двойные значения

IloIntVar above = new IloIntVar[numRect][]; 
IloIntVar below = new IloIntVar[numRect][]; 
IloIntVar left = new IloIntVar[numRect][]; 
IloIntVar right = new IloIntVar[numRect][]; 

for (int i = 0; i < numRect; i++) { 
     above[i] = cplex.boolVarArray(numRect); 
     below[i] = cplex.boolVarArray(numRect); 
     left[i] = cplex.boolVarArray(numRect); 
     right[i] = cplex.boolVarArray(numRect); 
} 

Значение numRect равно 1. В конце вывода программы I эти значения:

for (int i = 0; i < numRect; i++) { 
      for (int j = i + 1; j < numRect; j++) { 
       System.out.println(cplex.getValue(left[i][j])); 
       System.out.println(cplex.getValue(right[i][j])); 
       System.out.println(cplex.getValue(above[i][j])); 
       System.out.println(cplex.getValue(below[i][j])); 
       System.out.println(cplex.getValue(left[i][j]) + 
            cplex.getValue(right[i][j]) + 
            cplex.getValue(above[i][j]) + 
            cplex.getValue(below[i][j])); 
      } 
     } 

Вот выход я получаю:

0.0 
0.0 
9.313225750491594E-10 
0.9999999990686774 
1.0 

Я не понимаю, почему я получаю двойные значения вместо булевых. Любая помощь будет оценена по достоинству. Благодарю.

ответ

1

IloBoolVar - это просто IloNumVar, ограниченное 0 или 1. По умолчанию все, что находится в пределах 0,00001 из 0 или 1, считаются целыми числами. Вы можете изменить это, установив параметр EpInt. Параметр может быть установлен на ноль, но вы вызываете проблемы с производительностью. Это лучшая практика для округления ценностей. Фактически, в любое время, когда вы работаете с числами с плавающей запятой, вам нужно знать о проблемах округления, подобных этому.

+0

Спасибо. Это была большая помощь. – user1009285

0

Вы не сказали, на каком языке вы используете. По некоторым причинам, версия C++ Концерта имеет

IloCplex.GetIntValue() 

и вы получите 0 или 1.

Концерт для Java и C# (я не знаю о других языках) только IloCplex.GetValue(). Вам нужно округлить значения до 0 или 1. Я также должен сначала проверить, что значения находятся в пределах небольшого значения нуля или одного, просто чтобы убедиться, что вы фактически решаете MIP, а не LP.

+0

Благодарим вас за ответ. Я использую Java. Значения для булевых переменных очень близки к 0 или 1, как вы могли видеть на выходе. Две из моих переменных являются линейными, четыре из которых являются логическими. Я думаю, я должен игнорировать двойные значения, которые получаю, как вы сказали, потому что они очень близки к 0 или 1. – user1009285

+1

Да! Как сказал Дэвид Нехме в своем ответе, пока они находятся внутри EpInt целого числа, все в порядке. Я также добавлю его примечание о том, что вы не должны гасить с помощью EpInt или других параметров допуска. – raoulcousins

+0

Я решил не вмешиваться в этот параметр. Даже когда я установил его на 0, это не сработало для меня. Мое ограничение: t1 + d <= t2 + Integer.Max_value * (1-b). Здесь b - логическая переменная, t1 и t2 - целые переменные, а d - целое число, значение которого уже определено. Поскольку значение Integer.Max_value настолько велико, cplex делает b очень маленьким (например, 0.9999992) и делает условие истинным. Когда я попытался исправить, установив EPInt в 0, он дал boolean переменную значение b, но другие переменные указывают, что ограничения не были применены. Поэтому я заменил значение Interger.max некоторым другим целым числом, и он сработал. – user1009285