Lecture d'un fichier txt Matrix et le stockage sous forme de tableau
Question
J'écris actuellement un code Recuit Simulé pour résoudre un problème de voyageur de commerce et se sont heurtées à des difficultés avec le stockage et l'utilisation de mes données lues à partir d'un fichier txt. Chaque rangée et colonne du fichier représente chaque ville, la distance entre deux villes différentes stockées en tant que matrice 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
Pour lire cela, j'ai une fonction LoadCities (), comme indiqué ci-dessous:
#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();
}
Je l'ai essayé une méthode alternative à istreambuf_iterator arriver au point de manipuler le matériel de lecture dans des tableaux, mais il me semble toujours entraîner des complications:
ifstream CityFile("Cities.txt");
string theString((std::istreambuf_iterator<char>(CityFile)), std::istreambuf_iterator<char>());
Toute aide serait beaucoup appriciated. Dénigrement tête Been contre ce avec peu de succès!
################ EDIT / Mise à jour@ SoapBox - détail du code SA, fonctions et main (). Ce n'est pas propre, efficace, bien rangé et est ment pas être à ce stade, juste besoin de travailler pour le moment. Cette version (ci-dessous) fonctionne et est configuré pour résoudre polynômes (problèmes les plus simples). Ce qui doit être fait pour le convertir en un voyageur de commerce Le problème est à:
-
Exprimer la fonction LoadCities () pour recueillir les données de distance. (Courant)
-
Changement Initialiser () pour obtenir le total des distances
-
Variation E () à la fonction de TSP (par exemple Calculer la distance d'un trajet aléatoire)
Ces deux derniers, je sais que je peux le faire, mais je besoin LoadCities () de le faire. Rien d'autre a besoin d'être changé dans le script suivant.
#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 - Je sais que son mauvais code, mais malheureusement avec les contraintes de temps impliquées pour mon projet et la courbe d'apprentissage consiquental, les résultats sont ce qui sont nécessaires! :) Elle sera rangea au cours des étapes ultérieures.
@ dirkgently -. Ce fut la première raison pour le faire de cette façon, et donc pourquoi ma première tentative est d'aller à elle comme si
La solution
Comment cela? ( solution EMBRASSER )
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();
}
Travaux pour moi. Pourrait ne pas être que complexe et est peut-être pas très performant, mais aussi longtemps que vous ne lisez pas un tableau de 1000x1000, vous ne verrez aucune différence.
Autres conseils
Vous voulez sans doute quelque chose de simple, comme ceci:
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;
}
Fondamentalement, vous utilisez les flux d'entrée des données. Je suis probablement faire quelque chose de mal (je ne l'ai jamais traité iostreams; P). Mais cela devrait vous donner l'idée générale de la façon de structurer un lecteur de matrice
-t-il même compiler? Je reçois ~ 7 erreurs. Un échantillon:
strtok(cities, "\n");
Le premier argument de strtok()
est un char *
et non un std :: string.
Est-ce que cette aide?
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;
}
}
Travailler avec des matrices ne signifie pas que vous devez disposer d'un tableau multidimensionnel. En particulier, avec des tableaux 2D. Bien sûr, il est plus facile à lire et à écrire;)
Voici comment je charger / enregistrer:
#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;
}
Référence de mon blog: http://www.topbug.net/blog/2013/01/10/load-a-matrix-from-an-ascii-format-file/
Cet extrait de code a une tolérance de défaut supérieur au lieu de l'hypothèse où tout est bien formaté.
#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;
}