alpar@9: /* glpnet04.c (grid-like network problem generator) */ alpar@9: alpar@9: /*********************************************************************** alpar@9: * This code is part of GLPK (GNU Linear Programming Kit). alpar@9: * alpar@9: * This code is a modified version of the program GRIDGEN, a grid-like alpar@9: * network problem generator developed by Yusin Lee and Jim Orlin. alpar@9: * The original code is publically available on the DIMACS ftp site at: alpar@9: * . alpar@9: * alpar@9: * All changes concern only the program interface, so this modified alpar@9: * version produces exactly the same instances as the original version. alpar@9: * alpar@9: * Changes were made by Andrew Makhorin . alpar@9: * alpar@9: * GLPK is free software: you can redistribute it and/or modify it alpar@9: * under the terms of the GNU General Public License as published by alpar@9: * the Free Software Foundation, either version 3 of the License, or alpar@9: * (at your option) any later version. alpar@9: * alpar@9: * GLPK is distributed in the hope that it will be useful, but WITHOUT alpar@9: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY alpar@9: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public alpar@9: * License for more details. alpar@9: * alpar@9: * You should have received a copy of the GNU General Public License alpar@9: * along with GLPK. If not, see . alpar@9: ***********************************************************************/ alpar@9: alpar@9: #include "glpapi.h" alpar@9: alpar@9: /*********************************************************************** alpar@9: * NAME alpar@9: * alpar@9: * glp_gridgen - grid-like network problem generator alpar@9: * alpar@9: * SYNOPSIS alpar@9: * alpar@9: * int glp_gridgen(glp_graph *G, int v_rhs, int a_cap, int a_cost, alpar@9: * const int parm[1+14]); alpar@9: * alpar@9: * DESCRIPTION alpar@9: * alpar@9: * The routine glp_gridgen is a grid-like network problem generator alpar@9: * developed by Yusin Lee and Jim Orlin. alpar@9: * alpar@9: * The parameter G specifies the graph object, to which the generated alpar@9: * problem data have to be stored. Note that on entry the graph object alpar@9: * is erased with the routine glp_erase_graph. alpar@9: * alpar@9: * The parameter v_rhs specifies an offset of the field of type double alpar@9: * in the vertex data block, to which the routine stores the supply or alpar@9: * demand value. If v_rhs < 0, the value is not stored. alpar@9: * alpar@9: * The parameter a_cap specifies an offset of the field of type double alpar@9: * in the arc data block, to which the routine stores the arc capacity. alpar@9: * If a_cap < 0, the capacity is not stored. alpar@9: * alpar@9: * The parameter a_cost specifies an offset of the field of type double alpar@9: * in the arc data block, to which the routine stores the per-unit cost alpar@9: * if the arc flow. If a_cost < 0, the cost is not stored. alpar@9: * alpar@9: * The array parm contains description of the network to be generated: alpar@9: * alpar@9: * parm[0] not used alpar@9: * parm[1] two-ways arcs indicator: alpar@9: * 1 - if links in both direction should be generated alpar@9: * 0 - otherwise alpar@9: * parm[2] random number seed (a positive integer) alpar@9: * parm[3] number of nodes (the number of nodes generated might be alpar@9: * slightly different to make the network a grid) alpar@9: * parm[4] grid width alpar@9: * parm[5] number of sources alpar@9: * parm[6] number of sinks alpar@9: * parm[7] average degree alpar@9: * parm[8] total flow alpar@9: * parm[9] distribution of arc costs: alpar@9: * 1 - uniform alpar@9: * 2 - exponential alpar@9: * parm[10] lower bound for arc cost (uniform) alpar@9: * 100 * lambda (exponential) alpar@9: * parm[11] upper bound for arc cost (uniform) alpar@9: * not used (exponential) alpar@9: * parm[12] distribution of arc capacities: alpar@9: * 1 - uniform alpar@9: * 2 - exponential alpar@9: * parm[13] lower bound for arc capacity (uniform) alpar@9: * 100 * lambda (exponential) alpar@9: * parm[14] upper bound for arc capacity (uniform) alpar@9: * not used (exponential) alpar@9: * alpar@9: * RETURNS alpar@9: * alpar@9: * If the instance was successfully generated, the routine glp_gridgen alpar@9: * returns zero; otherwise, if specified parameters are inconsistent, alpar@9: * the routine returns a non-zero error code. alpar@9: * alpar@9: * COMMENTS alpar@9: * alpar@9: * This network generator generates a grid-like network plus a super alpar@9: * node. In additional to the arcs connecting the nodes in the grid, alpar@9: * there is an arc from each supply node to the super node and from the alpar@9: * super node to each demand node to guarantee feasiblity. These arcs alpar@9: * have very high costs and very big capacities. alpar@9: * alpar@9: * The idea of this network generator is as follows: First, a grid of alpar@9: * n1 * n2 is generated. For example, 5 * 3. The nodes are numbered as alpar@9: * 1 to 15, and the supernode is numbered as n1*n2+1. Then arcs between alpar@9: * adjacent nodes are generated. For these arcs, the user is allowed to alpar@9: * specify either to generate two-way arcs or one-way arcs. If two-way alpar@9: * arcs are to be generated, two arcs, one in each direction, will be alpar@9: * generated between each adjacent node pairs. Otherwise, only one arc alpar@9: * will be generated. If this is the case, the arcs will be generated alpar@9: * in alterntive directions as shown below. alpar@9: * alpar@9: * 1 ---> 2 ---> 3 ---> 4 ---> 5 alpar@9: * | ^ | ^ | alpar@9: * | | | | | alpar@9: * V | V | V alpar@9: * 6 <--- 7 <--- 8 <--- 9 <--- 10 alpar@9: * | ^ | ^ | alpar@9: * | | | | | alpar@9: * V | V | V alpar@9: * 11 --->12 --->13 --->14 ---> 15 alpar@9: * alpar@9: * Then the arcs between the super node and the source/sink nodes are alpar@9: * added as mentioned before. If the number of arcs still doesn't reach alpar@9: * the requirement, additional arcs will be added by uniformly picking alpar@9: * random node pairs. There is no checking to prevent multiple arcs alpar@9: * between any pair of nodes. However, there will be no self-arcs (arcs alpar@9: * that poins back to its tail node) in the network. alpar@9: * alpar@9: * The source and sink nodes are selected uniformly in the network, and alpar@9: * the imbalances of each source/sink node are also assigned by uniform alpar@9: * distribution. */ alpar@9: alpar@9: struct stat_para alpar@9: { /* structure for statistical distributions */ alpar@9: int distribution; alpar@9: /* the distribution: */ alpar@9: #define UNIFORM 1 /* uniform distribution */ alpar@9: #define EXPONENTIAL 2 /* exponential distribution */ alpar@9: double parameter[5]; alpar@9: /* the parameters of the distribution */ alpar@9: }; alpar@9: alpar@9: struct arcs alpar@9: { int from; alpar@9: /* the FROM node of that arc */ alpar@9: int to; alpar@9: /* the TO node of that arc */ alpar@9: int cost; alpar@9: /* original cost of that arc */ alpar@9: int u; alpar@9: /* capacity of the arc */ alpar@9: }; alpar@9: alpar@9: struct imbalance alpar@9: { int node; alpar@9: /* Node ID */ alpar@9: int supply; alpar@9: /* Supply of that node */ alpar@9: }; alpar@9: alpar@9: struct csa alpar@9: { /* common storage area */ alpar@9: glp_graph *G; alpar@9: int v_rhs, a_cap, a_cost; alpar@9: int seed; alpar@9: /* random number seed */ alpar@9: int seed_original; alpar@9: /* the original seed from input */ alpar@9: int two_way; alpar@9: /* 0: generate arcs in both direction for the basic grid, except alpar@9: for the arcs to/from the super node. 1: o/w */ alpar@9: int n_node; alpar@9: /* total number of nodes in the network, numbered 1 to n_node, alpar@9: including the super node, which is the last one */ alpar@9: int n_arc; alpar@9: /* total number of arcs in the network, counting EVERY arc. */ alpar@9: int n_grid_arc; alpar@9: /* number of arcs in the basic grid, including the arcs to/from alpar@9: the super node */ alpar@9: int n_source, n_sink; alpar@9: /* number of source and sink nodes */ alpar@9: int avg_degree; alpar@9: /* average degree, arcs to and from the super node are counted */ alpar@9: int t_supply; alpar@9: /* total supply in the network */ alpar@9: int n1, n2; alpar@9: /* the two edges of the network grid. n1 >= n2 */ alpar@9: struct imbalance *source_list, *sink_list; alpar@9: /* head of the array of source/sink nodes */ alpar@9: struct stat_para arc_costs; alpar@9: /* the distribution of arc costs */ alpar@9: struct stat_para capacities; alpar@9: /* distribution of the capacities of the arcs */ alpar@9: struct arcs *arc_list; alpar@9: /* head of the arc list array. Arcs in this array are in the alpar@9: order of grid_arcs, arcs to/from super node, and other arcs */ alpar@9: }; alpar@9: alpar@9: #define G (csa->G) alpar@9: #define v_rhs (csa->v_rhs) alpar@9: #define a_cap (csa->a_cap) alpar@9: #define a_cost (csa->a_cost) alpar@9: #define seed (csa->seed) alpar@9: #define seed_original (csa->seed_original) alpar@9: #define two_way (csa->two_way) alpar@9: #define n_node (csa->n_node) alpar@9: #define n_arc (csa->n_arc) alpar@9: #define n_grid_arc (csa->n_grid_arc) alpar@9: #define n_source (csa->n_source) alpar@9: #define n_sink (csa->n_sink) alpar@9: #define avg_degree (csa->avg_degree) alpar@9: #define t_supply (csa->t_supply) alpar@9: #define n1 (csa->n1) alpar@9: #define n2 (csa->n2) alpar@9: #define source_list (csa->source_list) alpar@9: #define sink_list (csa->sink_list) alpar@9: #define arc_costs (csa->arc_costs) alpar@9: #define capacities (csa->capacities) alpar@9: #define arc_list (csa->arc_list) alpar@9: alpar@9: static void assign_capacities(struct csa *csa); alpar@9: static void assign_costs(struct csa *csa); alpar@9: static void assign_imbalance(struct csa *csa); alpar@9: static int exponential(struct csa *csa, double lambda[1]); alpar@9: static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs alpar@9: *arc_ptr); alpar@9: static struct arcs *gen_basic_grid(struct csa *csa, struct arcs alpar@9: *arc_ptr); alpar@9: static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr); alpar@9: static void generate(struct csa *csa); alpar@9: static void output(struct csa *csa); alpar@9: static double randy(struct csa *csa); alpar@9: static void select_source_sinks(struct csa *csa); alpar@9: static int uniform(struct csa *csa, double a[2]); alpar@9: alpar@9: int glp_gridgen(glp_graph *G_, int _v_rhs, int _a_cap, int _a_cost, alpar@9: const int parm[1+14]) alpar@9: { struct csa _csa, *csa = &_csa; alpar@9: int n, ret; alpar@9: G = G_; alpar@9: v_rhs = _v_rhs; alpar@9: a_cap = _a_cap; alpar@9: a_cost = _a_cost; alpar@9: if (G != NULL) alpar@9: { if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) alpar@9: xerror("glp_gridgen: v_rhs = %d; invalid offset\n", v_rhs); alpar@9: if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) alpar@9: xerror("glp_gridgen: a_cap = %d; invalid offset\n", a_cap); alpar@9: if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) alpar@9: xerror("glp_gridgen: a_cost = %d; invalid offset\n", a_cost) alpar@9: ; alpar@9: } alpar@9: /* Check the parameters for consistency. */ alpar@9: if (!(parm[1] == 0 || parm[1] == 1)) alpar@9: { ret = 1; alpar@9: goto done; alpar@9: } alpar@9: if (parm[2] < 1) alpar@9: { ret = 2; alpar@9: goto done; alpar@9: } alpar@9: if (!(10 <= parm[3] && parm[3] <= 40000)) alpar@9: { ret = 3; alpar@9: goto done; alpar@9: } alpar@9: if (!(1 <= parm[4] && parm[4] <= 40000)) alpar@9: { ret = 4; alpar@9: goto done; alpar@9: } alpar@9: if (!(parm[5] >= 0 && parm[6] >= 0 && parm[5] + parm[6] <= alpar@9: parm[3])) alpar@9: { ret = 5; alpar@9: goto done; alpar@9: } alpar@9: if (!(1 <= parm[7] && parm[7] <= parm[3])) alpar@9: { ret = 6; alpar@9: goto done; alpar@9: } alpar@9: if (parm[8] < 0) alpar@9: { ret = 7; alpar@9: goto done; alpar@9: } alpar@9: if (!(parm[9] == 1 || parm[9] == 2)) alpar@9: { ret = 8; alpar@9: goto done; alpar@9: } alpar@9: if (parm[9] == 1 && parm[10] > parm[11] || alpar@9: parm[9] == 2 && parm[10] < 1) alpar@9: { ret = 9; alpar@9: goto done; alpar@9: } alpar@9: if (!(parm[12] == 1 || parm[12] == 2)) alpar@9: { ret = 10; alpar@9: goto done; alpar@9: } alpar@9: if (parm[12] == 1 && !(0 <= parm[13] && parm[13] <= parm[14]) || alpar@9: parm[12] == 2 && parm[13] < 1) alpar@9: { ret = 11; alpar@9: goto done; alpar@9: } alpar@9: /* Initialize the graph object. */ alpar@9: if (G != NULL) alpar@9: { glp_erase_graph(G, G->v_size, G->a_size); alpar@9: glp_set_graph_name(G, "GRIDGEN"); alpar@9: } alpar@9: /* Copy the generator parameters. */ alpar@9: two_way = parm[1]; alpar@9: seed_original = seed = parm[2]; alpar@9: n_node = parm[3]; alpar@9: n = parm[4]; alpar@9: n_source = parm[5]; alpar@9: n_sink = parm[6]; alpar@9: avg_degree = parm[7]; alpar@9: t_supply = parm[8]; alpar@9: arc_costs.distribution = parm[9]; alpar@9: if (parm[9] == 1) alpar@9: { arc_costs.parameter[0] = parm[10]; alpar@9: arc_costs.parameter[1] = parm[11]; alpar@9: } alpar@9: else alpar@9: { arc_costs.parameter[0] = (double)parm[10] / 100.0; alpar@9: arc_costs.parameter[1] = 0.0; alpar@9: } alpar@9: capacities.distribution = parm[12]; alpar@9: if (parm[12] == 1) alpar@9: { capacities.parameter[0] = parm[13]; alpar@9: capacities.parameter[1] = parm[14]; alpar@9: } alpar@9: else alpar@9: { capacities.parameter[0] = (double)parm[13] / 100.0; alpar@9: capacities.parameter[1] = 0.0; alpar@9: } alpar@9: /* Calculate the edge lengths of the grid according to the alpar@9: input. */ alpar@9: if (n * n >= n_node) alpar@9: { n1 = n; alpar@9: n2 = (int)((double)n_node / (double)n + 0.5); alpar@9: } alpar@9: else alpar@9: { n2 = n; alpar@9: n1 = (int)((double)n_node / (double)n + 0.5); alpar@9: } alpar@9: /* Recalculate the total number of nodes and plus 1 for the super alpar@9: node. */ alpar@9: n_node = n1 * n2 + 1; alpar@9: n_arc = n_node * avg_degree; alpar@9: n_grid_arc = (two_way + 1) * ((n1 - 1) * n2 + (n2 - 1) * n1) + alpar@9: n_source + n_sink; alpar@9: if (n_grid_arc > n_arc) n_arc = n_grid_arc; alpar@9: arc_list = xcalloc(n_arc, sizeof(struct arcs)); alpar@9: source_list = xcalloc(n_source, sizeof(struct imbalance)); alpar@9: sink_list = xcalloc(n_sink, sizeof(struct imbalance)); alpar@9: /* Generate a random network. */ alpar@9: generate(csa); alpar@9: /* Output the network. */ alpar@9: output(csa); alpar@9: /* Free all allocated memory. */ alpar@9: xfree(arc_list); alpar@9: xfree(source_list); alpar@9: xfree(sink_list); alpar@9: /* The instance has been successfully generated. */ alpar@9: ret = 0; alpar@9: done: return ret; alpar@9: } alpar@9: alpar@9: #undef random alpar@9: alpar@9: static void assign_capacities(struct csa *csa) alpar@9: { /* Assign a capacity to each arc. */ alpar@9: struct arcs *arc_ptr = arc_list; alpar@9: int (*random)(struct csa *csa, double *); alpar@9: int i; alpar@9: /* Determine the random number generator to use. */ alpar@9: switch (arc_costs.distribution) alpar@9: { case UNIFORM: alpar@9: random = uniform; alpar@9: break; alpar@9: case EXPONENTIAL: alpar@9: random = exponential; alpar@9: break; alpar@9: default: alpar@9: xassert(csa != csa); alpar@9: } alpar@9: /* Assign capacities to grid arcs. */ alpar@9: for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++) alpar@9: arc_ptr->u = random(csa, capacities.parameter); alpar@9: i = i - n_source - n_sink; alpar@9: /* Assign capacities to arcs to/from supernode. */ alpar@9: for (; i < n_grid_arc; i++, arc_ptr++) alpar@9: arc_ptr->u = t_supply; alpar@9: /* Assign capacities to all other arcs. */ alpar@9: for (; i < n_arc; i++, arc_ptr++) alpar@9: arc_ptr->u = random(csa, capacities.parameter); alpar@9: return; alpar@9: } alpar@9: alpar@9: static void assign_costs(struct csa *csa) alpar@9: { /* Assign a cost to each arc. */ alpar@9: struct arcs *arc_ptr = arc_list; alpar@9: int (*random)(struct csa *csa, double *); alpar@9: int i; alpar@9: /* A high cost assigned to arcs to/from the supernode. */ alpar@9: int high_cost; alpar@9: /* The maximum cost assigned to arcs in the base grid. */ alpar@9: int max_cost = 0; alpar@9: /* Determine the random number generator to use. */ alpar@9: switch (arc_costs.distribution) alpar@9: { case UNIFORM: alpar@9: random = uniform; alpar@9: break; alpar@9: case EXPONENTIAL: alpar@9: random = exponential; alpar@9: break; alpar@9: default: alpar@9: xassert(csa != csa); alpar@9: } alpar@9: /* Assign costs to arcs in the base grid. */ alpar@9: for (i = n_source + n_sink; i < n_grid_arc; i++, arc_ptr++) alpar@9: { arc_ptr->cost = random(csa, arc_costs.parameter); alpar@9: if (max_cost < arc_ptr->cost) max_cost = arc_ptr->cost; alpar@9: } alpar@9: i = i - n_source - n_sink; alpar@9: /* Assign costs to arcs to/from the super node. */ alpar@9: high_cost = max_cost * 2; alpar@9: for (; i < n_grid_arc; i++, arc_ptr++) alpar@9: arc_ptr->cost = high_cost; alpar@9: /* Assign costs to all other arcs. */ alpar@9: for (; i < n_arc; i++, arc_ptr++) alpar@9: arc_ptr->cost = random(csa, arc_costs.parameter); alpar@9: return; alpar@9: } alpar@9: alpar@9: static void assign_imbalance(struct csa *csa) alpar@9: { /* Assign an imbalance to each node. */ alpar@9: int total, i; alpar@9: double avg; alpar@9: struct imbalance *ptr; alpar@9: /* assign the supply nodes */ alpar@9: avg = 2.0 * t_supply / n_source; alpar@9: do alpar@9: { for (i = 1, total = t_supply, ptr = source_list + 1; alpar@9: i < n_source; i++, ptr++) alpar@9: { ptr->supply = (int)(randy(csa) * avg + 0.5); alpar@9: total -= ptr->supply; alpar@9: } alpar@9: source_list->supply = total; alpar@9: } alpar@9: /* redo all if the assignment "overshooted" */ alpar@9: while (total <= 0); alpar@9: /* assign the demand nodes */ alpar@9: avg = -2.0 * t_supply / n_sink; alpar@9: do alpar@9: { for (i = 1, total = t_supply, ptr = sink_list + 1; alpar@9: i < n_sink; i++, ptr++) alpar@9: { ptr->supply = (int)(randy(csa) * avg - 0.5); alpar@9: total += ptr->supply; alpar@9: } alpar@9: sink_list->supply = - total; alpar@9: } alpar@9: while (total <= 0); alpar@9: return; alpar@9: } alpar@9: alpar@9: static int exponential(struct csa *csa, double lambda[1]) alpar@9: { /* Returns an "exponentially distributed" integer with parameter alpar@9: lambda. */ alpar@9: return ((int)(- lambda[0] * log((double)randy(csa)) + 0.5)); alpar@9: } alpar@9: alpar@9: static struct arcs *gen_additional_arcs(struct csa *csa, struct arcs alpar@9: *arc_ptr) alpar@9: { /* Generate an arc from each source to the supernode and from alpar@9: supernode to each sink. */ alpar@9: int i; alpar@9: for (i = 0; i < n_source; i++, arc_ptr++) alpar@9: { arc_ptr->from = source_list[i].node; alpar@9: arc_ptr->to = n_node; alpar@9: } alpar@9: for (i = 0; i < n_sink; i++, arc_ptr++) alpar@9: { arc_ptr->to = sink_list[i].node; alpar@9: arc_ptr->from = n_node; alpar@9: } alpar@9: return arc_ptr; alpar@9: } alpar@9: alpar@9: static struct arcs *gen_basic_grid(struct csa *csa, struct arcs alpar@9: *arc_ptr) alpar@9: { /* Generate the basic grid. */ alpar@9: int direction = 1, i, j, k; alpar@9: if (two_way) alpar@9: { /* Generate an arc in each direction. */ alpar@9: for (i = 1; i < n_node; i += n1) alpar@9: { for (j = i, k = j + n1 - 1; j < k; j++) alpar@9: { arc_ptr->from = j; alpar@9: arc_ptr->to = j + 1; alpar@9: arc_ptr++; alpar@9: arc_ptr->from = j + 1; alpar@9: arc_ptr->to = j; alpar@9: arc_ptr++; alpar@9: } alpar@9: } alpar@9: for (i = 1; i <= n1; i++) alpar@9: { for (j = i + n1; j < n_node; j += n1) alpar@9: { arc_ptr->from = j; alpar@9: arc_ptr->to = j - n1; alpar@9: arc_ptr++; alpar@9: arc_ptr->from = j - n1; alpar@9: arc_ptr->to = j; alpar@9: arc_ptr++; alpar@9: } alpar@9: } alpar@9: } alpar@9: else alpar@9: { /* Generate one arc in each direction. */ alpar@9: for (i = 1; i < n_node; i += n1) alpar@9: { if (direction == 1) alpar@9: j = i; alpar@9: else alpar@9: j = i + 1; alpar@9: for (k = j + n1 - 1; j < k; j++) alpar@9: { arc_ptr->from = j; alpar@9: arc_ptr->to = j + direction; alpar@9: arc_ptr++; alpar@9: } alpar@9: direction = - direction; alpar@9: } alpar@9: for (i = 1; i <= n1; i++) alpar@9: { j = i + n1; alpar@9: if (direction == 1) alpar@9: { for (; j < n_node; j += n1) alpar@9: { arc_ptr->from = j - n1; alpar@9: arc_ptr->to = j; alpar@9: arc_ptr++; alpar@9: } alpar@9: } alpar@9: else alpar@9: { for (; j < n_node; j += n1) alpar@9: { arc_ptr->from = j - n1; alpar@9: arc_ptr->to = j; alpar@9: arc_ptr++; alpar@9: } alpar@9: } alpar@9: direction = - direction; alpar@9: } alpar@9: } alpar@9: return arc_ptr; alpar@9: } alpar@9: alpar@9: static void gen_more_arcs(struct csa *csa, struct arcs *arc_ptr) alpar@9: { /* Generate random arcs to meet the specified density. */ alpar@9: int i; alpar@9: double ab[2]; alpar@9: ab[0] = 0.9; alpar@9: ab[1] = n_node - 0.99; /* upper limit is n_node-1 because the alpar@9: supernode cannot be selected */ alpar@9: for (i = n_grid_arc; i < n_arc; i++, arc_ptr++) alpar@9: { arc_ptr->from = uniform(csa, ab); alpar@9: arc_ptr->to = uniform(csa, ab); alpar@9: if (arc_ptr->from == arc_ptr->to) alpar@9: { arc_ptr--; alpar@9: i--; alpar@9: } alpar@9: } alpar@9: return; alpar@9: } alpar@9: alpar@9: static void generate(struct csa *csa) alpar@9: { /* Generate a random network. */ alpar@9: struct arcs *arc_ptr = arc_list; alpar@9: arc_ptr = gen_basic_grid(csa, arc_ptr); alpar@9: select_source_sinks(csa); alpar@9: arc_ptr = gen_additional_arcs(csa, arc_ptr); alpar@9: gen_more_arcs(csa, arc_ptr); alpar@9: assign_costs(csa); alpar@9: assign_capacities(csa); alpar@9: assign_imbalance(csa); alpar@9: return; alpar@9: } alpar@9: alpar@9: static void output(struct csa *csa) alpar@9: { /* Output the network in DIMACS format. */ alpar@9: struct arcs *arc_ptr; alpar@9: struct imbalance *imb_ptr; alpar@9: int i; alpar@9: if (G != NULL) goto skip; alpar@9: /* Output "c", "p" records. */ alpar@9: xprintf("c generated by GRIDGEN\n"); alpar@9: xprintf("c seed %d\n", seed_original); alpar@9: xprintf("c nodes %d\n", n_node); alpar@9: xprintf("c grid size %d X %d\n", n1, n2); alpar@9: xprintf("c sources %d sinks %d\n", n_source, n_sink); alpar@9: xprintf("c avg. degree %d\n", avg_degree); alpar@9: xprintf("c supply %d\n", t_supply); alpar@9: switch (arc_costs.distribution) alpar@9: { case UNIFORM: alpar@9: xprintf("c arc costs: UNIFORM distr. min %d max %d\n", alpar@9: (int)arc_costs.parameter[0], alpar@9: (int)arc_costs.parameter[1]); alpar@9: break; alpar@9: case EXPONENTIAL: alpar@9: xprintf("c arc costs: EXPONENTIAL distr. lambda %d\n", alpar@9: (int)arc_costs.parameter[0]); alpar@9: break; alpar@9: default: alpar@9: xassert(csa != csa); alpar@9: } alpar@9: switch (capacities.distribution) alpar@9: { case UNIFORM: alpar@9: xprintf("c arc caps : UNIFORM distr. min %d max %d\n", alpar@9: (int)capacities.parameter[0], alpar@9: (int)capacities.parameter[1]); alpar@9: break; alpar@9: case EXPONENTIAL: alpar@9: xprintf("c arc caps : EXPONENTIAL distr. %d lambda %d\n", alpar@9: (int)capacities.parameter[0]); alpar@9: break; alpar@9: default: alpar@9: xassert(csa != csa); alpar@9: } alpar@9: skip: if (G == NULL) alpar@9: xprintf("p min %d %d\n", n_node, n_arc); alpar@9: else alpar@9: { glp_add_vertices(G, n_node); alpar@9: if (v_rhs >= 0) alpar@9: { double zero = 0.0; alpar@9: for (i = 1; i <= n_node; i++) alpar@9: { glp_vertex *v = G->v[i]; alpar@9: memcpy((char *)v->data + v_rhs, &zero, sizeof(double)); alpar@9: } alpar@9: } alpar@9: } alpar@9: /* Output "n node supply". */ alpar@9: for (i = 0, imb_ptr = source_list; i < n_source; i++, imb_ptr++) alpar@9: { if (G == NULL) alpar@9: xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply); alpar@9: else alpar@9: { if (v_rhs >= 0) alpar@9: { double temp = (double)imb_ptr->supply; alpar@9: glp_vertex *v = G->v[imb_ptr->node]; alpar@9: memcpy((char *)v->data + v_rhs, &temp, sizeof(double)); alpar@9: } alpar@9: } alpar@9: } alpar@9: for (i = 0, imb_ptr = sink_list; i < n_sink; i++, imb_ptr++) alpar@9: { if (G == NULL) alpar@9: xprintf("n %d %d\n", imb_ptr->node, imb_ptr->supply); alpar@9: else alpar@9: { if (v_rhs >= 0) alpar@9: { double temp = (double)imb_ptr->supply; alpar@9: glp_vertex *v = G->v[imb_ptr->node]; alpar@9: memcpy((char *)v->data + v_rhs, &temp, sizeof(double)); alpar@9: } alpar@9: } alpar@9: } alpar@9: /* Output "a from to lowcap=0 hicap cost". */ alpar@9: for (i = 0, arc_ptr = arc_list; i < n_arc; i++, arc_ptr++) alpar@9: { if (G == NULL) alpar@9: xprintf("a %d %d 0 %d %d\n", arc_ptr->from, arc_ptr->to, alpar@9: arc_ptr->u, arc_ptr->cost); alpar@9: else alpar@9: { glp_arc *a = glp_add_arc(G, arc_ptr->from, arc_ptr->to); alpar@9: if (a_cap >= 0) alpar@9: { double temp = (double)arc_ptr->u; alpar@9: memcpy((char *)a->data + a_cap, &temp, sizeof(double)); alpar@9: } alpar@9: if (a_cost >= 0) alpar@9: { double temp = (double)arc_ptr->cost; alpar@9: memcpy((char *)a->data + a_cost, &temp, sizeof(double)); alpar@9: } alpar@9: } alpar@9: } alpar@9: return; alpar@9: } alpar@9: alpar@9: static double randy(struct csa *csa) alpar@9: { /* Returns a random number between 0.0 and 1.0. alpar@9: See Ward Cheney & David Kincaid, "Numerical Mathematics and alpar@9: Computing," 2Ed, pp. 335. */ alpar@9: seed = 16807 * seed % 2147483647; alpar@9: if (seed < 0) seed = - seed; alpar@9: return seed * 4.6566128752459e-10; alpar@9: } alpar@9: alpar@9: static void select_source_sinks(struct csa *csa) alpar@9: { /* Randomly select the source nodes and sink nodes. */ alpar@9: int i, *int_ptr; alpar@9: int *temp_list; /* a temporary list of nodes */ alpar@9: struct imbalance *ptr; alpar@9: double ab[2]; /* parameter for random number generator */ alpar@9: ab[0] = 0.9; alpar@9: ab[1] = n_node - 0.99; /* upper limit is n_node-1 because the alpar@9: supernode cannot be selected */ alpar@9: temp_list = xcalloc(n_node, sizeof(int)); alpar@9: for (i = 0, int_ptr = temp_list; i < n_node; i++, int_ptr++) alpar@9: *int_ptr = 0; alpar@9: /* Select the source nodes. */ alpar@9: for (i = 0, ptr = source_list; i < n_source; i++, ptr++) alpar@9: { ptr->node = uniform(csa, ab); alpar@9: if (temp_list[ptr->node] == 1) /* check for duplicates */ alpar@9: { ptr--; alpar@9: i--; alpar@9: } alpar@9: else alpar@9: temp_list[ptr->node] = 1; alpar@9: } alpar@9: /* Select the sink nodes. */ alpar@9: for (i = 0, ptr = sink_list; i < n_sink; i++, ptr++) alpar@9: { ptr->node = uniform(csa, ab); alpar@9: if (temp_list[ptr->node] == 1) alpar@9: { ptr--; alpar@9: i--; alpar@9: } alpar@9: else alpar@9: temp_list[ptr->node] = 1; alpar@9: } alpar@9: xfree(temp_list); alpar@9: return; alpar@9: } alpar@9: alpar@9: int uniform(struct csa *csa, double a[2]) alpar@9: { /* Generates an integer uniformly selected from [a[0],a[1]]. */ alpar@9: return (int)((a[1] - a[0]) * randy(csa) + a[0] + 0.5); alpar@9: } alpar@9: alpar@9: /**********************************************************************/ alpar@9: alpar@9: #if 0 alpar@9: int main(void) alpar@9: { int parm[1+14]; alpar@9: double temp; alpar@9: scanf("%d", &parm[1]); alpar@9: scanf("%d", &parm[2]); alpar@9: scanf("%d", &parm[3]); alpar@9: scanf("%d", &parm[4]); alpar@9: scanf("%d", &parm[5]); alpar@9: scanf("%d", &parm[6]); alpar@9: scanf("%d", &parm[7]); alpar@9: scanf("%d", &parm[8]); alpar@9: scanf("%d", &parm[9]); alpar@9: if (parm[9] == 1) alpar@9: { scanf("%d", &parm[10]); alpar@9: scanf("%d", &parm[11]); alpar@9: } alpar@9: else alpar@9: { scanf("%le", &temp); alpar@9: parm[10] = (int)(100.0 * temp + .5); alpar@9: parm[11] = 0; alpar@9: } alpar@9: scanf("%d", &parm[12]); alpar@9: if (parm[12] == 1) alpar@9: { scanf("%d", &parm[13]); alpar@9: scanf("%d", &parm[14]); alpar@9: } alpar@9: else alpar@9: { scanf("%le", &temp); alpar@9: parm[13] = (int)(100.0 * temp + .5); alpar@9: parm[14] = 0; alpar@9: } alpar@9: glp_gridgen(NULL, 0, 0, 0, parm); alpar@9: return 0; alpar@9: } alpar@9: #endif alpar@9: alpar@9: /* eof */