2009-02-21 4 views
6

Attualmente sto scrivendo un codice di Ricottura simulata per risolvere un problema di commesso viaggiatore e ho incontrato difficoltà con l'archiviazione e l'utilizzo dei miei dati letti da un file txt. Ogni riga colonna & del file rappresenta ogni città, con la distanza tra due diverse città memorizzati come 15 x 15 matrice:Leggere un file txt Matrix e archiviarlo come array

0.0 5.0 5.0 6.0 7.0 2.0 5.0 2.0 1.0 5.0 5.0 1.0 2.0 7.1 5.0 
5.0 0.0 5.0 5.0 5.0 2.0 5.0 1.0 5.0 6.0 6.0 6.0 6.0 1.0 7.1 
5.0 5.0 0.0 6.0 1.0 6.0 5.0 5.0 1.0 6.0 5.0 7.0 1.0 5.0 6.0 
6.0 5.0 6.0 0.0 5.0 2.0 1.0 6.0 5.0 6.0 2.0 1.0 2.0 1.0 5.0 
7.0 5.0 1.0 5.0 0.0 7.0 1.0 1.0 2.0 1.0 5.0 6.0 2.0 2.0 5.0 
2.0 2.0 6.0 2.0 7.0 0.0 5.0 5.0 6.0 5.0 2.0 5.0 1.0 2.0 5.0 
5.0 5.0 5.0 1.0 1.0 5.0 0.0 2.0 6.0 1.0 5.0 7.0 5.0 1.0 6.0 
2.0 1.0 5.0 6.0 1.0 5.0 2.0 0.0 7.0 6.0 2.0 1.0 1.0 5.0 2.0 
1.0 5.0 1.0 5.0 2.0 6.0 6.0 7.0 0.0 5.0 5.0 5.0 1.0 6.0 6.0 
5.0 6.0 6.0 6.0 1.0 5.0 1.0 6.0 5.0 0.0 7.0 1.0 2.0 5.0 2.0 
5.0 6.0 5.0 2.0 5.0 2.0 5.0 2.0 5.0 7.0 0.0 2.0 1.0 2.0 1.0 
1.0 6.0 7.0 1.0 6.0 5.0 7.0 1.0 5.0 1.0 2.0 0.0 5.0 6.0 5.0 
2.0 6.0 1.0 2.0 2.0 1.0 5.0 1.0 1.0 2.0 1.0 5.0 0.0 7.0 6.0 
7.0 1.0 5.0 1.0 2.0 2.0 1.0 5.0 6.0 5.0 2.0 6.0 7.0 0.0 5.0 
5.0 7.0 6.0 5.0 5.0 5.0 6.0 2.0 6.0 2.0 1.0 5.0 6.0 5.0 0.0 

Per leggere questo ho un LoadCities() funzionano come illustrato di seguito:

#include "iostream" 
#include "fstream"  
#include "string" 
using namespace std; 

double distances [15][15]; 

void LoadCities() 
{ 
    ifstream CityFile; 

    if (!CityFile.is_open()) //check is file has been opened 
    { 
     CityFile.open ("Cities.txt", ios::in | ios::out); 

     if (!CityFile) 
     { 
      cerr << "Failed to open " << CityFile << endl; 
      exit(EXIT_FAILURE); //abort program 
     } 
    } 

    int length; 
    char * buffer; 
    string cities; 

    CityFile.seekg(0, ios::end); 
    length = CityFile.tellg(); 
    CityFile.seekg (0, ios::beg); 

    buffer = new char [length]; 

    cities = CityFile.read (buffer,length); 

    string rows = strtok(cities, "\n"); 

    distances = new double[rows.length()][rows.length()]; 

      for (int i = 0; i < (string) rows.length(); i++) 
      { 
       string distance = strtok(rows[i], " "); 

       for (int j = 0; j < distance.length(); j++) 
       { 
        distances[i][j] = (double) Parse(distance[j]); 
       } 
      } 

    CityFile.close(); 
} 

ho tentato un metodo istreambuf_iterator alternativo per arrivare al punto di manipolare il materiale di lettura in array, però mi sembra sempre di incorrere in complicazioni:

ifstream CityFile("Cities.txt"); 
string theString((std::istreambuf_iterator<char>(CityFile)), std::istreambuf_iterator<char>()); 

Qualsiasi aiuto sarebbe molto apprezzato. Mi sono scagliato contro la testa con poco successo!

################ MODIFICA/Aggiorna

@ SoapBox - Alcuni dettagli del codice SA, funzioni e main(). Questo non è pulito, efficiente, ordinato e non è di essere in questa fase, ha solo bisogno di lavorare per il momento. Questa versione (sotto) funziona ed è impostata per risolvere polinomi (problemi più semplici). Ciò che deve essere fatto per convertirlo in un problema del commesso viaggiatore è quello di:

  1. Scrivi i LoadCities function() per raccogliere i dati a distanza. (Current)

  2. Change Initialise() per ottenere il totale delle distanze

  3. Change E() per la funzione TSP (ad esempio, calcolare la distanza di un percorso casuale)

Il questi ultimi due so che posso fare, tuttavia ho bisogno di LoadCities() per farlo. Nient'altro deve essere cambiato nel seguente script.

#include "math.h" 
#include "iostream" 
#include "fstream" 
#include "time.h" // Define time() 
#include "stdio.h" // Define printf() 
#include "randomc.h" // Define classes for random number generators 
#include "mersenne.cpp" // Include code for the chosen random number generator 

using namespace std; // For the use of text generation in application 

double T; 
double T_initial; 

double S; 
double S_initial; 
double S_current; 
double S_trial; 

double E_current; 

int N_step;  // Number of Iterations for State Search per Temperature 
int N_max;   //Number of Iterations for Temperature 
int Write; 

const double EXP = 2.718281828; 

//------------------------------------------------------------------------------ 
//Problem Function of Primary Variable (Debugged 17/02/09 - Works as intended) 

double E(double x) //ORIGNINAL 
{ 
    double y = x*x - 6*x + 2; 

    return y; 
} 

//------------------------------------------------------------------------------ 
//Random Number Generation Function (Mod 19/02/09 - Generated integers only & fixed sequence) 

double Random_Number_Generator(double nHigh, double nLow) 
{ 
    int seed = (int)time(0);   // Random seed 

    CRandomMersenne RanGen(seed);  // Make instance of random number generator 

    double fr;       // Random floating point number 

    fr = ((RanGen.Random() * (nHigh - nLow)) + nLow); // Generatres Random Interger between nLow & nHigh 

    return fr; 
} 

//------------------------------------------------------------------------------ 
//Initializing Function (Temp 17/02/09) 

void Initialize() //E.g. Getting total Distance between Cities 
{ 
    S_initial = Random_Number_Generator(10, -10); 

    cout << "S_Initial: " << S_initial << endl; 
} 

//------------------------------------------------------------------------------ 
//Cooling Schedule Function (make variables) (Completed 16/02/09) 

double Schedule(double Temp, int i) // Need to find cooling schedule 
{ 
    double CoolingRate = 0.9999; 

    return Temp *= CoolingRate; 
} 

//------------------------------------------------------------------------------ 
//Next State Function (Mod 18/02/09) 

double Next_State(double T_current, int i) 
{ 
     S_trial = Random_Number_Generator(pow(3, 0.5), pow(3, 0.5)*-1); 

     S_trial += S_current; 

     double E_t = E(S_trial); 
     double E_c = E(S_current); 

     double deltaE = E_t - E_c;        //Defines gradient of movement 

     if (deltaE <= 0)          //Downhill 
     {  
      S_current = S_trial; 
      E_current = E_t; 
     } 
     else             //Uphill 
     { 
      double R = Random_Number_Generator(1,0);   //pseudo random number generated 
      double Ratio = 1-(float)i/(float)N_max;    //Control Parameter Convergence to 0 
      double ctrl_pram = pow(EXP, (-deltaE/T_current)); //Control Parameter 

      if (R < ctrl_pram*Ratio)       //Checking 
      { 
       S_current = S_trial;       //Expresses probability of uphill acceptance 
       E_current = E_t;         
      } 
      else 
       E_current = E_c; 
     } 

     return S_current; 
} 

//------------------------------------------------------------------------------ 
//Metropolis Function (Mod 18/02/09) 

double Metropolis(double S_start, double T_current, int N_Steps, int N_temperatures) 
{ 
    S_current = S_start;          //Initialised S_initial equated to S_current 

    for (int i=1; i <= N_step; i++)       //Iteration of neighbour states 
     S_current = Next_State(T_current, N_temperatures);  //Determines acceptance of new states 

    return S_current; 
} 

//------------------------------------------------------------------------------ 
//Write Results to Notepad (Completed 18/02/09) 

void WriteResults(double i, double T, double x, double y) 
{ 
//This function opens a results file (if not already opened) 
//and stores results for one time step 

    static ofstream OutputFile; 
    const int MAXLENGTH = 80; 

    if (!OutputFile.is_open()) //check is file has been opened 
    { 
     //no it hasn't. Get a file name and open it. 
     char FileName[MAXLENGTH]; 

     //read file name 
     cout << "Enter file name: "; 
     do 
     { 
      cin.getline(FileName, MAXLENGTH); 
     } 
     while (strlen(FileName) <= 0); //try again if length of string is 0 

     //open file 
     OutputFile.open(FileName); 

     // check if file was opened successfully 
     if (!OutputFile) 
     { 
      cerr << "Failed to open " << FileName << endl; 
      exit(EXIT_FAILURE); //abort program 
     } 

     OutputFile << "Iterations" << '\t' << "Temperatures" << '\t' << "X-Value" << '\t' << "Y-Value" << endl; 
     OutputFile << endl; 
    } 

    //OutputFile.width(10); 
    OutputFile << i << '\t' << T << '\t' << x << '\t' << y << endl; 

    if (i == N_max) 
    { 
     OutputFile << endl 
       << "Settings: " << endl 
       << "Initial Temperature: " << T_initial << endl 
       << "Temperature Iterations: " << N_max << endl 
       << "Step Iterations: " << N_step << endl 
       << endl 
       << "Results: " << endl 
       << "Final Temperature: " << T << endl 
       << "Minimum: " << S << endl; 

     OutputFile.close(); 
    } 
} 

//------------------------------------------------------------------------------ 
//Main SA Function (Mod 17/02/09) 

void SA(int W) 
{ 
    S = S_initial; 
    T = T_initial; 

    for (int N_temperatures = 1 ; N_temperatures <= N_max ; N_temperatures++) 
    { 
     S = Metropolis(S, T, N_step, N_temperatures); 
     T = Schedule(T, N_temperatures); 

     if (W == 1) 
      WriteResults(N_temperatures, T, S, E_current); 
    } 

    cout << "Result" << endl 
    << "Y-value> " << S << endl 
    << "Temperature> " << T << endl; 

} 

//------------------------------------------------------------------------------ 
//Execution of Traveling Salesman Problem (Progress 18/02/09) 


int main() 
{ 
    cout << "Quadratic Function" << endl 
     << "Solving method: Simulated Annealing" << endl; 
    cout << "" << endl; 

    cout << "Select desired Initial Temperature:" << endl 
     << "> "; 
    cin >> T_initial; 

    cout << "Select desired number of Temperature Iterations:" << endl 
     << "> "; 
    cin >> N_max; 

    cout << "Select desired number of step Iterations:" << endl 
     << "> "; 
    cin >> N_step; 

    Initialize(); 

    cout << "Write to file: (1/0) " << endl 
     << "> "; 
    cin >> Write; 

    SA(Write); 

    system ("PAUSE"); 

    return 0; 
} 

@ Strager - So che il suo codice male, ma purtroppo con i vincoli di tempo coinvolti per il mio progetto e la curva di apprendimento, consiquental risultati sono quelli che sono necessari! :) Sarà riordinato in queste ultime fasi.

@ dirkgently - Questa era la ragione iniziale per farlo in questo modo, e quindi perché il mio primo tentativo è quello di andare in questo modo.

+0

Un piccolo dettaglio in più su quale sia il problema potrebbe essere utile. Hai fornito un buon codice e molti dettagli, ma per lo più hai omesso quello che vuoi veramente risolvere ... – SoapBox

+0

Non è un buon codice ... non dovrebbe nemmeno essere compilato! Ci sono alcuni problemi le distanze è un doppio [15] [15] ma è assegnato come un puntatore. Il file viene controllato se è aperto prima che sia stato fatto qualcosa. Legge l'intero file in un buffer ... ecc., Ecc. – strager

+0

@strager: la lettura dell'intero file in un buffer è una tecnica di ottimizzazione. Molte persone che conosco lo usano quando scrivono il codice per programmare le competizioni;) – dirkgently

risposta

11

Che ne dici di questo?(KISS soluzione)

void LoadCities() { 
    int x, y; 
    ifstream in("Cities.txt"); 

    if (!in) { 
    cout << "Cannot open file.\n"; 
    return; 
    } 

    for (y = 0; y < 15; y++) { 
    for (x = 0; x < 15; x++) { 
     in >> distances[x][y]; 
    } 
    } 

    in.close(); 
} 

Lavori per me. Potrebbe non essere così complesso e forse non è molto performante, ma finché non stai leggendo un array 1000x1000, non vedrai alcuna differenza.

+0

Bello e semplicistico, ma per qualche motivo emette 0 o ogni valore quando eseguo il test, ad esempio aggiungo il seguente a destra dopo l'operazione <<: cout << x << "\ t" << y << '\ t' << distanze [x] [y] << endl; " – Temperedsoul

+0

Hm .. funziona qui (usando G ++) – schnaader

+0

@Temperedsoul: guarda i tuoi dati, è doppio, ma non ha una parte significativa dopo il decimale.Se vuoi un 5.0, devi dire tell così. aggiorna il mio esempio – dirkgently

1

Compilare anche? Ottengo ~ 7 errori. Un campione:

strtok(cities, "\n");

s' strtok() primo argomento è un char * e non uno std :: string.

Questo aiuto?

void LoadCities() 
{ 
    std::vector<double> f((std::istream_iterator<double> 
     (std::ifstream("city.txt"))), /* replace filename with your own */ 
    (std::istream_iterator<double>())); 
    if (!f.empty()) { 
    std::cout << f.size() << "\n"; 
    /* print an arbitrary data point with 2 places of decimal */ 
    std::cout << std::setprecision(2) << f[ 0 ] << std::endl; 

    } 
} 

Lavorare con le matrici non significa che è necessario disporre di una matrice multidimensionale. Soprattutto con array 2D. Naturalmente è più facile da leggere e scrivere;)

+0

così com'è non si compila. L'unico modo per compilarlo è quello di eliminare tutto da 'cities = ... "fino alla fine e semplicemente avere: CityFile.read (buffer, length) ;, cout.write (buffer, length); CityFile.close(); che non mi aiuta molto – Temperedsoul

+0

@Temperedsoul: Quindi, ora lo hai risolto? Se lo fai, perché non contrassegni la soluzione di schnaader come accettata? – dirkgently

1

probabilmente si desidera qualcosa di più semplice, come questo:

std::vector<std::vector<std::string> > LoadCities(const std::string &filename) 
{ 
    using namespace std; 

    ifstream file; 
    file.open(filename, ios::in | ios::out); 

    if(!file.is_open()) { 
     // error 
     return vector<vector<double> >(); 
    } 

    vector<vector<double> > data; 
    string line; 

    while(!std::getline(file, line, '\n').eof()) { 
     istringstream reader(line); 

     vector<double> lineData; 

     string::const_iterator i = line.begin(); 

     while(!reader.eof()) { 
      double val; 
      reader << val; 

      if(reader.fail()) 
       break; 

      lineData.push_back(val); 
     } 

     data.push_back(lineData); 
    } 

    return data; 
} 

In pratica si utilizza flussi di inserire i dati. Probabilmente sto facendo qualcosa di sbagliato (non mi sono mai occupato di iostreams; P) ma questo dovrebbe darti l'idea generale di come strutturare un lettore di matrici.

+0

Risultati in 4 errori, tre dei quali C2664 - 'funzione': impossibile convertire il numero di parametro da 'type1' a 'type2' - Vedrò se posso cancellarli. – Temperedsoul

0

Ecco come vorrei caricare/salvarlo:

#include <iostream> 
#include <fstream> 
#include <string> 

int width = 0; 
int height = 0; 
double **distances; 

void WriteDouble(std::ofstream &stream, double toWrite) 
{ 
    char buffer[8]; 
    memcpy(buffer, &toWrite, 8); 
    stream.write(buffer, 8); 
} 

void WriteInt(std::ofstream &stream, int toWrite) 
{ 
    char buffer[4]; 
    memcpy(buffer, &toWrite, 4); 
    stream.write(buffer, 4); 
} 

double ReadDouble(std::ifstream &stream) 
{ 
    double d = 0; 
    stream.read((char *)&d, 8); 
    return d; 
} 

int ReadInt(std::ifstream &stream) 
{ 
    int i = 0; 
    stream.read((char *)&i, 4); 
    return i; 
} 

void Save() 
{ 
    std::ofstream stream("cities", std::ios::out | std::ios::binary); 

    if(!stream.good()) { 
     throw std::exception("Error opening stream"); 
    } 

    WriteInt(stream, width); 
    WriteInt(stream, height); 

    for(int x = 0; x < width; x++) { 
     for(int y = 0; y < height; y++) { 
      WriteDouble(stream, distances[x][y]); 
     } 
    } 

    stream.close(); 
} 

void Load() 
{ 
    std::ifstream stream("cities", std::ios::in | std::ios::binary); 

    if(!stream.good()) { 
     throw std::exception("Error opening stream"); 
    } 

    width = ReadInt(stream); 
    height = ReadInt(stream); 

    distances = new double *[width]; 

    for(int i = 0; i < width; i++) { 
     distances[i] = new double[height]; 
    } 

    for(int x = 0; x < width; x++) { 
     for(int y = 0; y < height; y++) { 
      distances[x][y] = ReadDouble(stream); 
     } 
    } 

    stream.close(); 
} 

void RunSaveTest() 
{ 
    width = 15; 
    height = 15; 

    distances = new double *[width]; 

    for(int i = 0; i < width; i++) { 
     distances[i] = new double[height]; 
    } 

    for(int x = 0; x < width; x++) { 
     for(int y = 0; y < height; y++) { 
      distances[x][y] = (double)x/(double)(y + 1); 
      std::cout << distances[x][y] << std::endl; 
     } 
    } 

    Save(); 
} 

void RunLoadTest() 
{ 
    Load(); 

    for(int x = 0; x < width; x++) { 
     for(int y = 0; y < height; y++) { 
      std::cout << distances[x][y] << std::endl; 
     } 
    } 
} 

int main() 
{ 
    RunSaveTest(); 
    // RunLoadTest(); 

    return 0; 
} 
0

di riferimento dal mio blog: http://www.topbug.net/blog/2013/01/10/load-a-matrix-from-an-ascii-format-file/

Questo frammento di codice ha una maggiore tolleranza ai guasti invece di assumere tutto è ben formattato.

#include <istream> 
#include <string> 
#include <sstream> 
#include <vector> 

// load matrix from an ascii text file. 
void load_matrix(std::istream* is, 
     std::vector< std::vector<double> >* matrix, 
     const std::string& delim = " \t") 
{ 
    using namespace std; 

    string  line; 
    string  strnum; 

    // clear first 
    matrix->clear(); 

    // parse line by line 
    while (getline(*is, line)) 
    { 
     matrix->push_back(vector<double>()); 

     for (string::const_iterator i = line.begin(); i != line.end(); ++ i) 
     { 
      // If i is not a delim, then append it to strnum 
      if (delim.find(*i) == string::npos) 
      { 
       strnum += *i; 
       if (i + 1 != line.end()) // If it's the last char, do not continue 
        continue; 
      } 

      // if strnum is still empty, it means the previous char is also a 
      // delim (several delims appear together). Ignore this char. 
      if (strnum.empty()) 
       continue; 

      // If we reach here, we got a number. Convert it to double. 
      double  number; 

      istringstream(strnum) >> number; 
      matrix->back().push_back(number); 

      strnum.clear(); 
     } 
    } 
} 

// example 
#include <fstream> 
#include <iostream> 

int main() 
{ 
    using namespace std; 

    // read the file 
    std::ifstream is("input.txt"); 

    // load the matrix 
    std::vector< std::vector<double> > matrix; 
    load_matrix(&is, &matrix); 

    // print out the matrix 
    cout << "The matrix is:" << endl; 
    for (std::vector< std::vector<double> >::const_iterator it = matrix.begin(); it != matrix.end(); ++ it) 
    { 
     for (std::vector<double>::const_iterator itit = it->begin(); itit != it->end(); ++ itit) 
      cout << *itit << '\t'; 

     cout << endl; 
    } 

    return 0; 
} 
+0

questa soluzione è ultra mega plus SLOW – Pedro77

+0

@ Pedro77 Com'è così? – xuhdev

+0

Sto leggendo un file di testo di numeri 1200x1200. Matlab ⁠⁠⁠dlmread legge il file in pochi secondi. Questo metodo richiede un minuto. Qualcosa è sbagliato. – Pedro77