2009-02-21 12 views
6

Ich schreibe gerade einen Simulated Annealing-Code, um das Problem eines reisenden Verkäufers zu lösen, und habe Schwierigkeiten mit dem Speichern und Verwenden meiner gelesenen Daten aus einer TXT-Datei. Jede Zeile & Spalte in der Datei repräsentiert jede Stadt, wobei der Abstand zwischen zwei verschiedenen Städten als Matrix 15 x 15 gespeichert:Eine Matrix-TXT-Datei lesen und als Array speichern

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 

dies zu lesen Ich habe ein LoadCities() Funktion, wie unten gezeigt:

#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(); 
} 

ich habe eine alternative istreambuf_iterator Methode, um zu dem Punkt der Manipulation des Lesematerials in Arrays versucht, aber ich scheine immer in Komplikationen führen:

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

Jede Hilfe wäre sehr geschätzt. Ich habe meinen Kopf mit wenig Erfolg dagegengestoßen!

################ EDIT/Update

@ SoapBox - Einige Details der SA-Code, Funktionen und main(). Dies ist nicht sauber, effizient, sauber und nicht in diesem Stadium, sondern muss nur für den Moment arbeiten. Diese Version (unten) funktioniert und ist eingerichtet, um Polynome zu lösen (einfachste Probleme). Was muss getan werden, um wandelt es in ein Reiseproblem ist:

  1. die LoadCities Write() Funktion, um die Entfernungsdaten zu sammeln. (Current)

  2. ändern Initialise() die Summe der Entfernungen zu bekommen beteiligt

  3. ändern E() an die TSP-Funktion (zB Berechnen Entfernung einer Random-Route)

Die Letzten zwei, ich weiß, ich kann tun, aber ich brauche LoadCities(), um es zu tun. Im folgenden Skript muss nichts anderes geändert werden.

#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 - ich seinen schlechten Code kennen, aber leider mit den Zeitbeschränkungen für mein Projekt beteiligt und die consiquental Lernkurve, die Ergebnisse sind, was notwendig ist! :) Es wird in späteren Phasen aufgeräumt werden.

@ dirkentely - Das war der anfängliche Grund dafür, dies zu tun, und deshalb, warum mein erster Versuch ist es so zu gehen.

+0

Ein wenig mehr Details darüber, was das Problem tatsächlich ist, können hilfreich sein. Du hast guten Code und viele Details geliefert, aber größtenteils weggelassen, was du eigentlich lösen willst. – SoapBox

+0

Es ist kein guter Code ... er sollte nicht einmal kompilieren! Es gibt einige Probleme. Distanzen ist ein Doppel [15] [15], wird aber wie ein Zeiger zugewiesen. Die Datei wird geprüft, ob sie geöffnet wird, bevor etwas unternommen wurde. Er liest die gesamte Datei in einen Puffer ... usw. usw. – strager

+0

@strager: Das Lesen der gesamten Datei in einem Puffer ist eine Optimierungstechnik. Viele Leute, die ich kenne, benutzen es beim Schreiben von Code für Programmierwettbewerbe;) – dirkgently

Antwort

11

Wie wäre es damit?(KISS Lösung)

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(); 
} 

Funktioniert für mich. Vielleicht nicht so komplex und vielleicht nicht sehr performant, aber solange Sie kein 1000x1000 Array lesen, werden Sie keinen Unterschied sehen.

+0

Schön und simpel, aber aus irgendeinem Grund seine Ausgabe 0 oder jeden Wert wenn ich es teste, z. B. das folgende direkt nach der << Operation hinzufügen: "cout << x <<" \ t "<< y << '\ t' << distanzen [x] [y] << endl;" – Temperedsoul

+0

Hm .. funktioniert hier (mit G ++). – schnaader

+0

@Temperedsoul: Sehen Sie sich Ihre Daten an.Es ist doppelt, aber hat keinen signifikanten Teil nach dem Dezimal.Wenn Sie eine 5.0 wollen, müssen Sie tun, sagen Sie Cout so. Ich werde aktualisiere mein Beispiel – dirkgently

1

Kompiliert es überhaupt? Ich bekomme ~ 7 Fehler. Ein Beispiel:

strtok(cities, "\n");

strtok() ‚s erstes Argument ist ein char * und kein std :: string.

Hilft das?

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; 

    } 
} 

Das Arbeiten mit Matrizen bedeutet nicht, dass Sie ein mehrdimensionales Array benötigen. Vor allem mit 2D-Arrays. Natürlich ist es einfacher zu lesen und zu schreiben;)

+0

wie es ist kompiliert es nicht. Man kann es nur kompilieren, indem man alles von "cities = ..." bis zum Ende löscht und einfach: CityFile.read (Puffer, Länge) ;, cout.write (Puffer, Länge); CityFile.close(); was hilft mir nicht viel – Temperedsoul

+0

@Temperedsoul: So, jetzt haben Sie es behoben? Wenn Sie das tun, warum nicht schnaaders Lösung als akzeptiert markieren? – dirkgently

1

Sie wollen wahrscheinlich etwas einfacher, wie folgt aus:

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; 
} 

Grundsätzlich Sie die Datenströme zur Eingabe verwenden. Ich mache wahrscheinlich etwas falsches (ich habe mich nie mit Iostreams beschäftigt; P), aber das sollte Ihnen die allgemeine Idee geben, wie man einen Matrixleser strukturiert.

+0

Ergebnisse in 4 Fehlern, drei von ihnen C2664 - 'Funktion': kann nicht Konvertiere die Parameternummer von "type1" zu "type2" - ich werde sehen, ob ich sie aufräumen kann. – Temperedsoul

0

Hier ist, wie ich laden/speichern:

#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

Referenz aus meinem Blog: http://www.topbug.net/blog/2013/01/10/load-a-matrix-from-an-ascii-format-file/

Dieser Code-Schnipsel höhere Fehlertoleranz hat, anstatt alles unter der Annahme ist gut formatiert.

#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

diese Lösung ist Ultra Mega Plus SLOW – Pedro77

+0

@ Pedro77 Wie ist es so? – xuhdev

+0

Ich lese eine 1200x1200 Nummern Textdatei. Matlab ⁠⁠⁠dlmread liest die Datei in wenigen Sekunden. Diese Methode dauert eine Minute. Irgendwas stimmt nicht. – Pedro77

Verwandte Themen