2009-02-21 4 views
6

В настоящее время я пишу Имитированный код отжига для решения проблемы коммивояжера и сталкиваюсь с трудностями при хранении и использовании моих прочитанных данных из txt-файла. Каждый столбец строки & в файле представляет каждый город, с расстоянием между двумя различными городами, хранящихся в виде 15 х 15 матрицы:Чтение файла txt матрицы и сохранение в виде массива

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 

, чтобы прочитать это у меня есть LoadCities() функции, как показано ниже:

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

Я попытался альтернативный метод istreambuf_iterator, чтобы добраться до точки манипулируя чтения материала в массивы, но я всегда, кажется, столкнулись с осложнениями:

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

Любая помощь будет очень полезна. Я сбился с ног на голову с небольшим успехом!

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

@ SoapBox - Некоторые детали кода SA, функций и main(). Это не чисто, эффективно, аккуратно и не хочет быть на этом этапе, просто нужно работать на данный момент. Эта версия (ниже) работает и настраивается для решения многочленов (простейшие задачи). Что нужно сделать, чтобы преобразовать его в задачи коммивояжера заключается в следующем:

  1. Пишет LoadCities функции(), чтобы собрать данные расстояния. (Ток)

  2. Изменение Initialise(), чтобы получить общее количество расстояний

  3. Изменить E() функции TSP (например, рассчитать расстояние случайного маршрута)

последние два я знаю, что могу сделать, однако для этого требую LoadCities(). В следующем скрипте ничего не нужно изменять.

#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 - Я знаю его плохой код, но несчастливо с временными ограничениями, привлекаемых для моего проекта и consiquental кривой обучения, результаты являются то, что нужно! :) Это будет прибрано на последних этапах.

@ dirkgently - Это была начальная причина для этого, и поэтому моя первая попытка - пойти на него так.

+0

Немного подробная информация о том, что проблема на самом деле может быть полезна. Вы поставили хороший код и много деталей, но в основном оставили то, что вы на самом деле хотите решить ..... – SoapBox

+0

Это не хороший код ... он даже не компилируется! Есть некоторые проблемы. расстояния - это двойной [15] [15], но назначается как указатель. Файл проверяется, если он открыт, прежде чем что-либо будет сделано с ним. Он читает весь файл в буфер ... и т. Д. И т. Д. – strager

+0

@strager: чтение всего файла в буфере - это метод оптимизации. Многие люди, которых я знаю, используют это при написании кода для соревнований по программированию;) – dirkgently

ответ

11

Как насчет этого?(KISS)

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

Работы для меня. Возможно, это не так сложно и, возможно, не очень показательно, но пока вы не читаете массив 1000x1000, вы не увидите никакой разницы.

+0

Приятный и упрощенный, однако по какой-то причине его вывод 0 или любое значение когда я проверяю его. Например, добавьте следующее после << операции: «cout << x <<" \ t "<< y << '\ t' << расстояния [x] [y] << endl;" – Temperedsoul

+0

Hm .. работает здесь (с использованием G ++). – schnaader

+0

@Temperedsoul: Посмотрите на свои данные. Он двойной, но не имеет значимой части после десятичной. Если вам нужен 5.0, вам нужно будет сказать cout так. обновить мой пример. – dirkgently

1

Он даже скомпилирован? Я получаю ~ 7 ошибок. Образец:

strtok(cities, "\n");

strtok() «s первый аргумент является char * и не станд :: строка.

Помогает ли это?

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; 

    } 
} 

Работа с матрицами не означает, что вам необходимо иметь многомерный массив. Особенно, с 2D-массивами. Конечно, читать и писать легче;)

+0

как есть. Единственный способ скомпилировать его - удалить все из «city = ...» до конца и просто иметь: CityFile.read (buffer, length) ;, cout.write (buffer, length); CityFile.close(); - который мне не очень помогает – Temperedsoul

+0

@Temperedsoul: Итак, теперь вы его исправили? Если вы это сделаете, почему бы вам не пометить решение schnaader как принятое? – dirkgently

1

Вы, вероятно, хотите что-нибудь попроще, например:

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

В основном вы используете потоки для ввода данных. Я, вероятно, что-то делаю неправильно (я никогда не занимался iostreams; P), но это должно дать вам общее представление о том, как структурировать матричный читатель.

+0

Результаты в 4 ошибки, три из них C2664 - «function»: can not преобразовать номер параметра из 'type1' в 'type2' - я увижу, смогу ли я их очистить. – Temperedsoul

0

Вот как я бы загрузить/сохранить:

#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

Ссылка из моего блога: http://www.topbug.net/blog/2013/01/10/load-a-matrix-from-an-ascii-format-file/

Этот фрагмент кода имеет более высокую отказоустойчивость, а не предполагая, все хорошо отформатированный.

#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

это решение - ультра мега плюс SLOW – Pedro77

+0

@ Pedro77 Как это так? – xuhdev

+0

Я читаю текстовый файл с номерами 1200x1200. Matlab ⁠⁠⁠dlmread читает файл за несколько секунд. Этот метод занимает минуту. Что-то не так. – Pedro77