问题
my question is related to my previous question. I should make some change in my code. I have a number of nodes between 1 to 100 in the CSV file. I create another CSV file and generate 20 random numbers between the 100 nodes and called them demand points. Each of this demand point has specific demands which are the randomly generate numbers between 1 to 10. I want to read this demand points(the indexes) and their weights. this is the first part of my question? how can I read this? After that, I need to have a distance between each of these demand points and all nodes. I don't how can I just read the indexes of demand points and calculate the distance between them and all the nodes. Based on the code that I provided, I need the indexes of demand points for a lot of places. My main problem is that I don't know how should I get these indexes in Cplex through the CSV file. The demand points with their demands picture is: first column is demandpointindex and second column in their demands this file has 200 rows
I tried this code for reading the demand points:
tuple demands
{
int demandpoint;
int weight;
}
{demands} demand={};
execute
{
var f=new IloOplInputFile("weight.csv");
while (!f.eof)
{
var data = f.readline().split(",");
if (ar.length==2)
demand.add(Opl.intValue(ar[0]),Opl.intValue(ar[1]));
}
f.close();
}
execute
{
writeln(demand);
}
but it's not true.
int n=100;
int p=5;
tuple demands
{
int demandpointindex;
int weight;
}
{demands} demand={};
execute
{
var f=new IloOplInputFile("weight.csv");
while (!f.eof)
{
var data = f.readline().split(",");
if (ar.length==2)
demand.add(Opl.intValue(ar[0]),Opl.intValue(ar[1]));
}
f.close();
}
execute
{
writeln(demand);
}
float d[demandpointindexes][facilities];
execute {
var f = new IloOplInputFile("test1.csv");
while (!f.eof) {
var data = f.readline().split(",");
if (data.length == 3)
d[Opl.intValue(data[0])][Opl.intValue(data[1])] = Opl.floatValue(data[2]);
}
writeln(d);
}
dvar boolean x[demandpointindexe][facilities];
...
回答1:
I hope I got your explanation right. Assume you have a file weight.csv
like this:
1,2,
3,7,
4,9,
Here the first item in each row is the index of a demand point, the second item is its weight. Then you can parse this as before using this scripting block:
tuple demandpoint {
int index;
int weight;
}
{demandpoint} demand={};
execute {
var f = new IloOplInputFile("weight.csv");
while (!f.eof) {
var data = f.readline().split(",");
if (data.length == 3)
demand.add(Opl.intValue(data[0]), Opl.intValue(data[1]));
}
writeln(demand);
}
Next you can create a set that contains the indeces of all the demand points:
{int} demandpoints = { d.index | d in demand };
Assume file test1.csv looks like this
1,1,0,
1,2,5,
1,3,6,
1,4,7,
3,1,1,
3,2,1.5,
3,3,0,
3,4,3.5,
4,1,1,
4,2,1.5,
4,3,1.7,
4,4,0,
Here the first item is a demand point index, the second item is a facility index and the third item is the distance between first and second item. Note that there are no lines that start with 2 since there is no demand point with index 2 in weight.csv
. Also note that I assume only 4 facilities here (to keep the file short). You can read the distance between demand points and facitilies as follows:
range facilities = 1..4;
float d[demandpoints][facilities];
execute {
var f = new IloOplInputFile("test1.csv");
while (!f.eof) {
var data = f.readline().split(",");
if (data.length == 4)
d[Opl.intValue(data[0])][Opl.intValue(data[1])] = Opl.floatValue(data[2]);
}
writeln(d);
}
The full script (including a dummy objective and constraints so that it can be run) looks:
tuple demandpoint {
int index;
int weight;
}
{demandpoint} demand={};
execute {
var f = new IloOplInputFile("weight.csv");
while (!f.eof) {
var data = f.readline().split(",");
if (data.length == 3)
demand.add(Opl.intValue(data[0]), Opl.intValue(data[1]));
}
writeln(demand);
}
// Create a set that contains all the indeces of demand points
// as read from weight.csv
{int} demandpoints = { d.index | d in demand };
range facilities = 1..4;
float d[demandpoints][facilities];
execute {
var f = new IloOplInputFile("test1.csv");
while (!f.eof) {
var data = f.readline().split(",");
if (data.length == 4)
d[Opl.intValue(data[0])][Opl.intValue(data[1])] = Opl.floatValue(data[2]);
}
writeln(d);
}
minimize 0;
subject to {}
It prints
{<1 2> <3 7> <4 9>}
[[0 5 6 7]
[1 1.5 0 3.5]
[1 1.5 1.7 0]]
Be careful about how many commas you have in your csv! The code posted above assumes that each line ends with a comma. That is, each line has as many commas as it has fields. If the last field is not terminated by a comma then you have to adapt the parser.
If you have in test1.csv
the distance between all the nodes then it makes sense to first read the data into an array float distance[facilities][facilities];
and then define the array d
based on that as
float d[i in demandpoints][j in facilities] = distance[i][j];
Update for the more detailed specification you gave in the comments:
In order to handle the test1.csv
you explained in the comments you could define a new tuple:
tuple Distance {
int demandpoint;
int facility;
float distance;
}
{Distance} distances = {};
and read/parse this exactly as you did parse the weight.csv
file (with one additional field, of course).
Then you can create the distance matrix like so:
float d[i in I][j in J] = sum (dist in distances : dist.demandpoint == i && dist.facility == j) dist.distance;
Here I
and J
are the sets or ranges of demand points and facilities, respectively. See above for how you can get a set of all demand points defined in the tuple set. The created matrix will have an entry for each demandpoint/distance pair. The trick in the definition d
is that there are two cases:
- If a pair (i,j) is defined in
test1.csv
then the sum will match exactly one element indistances
: the one that defines the distance between two points. - If a pair (i,j) is not defined in
test1.csv
then the sum will not match anything and the corresponding entry in the distance matrix will thus be 0.
来源:https://stackoverflow.com/questions/56100539/read-csv-file-in-cplex