Pergunta

Atualmente estou escrevendo um código Simulated Annealing para resolver um problema do caixeiro viajante e ter executado em dificuldades com armazenamento e uso de meus dados lidos de um arquivo txt. Cada linha e coluna no arquivo representa cada cidade, com a distância entre duas cidades diferentes armazenados como uma matriz de 15 x 15:

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 ler este eu tenho LoadCities () como mostrado abaixo:

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

Eu tenho tentado um método istreambuf_iterator alternativa para chegar ao ponto de manipular o material de leitura em matrizes, no entanto eu sempre parecem correr em complicações:

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

Qualquer ajuda seria muito appriciated. Sido batendo minha cabeça contra isso com pouco sucesso!

################ EDIT / Atualizar

@ SoapBox - algum detalhe do SA de código, funções e main (). Este não é limpo, eficiente, arrumado e não é ment ser nesta fase, só precisa de trabalho para o momento. Esta versão (abaixo) funciona e está configurado para resolver polinômios (problemas mais simples). O que precisa ser feito para convertê-lo em um vendedor ambulante Problema é:

    função
  1. Escrever os LoadCities () para reunir os dados de distância. (Atual)

  2. Alterar Inicializar () para obter o total das distâncias envolvidas

  3. Mudança E () a função do TSP (por exemplo, calcular a distância de um percurso aleatório)

Os dois últimos eu sei que posso fazer, no entanto eu preciso LoadCities () para fazê-lo. necessidades nada mais a ser alterada na seguinte 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 - Eu sei que o seu código ruim, mas infelizmente com as limitações de tempo envolvidos para o meu projeto e a curva de aprendizagem consiquental, os resultados são o que são necessários! :) Vai ser arrumado em fases finais.

@ dirkgently - Essa foi a razão inicial para fazê-lo desta forma, e daí porque a minha primeira tentativa é ir para ele como assim

.
Foi útil?

Solução

Como sobre isso? ( solução BEIJO )

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 mim. Pode não ser tão complexo e, talvez, não é muito alto desempenho, mas contanto que você não está lendo uma matriz 1000x1000, você não vai ver nenhuma diferença.

Outras dicas

Você provavelmente vai querer algo mais simples, como este:

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

Basicamente você usa fluxos para inserir os dados. Eu provavelmente estou fazendo algo errado (eu nunca lidaram com iostreams; P). Mas isso deve dar-lhe a idéia geral de como estruturar um leitor de matriz

Será que ainda compilar? Eu recebo ~ 7 erros. Uma amostra:

strtok(cities, "\n");

O primeiro argumento de strtok() é um char * e não um std :: string.

Será que isso ajuda?

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; 

  }
}

Trabalhar com matrizes não significa que você precisa ter uma matriz multidimensional. Especialmente, com 2D matrizes. É claro que é mais fácil de ler e escrever;)

Aqui está como eu iria carregar / salvar-lo:

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

Referência do meu blog: http://www.topbug.net/blog/2013/01/10/load-a-matrix-from-an-ascii-format-file/

Este trecho de código tem maior tolerância a falhas ao invés de assumir que tudo está bem formatado.

#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;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top