2009-02-21 11 views
6

Actualmente estoy escribiendo un código de recocido simulado para resolver un problema de vendedor ambulante y he tenido dificultades para almacenar y usar mis datos leídos de un archivo txt. Cada columna fila & en el archivo representa cada ciudad, con la distancia entre dos ciudades diferentes almacenados como una matriz de 15 x 15:Lectura de un archivo txt Matrix y almacenamiento como una matriz

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 

Para leer este Tengo LoadCities() la función como se muestra a continuación:

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

he intentado un método istreambuf_iterator alternativa para llegar al punto de manipular el material de lectura en matrices, sin embargo siempre me parece encontrarse con complicaciones:

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

Cualquier ayuda sería muy apreciada. ¡He estado golpeando mi cabeza contra esto con poco éxito!

################ EDITAR/actualización

@ SoapBox - Algunos Detalle del código SA, funciones y main(). Esto no es limpio, eficiente, ordenado y no está en esta etapa, solo necesita trabajar por el momento. Esta versión (a continuación) funciona y está configurada para resolver polinomios (los problemas más simples). Lo que hay que hacer para convertirlo en un problema del viajante es:

  1. escribir el LoadCities() para recopilar los datos de distancia. (Actual)

  2. Cambio de iniciación() para obtener el total de las distancias

  3. Cambio E() a la función TSP (por ejemplo, calcular la distancia de una ruta al azar)

El Los últimos dos que sé que puedo hacer, sin embargo, requiero que LoadCities() lo haga. Nada más debe cambiarse en el siguiente 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 - Sé que es mal código, pero por desgracia con las limitaciones de tiempo para mi proyecto y la curva de aprendizaje consiquental, los resultados son lo que se necesita! :) Será arreglado en las últimas etapas.

@ dirkgently - Esa fue la razón inicial para hacerlo de esta manera, y por lo tanto, mi primer intento es hacerlo de esa manera.

+0

Un poco más de detalles acerca de lo que es realmente el problema puede ser útil. Has proporcionado un buen código y muchos detalles, pero casi siempre has omitido lo que realmente quieres resolver ... – SoapBox

+0

No es un código bueno ... ¡ni siquiera debería compilar! Hay algunos problemas. distancias es un doble [15] [15] pero se asigna como un puntero. El archivo se marca si se abre antes de que se le haya hecho algo. Lee el archivo completo en un búfer ... etc, etc. – strager

+0

@strager: Leer todo el archivo en un búfer es una técnica de optimización. Mucha gente que conozco lo usa cuando escribe código para competiciones de programación;) – dirkgently

Respuesta

11

¿Qué tal esto?(KISS solución)

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

Funciona para mí. Puede que no sea tan complejo y que tal vez no sea muy eficaz, pero mientras no esté leyendo una matriz de 1000x1000, no verá ninguna diferencia.

+0

Agradable y simplista, sin embargo, por alguna razón su salida 0 o cada valor cuando lo pruebo. Por ejemplo, agregando lo siguiente justo después de la << operación: "cout << x <<" \ t "<< y << '\ t' << distancias [x] [y] << endl;" – Temperedsoul

+0

Hm .. funciona aquí (usando G ++). – schnaader

+0

@Temperedsoul: Mire sus datos. Es doble, pero no tiene una parte significativa después del decimal. Si quiere un 5.0, debe informarlo. actualizar mi ejemplo. – dirkgently

1

¿Incluso compila? Recibo ~ 7 errores. Una muestra:

strtok(cities, "\n");

strtok() 's primer argumento es una char * y no un std :: string.

¿Le sirve de ayuda?

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; 

    } 
} 

Trabajar con matrices no significa que necesite tener una matriz multidimensional. Especialmente, con arreglos en 2D. Por supuesto, es más fácil de leer y escribir;)

+0

ya que no compila. La única forma de compilarlo es eliminar todo, desde 'cities = ...' hasta el final y simplemente tener: CityFile.read (buffer, length) ;, cout.write (buffer, length); CityFile.close(); - que no me ayuda mucho – Temperedsoul

+0

@Temperedsoul: Entonces, ¿ya lo tienes arreglado? Si lo haces, ¿por qué no marcas la solución de schnaader como aceptada? – dirkgently

1

es probable que desee algo más simple, como esto:

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

Básicamente se usan corrientes de entrada a los datos. Probablemente estoy haciendo algo mal (nunca he tratado con iostreams; P) pero esto debería darte la idea general de cómo estructurar un lector de matriz.

+0

Resulta en 4 errores, tres de ellos C2664 - 'función': no ​​se puede convertir el número de parámetro de 'type1' a 'type2' - Veré si puedo borrarlos. – Temperedsoul

0

Aquí es cómo iba a cargar/guardar:

#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

de referencia de mi blog: http://www.topbug.net/blog/2013/01/10/load-a-matrix-from-an-ascii-format-file/

Este fragmento de código tiene una mayor tolerancia a fallos en lugar de asumir que todo está bien formateado.

#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

esta solución es ultra mega plus LENTA – Pedro77

+0

@ Pedro77 ¿Cómo es esto? – xuhdev

+0

Estoy leyendo un archivo de texto con números de 1200x1200. Matlab ⁠⁠⁠dlmread lee el archivo en unos segundos. Este método toma un minuto. Algo está mal. – Pedro77

Cuestiones relacionadas