I have to implement a clustering algorithm, after loading the dataset, I go to check for each point in which cluster it can be inserted. If points cannot be inserted into any cluster, I have to move them from the dataset and insert them into the retained set. Since I do not know a priori the size of the retained set, I allocate an area of memory initially equal to 0 and that is incremented by the bytes size needed to hold a point each time I have to insert a point into the retained set.
It works for some iterations (4 to be precise) and then stops
This is what I try:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <malloc/malloc.h>
#include <float.h>
#include <stdbool.h>
double **load_dataset(char *filename, int d, int chunk_size);
int assign_point_to_cluster(double **clusters, int **set, double **retained_set, double *point,double *standard_deviation,
int d, int k, int *chunk_size, int p_in_r);
int find_candidate_cluster(double **clusters, double *point, double *std_deviation, int d, int k);
double mean(const double *vector, int d);
double mahalanobis(const double *cluster, const double *point, const double *standard_deviation, int d);
void compute_std_dev(const double *cluster, double *standard_deviation_vector, int d);
int inizialize_cluster(double **dataset, int d, int k, double **clusters, int **set, int chunk_size, bool retain);
double compute_sum_of_euclidean_distance(double **center_points, double *point, int n, int d);
void feature_scaling(double **dataset, int d, int chunk_size);
int main(int argc, char **argv) {
if(argc < 6){
printf("Error parameters! Usage: ./main <input_file> <total number of point> <chunk_size> <points_dimension> <cluster_number>");
return 0;
}
char* filename = argv[1];
int d = atoi(argv[4]), k = atoi(argv[5]), chunk_size = atoi(argv[3]), total = atoi(argv[2]);
int k_compressed = 0;
printf("Path: %s\n", filename);
printf("Number of point in set %i\n", total);
printf("chunk size: %i\n", chunk_size);
printf("Dimension of points: %i\n", d);
printf("Number of cluster: %i\n", k);
printf("----------------\n");
double **clusters = malloc(k * sizeof(double *));
double *standard_deviation = malloc(d * sizeof(double));
int **discard_set = malloc(k * sizeof(int *));
double **retained_set = malloc(1);
double * cohesion = malloc(2 * sizeof(double));
double* radius = NULL;
double **mini_cluster = NULL;
double* temp_cluster = NULL;
int** compressed_set = NULL;
double** mini_cluster_temp = NULL;
int p_in_r = 0;
double **dataset = load_dataset(filename, d, chunk_size);
/**
* Rescaling of variables
*/
//feature_scaling(dataset, d, chunk_size); TODO: Something is wrong
/**
* Cluster initialization
*/
if(!clusters || !discard_set || !standard_deviation || !retained_set || !cohesion){
printf("Something went wrong in main(), memory allocation failed!");
exit(1);
}
chunk_size = inizialize_cluster(dataset, d, k, clusters, discard_set, chunk_size, false);
/**
* At this point we are only interested in keeping a "summary" of the data that will be placed within a cluster.
* In dataset we put the id of the points that are added to a cluster, while cluster contains the statistics
* useful to perform clustering
**/
/**
* We start processing the points the (CHUNK - 1)eighth point in the dataset is assigned to the cluster if the
* mahalanobis distance is less than a threshold and if it is the closest.
* Clusetering dataset -> discard_set
*/
while (chunk_size > 0) {
p_in_r += assign_point_to_cluster(clusters, discard_set, retained_set, dataset[chunk_size - 1], standard_deviation, d, k, &chunk_size, p_in_r);
/**
* always working on the last element of the dataset, it is not necessary to move the list of points,
* just delete the last element
*/
free(dataset[chunk_size]);
dataset[chunk_size] = NULL;
dataset = realloc(dataset, chunk_size * sizeof(double *));
if(dataset == NULL){
printf("Something went wrong in main(), memory allocation failed!");
exit(1);
}
}
free(dataset);
dataset = NULL;
return 0;
}
int inizialize_cluster(double **dataset, int d, int k, double ** clusters, int** set, int chunk_size, bool retain) {
double ** center_point = malloc(k * sizeof(double *));
for (int i = 0; i < k; i++) {
center_point[i] = malloc((d + 1) * sizeof(double));
if(center_point[i] == NULL){
printf("Something went wrong in inizialize_cluster(), memory allocation failed!");
exit(1);
}
}
/**
* The point representing the center of the first cluster is chosen as the first point in the dataset
**/
memcpy(*center_point, *dataset, (d + 1) * sizeof(double));
/**
* The first point can be removed from the dataset or
* in case we are working on the retained set, move it to the end.
**/
chunk_size--;
if(retain){
double* temp = malloc(sizeof(double *));
memcpy(temp, dataset, sizeof(double *));
memcpy(dataset, dataset+1, chunk_size * sizeof(double *));
memcpy(dataset+chunk_size-1, temp, sizeof(double *));
/*for (int i = 0; i < CHUNK; ++i) {
printf("id[%i]: %f", dataset[i][0]);
}*/
}
else{
free(dataset[0]);
memcpy(dataset, dataset+1, chunk_size * sizeof(double *));
dataset[chunk_size] = NULL;
dataset = realloc(dataset, chunk_size * sizeof(double *));
if(dataset == NULL){
printf("Something went wrong in inizialize_cluster(), memory allocation failed!");
exit(1);
}
}
/**
* The centers of the next clusters are chosen as those that are furthest apart
**/
double max;
int pos;
double distance;
for (int i = 1; i < k; i++) {
/**
* I choose the point that maximizes the sum of the distances from the centerpieces
*/
max = -1;
for (int j = 0; j < chunk_size; j++){
distance = compute_sum_of_euclidean_distance(center_point, dataset[j], i, d);
if (distance > max) {
pos = j;
max = distance;
}
}
memcpy(*(center_point + i), *(dataset + pos), (d + 1) * sizeof(double));
/**
* When a point is chosen as the center of a cluster, I remove it from the dataset
**/
chunk_size--;
if(retain){
double** temp = malloc(sizeof(double *));
memcpy(temp, dataset + pos, sizeof(double *));
memcpy(dataset + pos, dataset + pos + 1, (chunk_size - pos) * sizeof(double *));
memcpy(dataset + chunk_size - 1, temp, sizeof(double *));
}
else{
free(dataset[pos]);
memcpy(dataset + pos, dataset + pos + 1, (chunk_size - pos) * sizeof(double *));
dataset = realloc(dataset, chunk_size * sizeof(double *));
if(dataset == NULL){
printf("Something went wrong in inizialize_cluster(), memory allocation failed!");
exit(1);
}
}
}
/**
* When I have found k points that can be used as the initial centres of the k clusters,
* I summarize them (calculate cluster statistics) and enter them into the discard set.
*/
for (int i = 0; i < k; i++) {
/**
* Cluster and discard set initialization
*/
clusters[i] = malloc(((2 * d) + 1) * sizeof(double));
set[i] = malloc(sizeof(int ));
if(clusters[i] == NULL || set[i] == NULL){
printf("Something went wrong in in inizialize_cluster(), memory allocation failed!");
exit(1);
}
clusters[i][0]=1;
set[i][0] = (int) center_point[i][0];
for (int j = 1; j < d + 1; j++) {
clusters[i][j] = center_point[i][j];
clusters[i][j + d] = pow(center_point[i][j], 2);
}
free(center_point[i]);
center_point[i] = NULL;
}
free(center_point);
center_point = NULL;
return chunk_size;
}
double **load_dataset(char *filename, int d, int chunk_size) {
double **dataset = malloc(chunk_size * sizeof(double *));
if(dataset == NULL){
printf("Something went wrong in load_dataset(), memory allocation failed!");
exit(1);
}
for (int i = 0; i < chunk_size; i++) {
dataset[i] = malloc((d + 1) * sizeof(double));
if(dataset[i] == NULL){
printf("Something went wrong in load_dataset(), memory allocation failed!");
exit(1);
}
}
FILE *file;
file=fopen(filename, "r");
if (file == NULL){
printf("Something went wrong in load_dataset(), file opening failed! (row 162)");
exit(1);
}
char *line = NULL, *token;
size_t len = 0;
int i = 0;
int j = 0;
int first_line = 0;
while ((getline(&line, &len, file)) != -1 && i < chunk_size) {
if(first_line != 0) {
while ((token = strsep(&line, ",")) != NULL) {
dataset[i][j] = atof(token);
j++;
}
j = 0;
i++;
} else{
first_line = 1;
}
}
fclose(file);
return dataset;
}
int assign_point_to_cluster(double **clusters, int **set, double **retained_set, double *point,double *standard_deviation,
int d, int k, int *chunk_size, int p_in_r) {
/**
* For each point I assess which cluster it can go into
*/
int candidate;
candidate = find_candidate_cluster(clusters, point, standard_deviation, d, k);
/**
* After identifying the candidate cluster (if there is one), I add the point to the discard set and update the
* cluster statistics otherwise I go ahead and put the point in the retained set
*/
(*chunk_size)--;
if(candidate > -1){
/**
* I add the point to the discard/compressed set
*/
clusters[candidate][0]++;
set[candidate] = realloc(set[candidate], (unsigned long)clusters[candidate][0] * sizeof(int));
if(set[candidate] == NULL){
printf("Something went wrong in in assign_point_to_cluster(), memory allocation failed!");
exit(1);
}
set[candidate][(int) clusters[candidate][0] - 1] = (int) point[0];
/**
* I update the cluster statistics
*/
for (int i = 1; i < d + 1; i++) {
clusters[candidate][i] += point[i];
clusters[candidate][i + d] += pow(point[i], 2);
}
}
else if(retained_set){
/**
* I insert the point in the retained set
*/
p_in_r++;
retained_set = realloc(retained_set, p_in_r * sizeof(double *));
retained_set[p_in_r - 1] = malloc((d + 1) * sizeof(double));
memcpy(*(retained_set + p_in_r - 1), point, (d + 1) * sizeof(double ));
return 1;
}
return 0;
}
int find_candidate_cluster(double **clusters, double *point, double *std_deviation, int d, int k) {
double actual = DBL_MAX;
int candidate = -1;
double threshold;
double distance;
for (int j = 0; j < k; j++) {
/**
* Calculation of varainza,threshold and mahalanobis' distance
*/
compute_std_dev(clusters[j], std_deviation, d);
//TODO: Would it be okay as a threshold? An alternative could be the module?
threshold = 3.5 * mean(std_deviation, d);
distance = mahalanobis(clusters[j], point, std_deviation, d);
if(distance < threshold && distance < actual){
/**
* the cluster is a candidate for the point
*/
candidate = j;
actual = distance;
}
}
return candidate;
}
double mean(const double *vector, int d) {
double sum = 0;
for (int i = 0; i < d; ++i) {
sum += vector[i];
}
return sum/d;
}
void compute_std_dev(const double *cluster, double *standard_deviation_vector, int d) {
double sigma;
/**
* Vector of the variances of the components of the cluster elements
*/
for (int i = 0; i < d; i++) {
sigma = sqrt(fabs(cluster[i + 1 + d]/cluster[0] - pow(cluster[i + 1]/cluster[0], 2)));
if( sigma == 0)
sigma = 1;
standard_deviation_vector[i] = sigma;
}
}
double mahalanobis(const double *cluster, const double *point, const double *standard_deviation, int d) {
double distance=0;
for (int i = 1; i < d; ++i) {
distance += pow((point[i] - cluster[i]) / standard_deviation[i - 1], 2);
}
return sqrt(distance)/d; //TODO: can it be okay? I thought so since the threshold is the average of the st.dev.
}
double compute_sum_of_euclidean_distance(double **center_points, double *point, int n, int d) {
double component_sum = 0;
double final_sum = 0;
for (int i = 0; i < n; i++) {
for (int j = 1; j < d + 1; j++){
component_sum += pow(center_points[i][j] - point[j], 2);
}
final_sum += sqrt(component_sum);
}
return final_sum;
}
void feature_scaling(double **dataset, int d, int chunk_size) {
/**
* We perform a Z-score Normalization
**/
double mean;
double sigma;
double sum;
double sumQ;
double variance;
/**
* We calculate mean and variance for each column
**/
for (int i = 1; i < d + 1; i++) {
sum = 0;
for (int j = 0; j < chunk_size; j++) {
sum += dataset[j][i];
}
mean = sum / chunk_size;
sumQ = 0;
for (int j = 0; j < chunk_size; j++) {
sumQ += pow((dataset[j][i] - mean), 2);
}
variance = sumQ / chunk_size;
sigma = sqrt(variance);
if( sigma == 0)
sigma = 1;
/**
* Feature scaling: (x-x_med)/sigma
**/
for (int j = 0; j < chunk_size; j++) {
dataset[j][i] = (dataset[j][i] - mean) / sigma;
}
}
}
The command I use when run is:
./main "db.csv" 100 35 4 3
It works if the 3rd argument is less then 34
The file db.csv contains:
CustomerID,Gender,Age,Annual Income (k$),Spending Score (1-100),cluster
1,0,19,15,39,4
2,0,21,47,81,3
3,1,20,56,6,4
4,1,23,16,77,3
5,1,31,17,40,4
6,1,22,17,76,3
7,1,35,18,6,4
8,1,23,18,94,3
9,0,64,19,3,4
10,1,30,19,72,3
11,0,67,19,14,4
12,1,35,19,99,3
13,1,58,20,15,4
14,1,24,20,77,3
15,0,37,20,13,4
16,0,22,20,79,3
17,1,35,21,35,4
18,0,20,21,66,3
19,0,52,23,29,4
20,1,35,23,98,3
21,0,35,24,35,4
22,0,25,24,73,3
23,1,46,25,5,4
24,0,31,25,73,3
25,1,54,28,14,4
26,0,29,28,82,3
27,1,45,28,32,4
28,0,35,28,61,3
29,1,40,29,31,4
30,1,23,29,87,3
31,0,60,30,4,4
32,1,21,30,73,3
33,0,53,33,4,4
34,0,18,33,92,3
35,1,49,33,14,4
36,1,21,33,81,3
37,1,42,34,17,4
38,1,30,34,73,3
39,1,36,37,26,4
40,1,20,37,75,3
41,1,65,38,35,0
42,0,24,38,92,3
43,0,48,39,36,0
44,1,31,39,61,5
45,1,49,39,28,4
46,1,24,39,65,3
47,1,50,40,55,0
48,1,27,40,47,5
49,1,29,40,42,5
50,1,31,40,42,5
51,1,49,42,52,0
52,0,33,42,60,5
53,1,31,43,54,5
54,0,59,43,60,0
55,1,50,43,45,0
56,0,47,43,41,0
57,1,51,44,50,0
58,0,69,44,46,0
59,1,27,46,51,5
60,0,53,46,46,0
61,0,70,46,56,0
62,0,19,46,55,5
63,1,67,47,52,0
64,1,54,47,59,0
65,0,63,48,51,0
66,0,18,48,59,5
67,1,43,48,50,0
68,1,68,48,48,0
69,0,19,48,59,5
70,1,32,48,47,5
71,0,70,49,55,0
72,1,47,49,42,0
73,1,60,50,49,0
74,1,60,50,56,0
75,0,59,54,47,0
76,0,26,54,54,5
77,1,45,54,53,0
78,0,40,54,48,5
79,1,23,54,52,5
80,1,49,54,42,0
81,0,57,54,51,0
82,0,38,54,55,5
83,0,67,54,41,0
84,1,46,54,44,0
85,1,21,54,57,5
86,0,48,54,46,0
87,1,55,57,58,0
88,1,22,57,55,5
89,1,34,58,60,5
90,1,50,58,46,0
91,1,68,59,55,0
92,0,18,59,41,5
93,0,48,60,49,0
94,1,40,60,40,5
95,1,32,60,42,5
96,0,24,60,52,5
97,1,47,60,47,0
98,1,27,60,50,5
99,0,48,61,42,0
100,0,20,61,49,5
101,1,23,62,41,5
102,1,49,62,48,0
103,0,67,62,59,0
104,0,26,62,55,5
105,0,49,62,56,0
106,1,21,62,42,5
107,1,66,63,50,0
108,0,54,63,46,0
109,0,68,63,43,0
110,0,66,63,48,0
111,0,65,63,52,0
112,1,19,63,54,5
113,1,38,64,42,5
114,0,19,64,46,5
115,1,18,65,48,5
116,1,19,65,50,5
117,1,63,65,43,0
118,1,49,65,59,0
119,1,51,67,43,0
120,1,50,67,57,0
121,0,27,67,56,5
122,1,38,67,40,5
123,1,40,69,58,5
124,0,39,69,91,1
125,1,23,70,29,5
126,1,31,70,77,1
127,0,43,71,35,2
128,0,40,71,95,1
129,0,59,71,11,2
130,0,38,71,75,1
131,0,47,71,9,2
132,0,39,71,75,1
133,1,25,72,34,5
134,1,31,72,71,1
135,0,20,73,5,2
136,1,29,73,88,1
137,1,44,73,7,2
138,0,32,73,73,1
139,0,19,74,10,2
140,1,35,74,72,1
141,1,57,75,5,2
142,0,32,75,93,1
143,1,28,76,40,5
144,1,32,76,87,1
145,0,25,77,12,2
146,0,28,77,97,1
147,0,48,77,36,2
148,1,32,77,74,1
149,1,34,78,22,2
150,0,34,78,90,1
151,0,43,78,17,2
152,0,39,78,88,1
153,1,44,78,20,2
154,1,38,78,76,1
155,1,47,78,16,2
156,1,27,78,89,1
157,0,37,78,1,2
158,1,30,78,78,1
159,0,34,78,1,2
160,1,30,78,73,1
161,1,56,79,35,2
162,1,29,79,83,1
163,0,19,81,5,2
164,1,31,81,93,1
165,0,50,85,26,2
166,1,36,85,75,1
167,0,42,86,20,2
168,1,33,86,95,1
169,1,36,87,27,2
170,0,32,87,63,1
171,0,40,87,13,2
172,0,28,87,75,1
173,0,36,87,10,2
174,0,36,87,92,1
175,1,52,88,13,2
176,1,30,88,86,1
177,0,58,88,15,2
178,0,27,88,69,1
179,0,59,93,14,2
180,0,35,93,90,1
181,1,37,97,32,2
182,1,32,97,86,1
183,0,46,98,15,2
184,1,29,98,88,1
185,1,41,99,39,2
186,0,30,99,97,1
187,1,54,101,24,2
188,0,28,101,68,1
189,1,41,103,17,2
190,1,36,103,85,1
191,1,34,103,23,2
192,1,32,103,69,1
193,0,33,113,8,2
194,1,38,113,91,1
195,1,47,120,16,2
196,1,35,120,79,1
197,1,45,126,28,2
198,0,32,126,74,1
199,0,32,137,18,2
200,0,30,137,83,1
download it from mega: db.csv.
Originally found on Kaggle but I made some modifications.
Edit: I included the whole code
Edit: I alse get this error trying to see what is in retained_set : read memory from 0x3d2fdfcb8030 failed (0 of 8 bytes read)
Edit: I translate the comment in the code and added the file I use as input
assign_point_to_cluster has a local variable double **retained_set. This means that you cannot do retained_set = realloc(retained_set, ... or you will just change where that local variable points at, not where the pointer-to-pointer on the caller side points at. And because of that you also create a memory leak. See this FAQ: Dynamic memory access only works inside function
As for how to solve it, it appears that encapsulating all of this data into structs would simplify the program a lot. You could also implement it as an "opaque type" (How to do private encapsulation in C?) and get rid of the caller's responsibility to handle dynamic allocation.
Using 2D arrays instead of pointer-to-pointers might also simplify the program and improve performance. For example if you could use a "pointer to array pointer" parameter double (**retained_set)[x][y]) then you could do double (*tmp)[x][y] = realloc(*retained_set,...) and then *retained_set = tmp;, which would affect the caller. But structs would be easier to read so that should be the first option.
Also note that malloc.h has been obsolete since forever. difference between <stdlib.h> and <malloc.h>
I am writing a C programme in which there will be several arrays which lengths are configured in a data file.
I am trying to read I and J from OFDMA.dat, and create arrays Noise, Bw .etc
The lines I have commented belong to the original programme which works:
//#define I 3;
//#define J 2;
//#define NUMROWS (1+I+2*I*J)
//#define NUMCOLS 3*I*J
//#define NUMNZ 6*I*J
Then I tried to read from OFDMA.dat with following code:
while (fgets(buffer, 80, dat) != NULL) {
if (buffer[0] == '#') continue;
if (counter == 1){
maxIter = atoi(buffer);
printf("maxIter \n");
}
if (counter == 2){
Pwr = atof(buffer);
printf("Pwr \n");
}
if (counter == 3){
I = atoi(buffer);
printf("I \n");
Bw = (double*)malloc(sizeof(double)*I);
Noise = (double*)malloc(sizeof(double)*I);
}
if (counter == 4){
J = atoi(buffer);
printf("J \n");
}
if (counter>4 && counter <= 4 + I){
Noise[counter - 5] = atof(buffer);
printf("Noise[%d]: %lf\n", counter - 5, Noise[counter - 5]);
}
if (counter>4 + I&&counter<4 + 2 * I){
Bw[counter - 5 - I] = atof(buffer);
printf("Bw[%d]: %lf\n", counter - I - 5, Bw[counter - I - 5]);
}
counter++;
}
Then visual studio says:
1>OFDMA.c(96): error C2057: expected constant expression
1>OFDMA.c(96): error C2466: cannot allocate an array of constant size 0
1>OFDMA.c(102): error C2057: expected constant expression
1>OFDMA.c(102): error C2466: cannot allocate an array of constant size 0
1>OFDMA.c(135): error C2057: expected constant expression
1>OFDMA.c(135): error C2466: cannot allocate an array of constant size 0
1>OFDMA.c(135): error C2133: 'x' : unknown size
1>OFDMA.c(136): error C2057: expected constant expression
1>OFDMA.c(136): error C2466: cannot allocate an array of constant size 0
1>OFDMA.c(136): error C2133: 'slack' : unknown size
1>OFDMA.c(352): error C2057: expected constant expression
1>OFDMA.c(352): error C2466: cannot allocate an array of constant size 0
1>OFDMA.c(546): error C2057: expected constant expression
1>OFDMA.c(546): error C2466: cannot allocate an array of constant size 0
In those lines, I and J are used in declaring arrays. For example:
static int
setproblemdata(char **probname_p, int *numcols_p, int *numrows_p, int *objsen_p,
double **obj_p, double **rhs_p, char **sense_p, int **matbeg_p,
int **matcnt_p, int **matind_p, double **matval_p, double **lb_p,
double **ub_p, char **ctype_p, double Noise_p[I]);
The full codes:
/* Bring in the CPLEX function declarations and the C library
header file stdio.h with the include of cplex.h. */
#include <ilcplex/cplex.h>
/* Bring in the declarations for the string functions */
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
/* The problem we are optimizing will have I channels, J users.
* So there will be 1+I+2*I*J rows, 3*I*J columns, and 5*I*J nonzeros. */
//#define I 3;
//#define J 2;
//#define NUMROWS (1+I+2*I*J)
//#define NUMCOLS 3*I*J
//#define NUMNZ 6*I*J
int I, J;
int maxIter;
double Pwr;
double* Bw;
double* Noise;
/* Include declaration for function at end of program */
static int readdata(){
int counter = 1;
FILE * dat;
dat = fopen("OFDMA.dat", "r");
char buffer[80];
if (!dat) // equivalent to saying if ( in_file == NULL )
{
printf("oops, file can't be read\n");
return 1;
}
while (fgets(buffer, 80, dat) != NULL) {
if (buffer[0] == '#') continue;
if (counter == 1){
maxIter = atoi(buffer);
printf("maxIter \n");
}
if (counter == 2){
Pwr = atof(buffer);
printf("Pwr \n");
}
if (counter == 3){
I = atoi(buffer);
printf("I \n");
Bw = (double*)malloc(sizeof(double)*I);
Noise = (double*)malloc(sizeof(double)*I);
NUMROWS=1+I+2*I*J;
NUMCOLS=4*I*J;
NUMNZ=6*I*J;
}
if (counter == 4){
J = atoi(buffer);
printf("J \n");
}
if (counter>4 && counter <= 4 + I){
Noise[counter - 5] = atof(buffer);
printf("Noise[%d]: %lf\n", counter - 5, Noise[counter - 5]);
}
if (counter>4 + I&&counter<4 + 2 * I){
Bw[counter - 5 - I] = atof(buffer);
printf("Bw[%d]: %lf\n", counter - I - 5, Bw[counter - I - 5]);
}
counter++;
}
fclose(dat);
return 0;
}
static int
setproblemdata(char **probname_p, int *numcols_p, int *numrows_p, int *objsen_p,
double **obj_p, double **rhs_p, char **sense_p, int **matbeg_p,
int **matcnt_p, int **matind_p, double **matval_p, double **lb_p,
double **ub_p, char **ctype_p, double Noise_p[I]);
static void
free_and_null(char **ptr);
static int
addcuts(double **matval_p, double **rhs_p, double pbar_p[I*J], const double Bw_[I], double Noise_p[I]);
int main(void) {
/* Declare pointers for the variables and arrays that will contain
the data which define the LP problem. The setproblemdata() routine
allocates space for the problem data. */
char *probname = NULL;
int numcols;
int numrows;
int objsen;
double *obj = NULL;
double *rhs = NULL;
char *sense = NULL;
int *matbeg = NULL;
int *matcnt = NULL;
int *matind = NULL;
double *matval = NULL;
double *lb = NULL;
double *ub = NULL;
char *ctype = NULL;
double *pbar = NULL;
/* Declare and allocate space for the variables and arrays where we will
store the optimization results including the status, objective value,
variable values, and row slacks. */
int solstat;
double objval;
double x[NUMCOLS];
double slack[NUMROWS];
CPXENVptr env = NULL;
CPXLPptr lp = NULL;
int status;
int i, j;
int counter;
int cur_numrows, cur_numcols;
/* Import Data from file OFDMA.dat*/
status = readdata();
if (status){
fprintf(stderr, "Failure to read data from file. \n");
goto TERMINATE;
}
/* Initialize the CPLEX environment */
env = CPXopenCPLEX(&status);
/* If an error occurs, the status value indicates the reason for
failure. A call to CPXgeterrorstring will produce the text of
the error message. Note that CPXopenCPLEX produces no output,
so the only way to see the cause of the error is to use
CPXgeterrorstring. For other CPLEX routines, the errors will
be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */
if (env == NULL) {
char errmsg[CPXMESSAGEBUFSIZE];
fprintf(stderr, "Could not open CPLEX environment.\n");
CPXgeterrorstring(env, status, errmsg);
fprintf(stderr, "%s", errmsg);
goto TERMINATE;
}
/* Turn on output to the screen */
status = CPXsetintparam(env, CPXPARAM_ScreenOutput, CPX_ON);
if (status) {
fprintf(stderr, "Failure to turn on screen indicator, error %d.\n",
status);
goto TERMINATE;
}
/* Fill in the data for the problem. */
status = setproblemdata(&probname, &numcols, &numrows, &objsen, &obj, &rhs,
&sense, &matbeg, &matcnt, &matind, &matval, &lb, &ub, &ctype, Noise);
if (status) {
fprintf(stderr, "Failed to build problem data arrays.\n");
goto TERMINATE;
}
/* Create the problem. */
lp = CPXcreateprob(env, &status, probname);
/* A returned pointer of NULL may mean that not enough memory
was available or there was some other problem. In the case of
failure, an error message will have been written to the error
channel from inside CPLEX. In this example, the setting of
the parameter CPXPARAM_ScreenOutput causes the error message to
appear on stdout. */
if (lp == NULL) {
fprintf(stderr, "Failed to create LP.\n");
goto TERMINATE;
}
/* Main Loop */
for (i = 0; i < maxIter; i++) {
/* Now copy the problem data into the lp */
status = CPXcopylp(env, lp, numcols, numrows, objsen, obj, rhs, sense,
matbeg, matcnt, matind, matval, lb, ub, NULL);
if (status) {
fprintf(stderr, "Failed to copy problem data.\n");
goto TERMINATE;
}
/* Now copy the ctype array */
status = CPXcopyctype(env, lp, ctype);
if (status) {
fprintf(stderr, "Failed to copy ctype\n");
goto TERMINATE;
}
/* Optimize the problem and obtain solution. */
status = CPXmipopt(env, lp);
if (status) {
fprintf(stderr, "Failed to optimize MIP.\n");
goto TERMINATE;
}
solstat = CPXgetstat(env, lp);
/* Write the output to the screen. */
printf("\nSolution status = %d\n", solstat);
status = CPXgetobjval(env, lp, &objval);
if (status) {
fprintf(stderr, "No MIP objective value available. Exiting...\n");
goto TERMINATE;
}
cur_numcols = CPXgetnumcols(env, lp);
status = CPXgetx(env, lp, x, 0, cur_numcols - 1);
if (status) {
fprintf(stderr, "Failed to get optimal integer x.\n");
goto TERMINATE;
}
printf("Solution value = %f\n\n", objval);
/* Add Cuts to the problem */
addcuts(&matval, &rhs, x, Bw, Noise);
}
/* The size of the problem should be obtained by asking CPLEX what
the actual size is, rather than using what was passed to CPXcopylp.
cur_numrows and cur_numcols store the current number of rows and
columns, respectively. */
cur_numrows = CPXgetnumrows(env, lp);
cur_numcols = CPXgetnumcols(env, lp);
status = CPXgetx(env, lp, x, 0, cur_numcols - 1);
if (status) {
fprintf(stderr, "Failed to get optimal integer x.\n");
goto TERMINATE;
}
status = CPXgetslack(env, lp, slack, 0, cur_numrows - 1);
if (status) {
fprintf(stderr, "Failed to get optimal slack values.\n");
goto TERMINATE;
}
for (i = 0; i < cur_numrows; i++) {
printf("Row %d: Slack = %10f\n", i, slack[i]);
}
for (j = 0; j < cur_numcols; j++) {
printf("Column %d: Value = %10f\n", j, x[j]);
}
/* Finally, write a copy of the problem to a file. */
status = CPXwriteprob(env, lp, "OFMDA.lp", NULL);
if (status) {
fprintf(stderr, "Failed to write LP to disk.\n");
goto TERMINATE;
}
TERMINATE:
/* Free up the problem as allocated by CPXcreateprob, if necessary */
if (lp != NULL) {
status = CPXfreeprob(env, &lp);
if (status) {
fprintf(stderr, "CPXfreeprob failed, error code %d.\n", status);
}
}
/* Free up the CPLEX environment, if necessary */
if (env != NULL) {
status = CPXcloseCPLEX(&env);
/* Note that CPXcloseCPLEX produces no output,
so the only way to see the cause of the error is to use
CPXgeterrorstring. For other CPLEX routines, the errors will
be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */
if (status) {
char errmsg[CPXMESSAGEBUFSIZE];
fprintf(stderr, "Could not close CPLEX environment.\n");
CPXgeterrorstring(env, status, errmsg);
fprintf(stderr, "%s", errmsg);
}
}
/* Free up the problem data arrays, if necessary. */
free_and_null((char **)&probname);
free_and_null((char **)&obj);
free_and_null((char **)&rhs);
free_and_null((char **)&sense);
free_and_null((char **)&matbeg);
free_and_null((char **)&matcnt);
free_and_null((char **)&matind);
free_and_null((char **)&matval);
free_and_null((char **)&lb);
free_and_null((char **)&ub);
free_and_null((char **)&ctype);
return (status);
} /* END main */
static int setproblemdata(char **probname_p, int *numcols_p, int *numrows_p,
int *objsen_p, double **obj_p, double **rhs_p, char **sense_p,
int **matbeg_p, int **matcnt_p, int **matind_p, double **matval_p,
double **lb_p, double **ub_p, char **ctype_p, double Noise_p[I]) {
char *zprobname = NULL; /* Problem name <= 16 characters */
double *zobj = NULL;
double *zrhs = NULL;
char *zsense = NULL;
int *zmatbeg = NULL;
int *zmatcnt = NULL;
int *zmatind = NULL;
double *zmatval = NULL;
double *zlb = NULL;
double *zub = NULL;
char *zctype = NULL;
int status = 0;
int i, j; //channel and user
int counter = 0; //counter
zprobname = (char *)malloc(16 * sizeof (char));
zobj = (double *)malloc(NUMCOLS * sizeof (double));
zrhs = (double *)malloc(NUMROWS * sizeof (double));
zsense = (char *)malloc(NUMROWS * sizeof (char));
zmatbeg = (int *)malloc(NUMCOLS * sizeof (int));
zmatcnt = (int *)malloc(NUMCOLS * sizeof (int));
zmatind = (int *)malloc(NUMNZ * sizeof (int));
zmatval = (double *)malloc(NUMNZ * sizeof (double));
zlb = (double *)malloc(NUMCOLS * sizeof (double));
zub = (double *)malloc(NUMCOLS * sizeof (double));
zctype = (char *)malloc(NUMCOLS * sizeof (char));
if (zprobname == NULL || zobj == NULL || zrhs == NULL || zsense == NULL
|| zmatbeg == NULL || zmatcnt == NULL || zmatind == NULL
|| zmatval == NULL || zlb == NULL || zub == NULL || zctype == NULL) {
status = 1;
goto TERMINATE;
}
strcpy(zprobname, "example");
/* The code is formatted to make a visual correspondence
between the mathematical linear program and the specific data
items. */
/* Objective Function*/
/* coefficients of p_ij and x_ij*/
for (i = 0; i < 2 * I * J; i++) {
zobj[i] = 0;
}
/* coefficients of e_ij*/
for (i = 2 * I * J; i < 3 * I * J; i++) {
zobj[i] = 1;
}
/* Constraints */
/*
* Non-zeros
*
* Every p_ij appears twice, at the 0th and (I+i)th constraints.
* Every x_ij appears twice, at the ...........
* Every e_ij appears once, at the (1+I+I*J+i)th constraint.
*/
for (i = 0; i < I * J; i++) {
zmatbeg[i] = 3 * i;
zmatcnt[i] = 3;
}
for (i = 0; i < I * J; i++) {
zmatbeg[I * J + i] = 3 * I * J + 2 * i;
zmatcnt[I * J + i] = 2;
}
for (i = 0; i < I * J; i++) {
zmatbeg[2 * I * J + i] = 5 * I * J + i;
zmatcnt[2 * I * J + i] = 1;
}
/*
* p_ij appears at the 0th and (I+i+1)th constraints, coefficient is 1.
*/
for (i = 0; i < I * J; i++) {
zmatind[3 * i] = 0;
zmatval[3 * i] = 1.0;
zmatind[3 * i + 1] = I + i + 1;
zmatval[3 * i + 1] = 1.0;
zmatind[3 * i + 2] = 1 + I + I * J + i;
zmatval[3 * i + 2] = -1.0;
}
/*
* x_ij
*/
int ztmpind = I + 1;
for (i = 0; i < 2 * I * J; i += 2) {
zmatind[3 * I * J + i] = i / (2 * J) + 1;
zmatval[3 * I * J + i] = 1;
zmatind[3 * I * J + i + 1] = ztmpind;
zmatval[3 * I * J + i + 1] = -1 * Pwr;
ztmpind++;
}
/*
* e_ij appears at the (1+I+I*J+i)th constraint.
*/
for (i = 0; i < I * J; i++) {
zmatind[5 * I * J + i] = 1 + I + I * J + i;
zmatval[5 * I * J + i] = 1;
}
/*
* Domain of variables
*/
for (i = 0; i < I * J; i++) {
zlb[i] = 0.0;
zub[i] = CPX_INFBOUND;
zctype[i] = 'C';
}
for (i = I * J; i < 2 * I * J; i++) {
zlb[i] = 0.0;
zub[i] = 1.0;
zctype[i] = 'I';
}
for (i = 2 * I * J; i < 3 * I * J; i++) {
zlb[i] = 0.0;
zub[i] = CPX_INFBOUND;
zctype[i] = 'C';
}
/* The right-hand-side values don't fit nicely on a line above. So put
them here. */
zsense[0] = 'L';
zrhs[0] = Pwr;
for (i = 0; i < I; i++) {
zsense[i + 1] = 'L';
zrhs[i + 1] = 1;
}
for (i = 0; i < I * J; i++) {
zsense[I + i + 1] = 'L';
zrhs[I + 1 + i] = 0;
}
counter = 0;
for (i = 0; i < I; i++) {
for (j = 0; j < J; j++) {
zsense[1 + I + I * J + counter] = 'L';
zrhs[1 + I + I * J + counter] = log(1 + Pwr / Noise_p[i]);
counter++;
}
}
TERMINATE:
if (status) {
free_and_null((char **)&zprobname);
free_and_null((char **)&zobj);
free_and_null((char **)&zrhs);
free_and_null((char **)&zsense);
free_and_null((char **)&zmatbeg);
free_and_null((char **)&zmatcnt);
free_and_null((char **)&zmatind);
free_and_null((char **)&zmatval);
free_and_null((char **)&zlb);
free_and_null((char **)&zub);
free_and_null((char **)&zctype);
}
else {
*numcols_p = NUMCOLS;
*numrows_p = NUMROWS;
*objsen_p = CPX_MAX; /* The problem is maximization */
*probname_p = zprobname;
*obj_p = zobj;
*rhs_p = zrhs;
*sense_p = zsense;
*matbeg_p = zmatbeg;
*matcnt_p = zmatcnt;
*matind_p = zmatind;
*matval_p = zmatval;
*lb_p = zlb;
*ub_p = zub;
*ctype_p = zctype;
}
return (status);
} /* END setproblemdata */
/* Add Cuts to the problem */
static int addcuts(double **matval_p, double **rhs_p, double pbar_p[I*J], const double Bw_p[I], double Noise_p[I]) {
double *zmatval = NULL;
double *zrhs = NULL;
int status = 0;
int i, j;
int counter;
zrhs = (double *)malloc(NUMROWS * sizeof (double));
zmatval = (double *)malloc(NUMNZ * sizeof (double));
if (zrhs == NULL || zmatval == NULL) {
status = 1;
goto TERMINATE;
}
zrhs = *rhs_p;
zmatval = *matval_p;
for (i = 0; i < I * J; i++) {
printf("pbar_%d is %f\n", i, pbar_p[i]);
}
/*
*/
counter = 0;
for (i = 0; i < I; i++) {
for (j = 0; j < J; j++) {
printf("e_bar: %f\n", Bw_p[i] * log2(1 + pbar_p[counter] / Noise_p[i]));
}
}
for (i = 0; i < I; i++) {
for (j = 0; j < J; j++) {
printf("xx: %f\n", -Bw_p[i] / (log(2)*(Noise_p[i] + pbar_p[i])));
}
}
for (i = 0; i < I; i++) {
for (j = 0; j < J; j++) {
zmatval[3 * i + 2] = -Bw_p[i] / (log(2)*(Noise_p[i] + pbar_p[i]));
}
}
for (i = 0; i < I; i++) {
for (j = 0; j < J; j++) {
zrhs[1 + I + I * J + i] = Bw_p[i] * log2(1 + pbar_p[i] / Noise_p[i]) - Bw_p[i] / (log(2)*(Noise_p[i] + pbar_p[i])) * pbar_p[i];
}
}
TERMINATE:
if (status) {
free_and_null((char **)&zrhs);
}
else {
*rhs_p = zrhs;
}
return (status);
} /* END addcuts */
/* This simple routine frees up the pointer *ptr, and sets *ptr to NULL */
static void free_and_null(char **ptr) {
if (*ptr != NULL) {
free(*ptr);
*ptr = NULL;
}
} /* END free_and_null */
Can anybody give me an example please?
EDIT 2 (assigning values to #define value)
There are many parts to your code that need to be addressed, however, sticking only to the part you have asked about, consider this section of your code:
Bw = (double*)malloc(sizeof(double)*I);
Noise = (double*)malloc(sizeof(double)*I);
NUMROWS=1+I+2*I*J;
NUMCOLS=4*I*J;
NUMNZ=6*I*J;
It is not the malloc statements that are being addressed by the error messages: example:
1>OFDMA.c(96): error C2057: expected constant expression
1>OFDMA.c(96): error C2466: cannot allocate an array of constant size 0
...
...
rather the lines where you are attempting to assign values to NUMROWS, NUMCOLS etc. As I have said below, these you have created using #define, and are not changeable during run-time.
EDIT (to address I & J) When I try to read I and J from a data file, the visual studio doesn't allow me to do so saying:
expected constant expression
You've created I & J as #defines,
#define I ii
#define J 2
they are therefore not changeable during runtime. If you want them to be changeble, created them as int, char[], or double. example:
char I[10];
int J;
They will then be able to accept assignments during run time.
It is not clear from your question exactly what you are having problems with, reading the initializer value in from a file, or using it to initialize a variable.
This addresses the initialization part only:
C99 allows for variable array initializers, so reading values in from a file, (and converting them from string to int or float) then using them to initialize an array, is completely legal. For example:
float read_and_process(int n)
{
float vals[n];//variable array initializer "n"
for (int i = 0; i < n; i++)
vals[i] = read_val();
return process(vals, n);
}
Reference1
Reference2
You first have to understand that the preprocessor will change every instance of I and J to their respective values of 3 and 2 before the actual compilation kicks in and spits out this error message.
To dynamically allocate an array you need to use malloc. You can find plenty of example by Googling.
In C, arrays length are constant and they are defined in compiling time.
If you want to trade with a variable-length array, you have to use malloc:
double* B;
double* N;
double* NZmatrix;
static int main(){
int I, NZ;
I = 2;
NZ = 3;
B = (double*)malloc(sizeof(double)*I);
N = (double*)malloc(sizeof(double)*I)
NZmatrix = (double*)malloc(sizeof(double)*NZ)
}
And I and NZ are integer variables that contain the desired length.