Загрузка матрицы из файла - PullRequest
2 голосов
/ 06 февраля 2011

Мне нужно прочитать файл с матричными данными и создать матрицу в моей программе.Формат файла Matrix выглядит примерно так:

#  Matrix made by matblas from blosum62.iij
#  * column uses minimum score
#  BLOSUM Clustered Scoring Matrix in 1/2 Bit Units
#  Blocks Database = /data/blocks_5.0/blocks.dat
#  Cluster Percentage: >= 62
#  Entropy =   0.6979, Expected =  -0.5209
   A  R  N  D  C  Q  E  G  H  I  L  K  M  F  P  S  T  W  Y  V  B  Z  X  *
A  4 -1 -2 -2  0 -1 -1  0 -2 -1 -1 -1 -1 -2 -1  1  0 -3 -2  0 -2 -1  0 -4 
R -1  5  0 -2 -3  1  0 -2  0 -3 -2  2 -1 -3 -2 -1 -1 -3 -2 -3 -1  0 -1 -4 
N -2  0  6  1 -3  0  0  0  1 -3 -3  0 -2 -3 -2  1  0 -4 -2 -3  3  0 -1 -4 
D -2 -2  1  6 -3  0  2 -1 -1 -3 -4 -1 -3 -3 -1  0 -1 -4 -3 -3  4  1 -1 -4 
C  0 -3 -3 -3  9 -3 -4 -3 -3 -1 -1 -3 -1 -2 -3 -1 -1 -2 -2 -1 -3 -3 -2 -4 
Q -1  1  0  0 -3  5  2 -2  0 -3 -2  1  0 -3 -1  0 -1 -2 -1 -2  0  3 -1 -4 
E -1  0  0  2 -4  2  5 -2  0 -3 -3  1 -2 -3 -1  0 -1 -3 -2 -2  1  4 -1 -4 
G  0 -2  0 -1 -3 -2 -2  6 -2 -4 -4 -2 -3 -3 -2  0 -2 -2 -3 -3 -1 -2 -1 -4 
H -2  0  1 -1 -3  0  0 -2  8 -3 -3 -1 -2 -1 -2 -1 -2 -2  2 -3  0  0 -1 -4 
I -1 -3 -3 -3 -1 -3 -3 -4 -3  4  2 -3  1  0 -3 -2 -1 -3 -1  3 -3 -3 -1 -4 
L -1 -2 -3 -4 -1 -2 -3 -4 -3  2  4 -2  2  0 -3 -2 -1 -2 -1  1 -4 -3 -1 -4 
K -1  2  0 -1 -3  1  1 -2 -1 -3 -2  5 -1 -3 -1  0 -1 -3 -2 -2  0  1 -1 -4 
M -1 -1 -2 -3 -1  0 -2 -3 -2  1  2 -1  5  0 -2 -1 -1 -1 -1  1 -3 -1 -1 -4 
F -2 -3 -3 -3 -2 -3 -3 -3 -1  0  0 -3  0  6 -4 -2 -2  1  3 -1 -3 -3 -1 -4 
P -1 -2 -2 -1 -3 -1 -1 -2 -2 -3 -3 -1 -2 -4  7 -1 -1 -4 -3 -2 -2 -1 -2 -4 
S  1 -1  1  0 -1  0  0  0 -1 -2 -2  0 -1 -2 -1  4  1 -3 -2 -2  0  0  0 -4 
T  0 -1  0 -1 -1 -1 -1 -2 -2 -1 -1 -1 -1 -2 -1  1  5 -2 -2  0 -1 -1  0 -4 
W -3 -3 -4 -4 -2 -2 -3 -2 -2 -3 -2 -3 -1  1 -4 -3 -2 11  2 -3 -4 -3 -2 -4 
Y -2 -2 -2 -3 -2 -1 -2 -3  2 -1 -1 -2 -1  3 -3 -2 -2  2  7 -1 -3 -2 -1 -4 
V  0 -3 -3 -3 -1 -2 -2 -3 -3  3  1 -2  1 -1 -2 -2  0 -3 -1  4 -3 -2 -1 -4 
B -2 -1  3  4 -3  0  1 -1  0 -3 -4  0 -3 -3 -2  0 -1 -4 -3 -3  4  1 -1 -4 
Z -1  0  0  1 -3  3  4 -2  0 -3 -3  1 -1 -3 -1  0 -1 -3 -2 -2  1  4 -1 -4 
X  0 -1 -1 -1 -2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -2  0  0 -2 -1 -1 -1 -1 -1 -4 
* -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4 -4  1 

Буквы занимают постоянное место, поэтому, поскольку меня интересуют только четыре из них, я могу назначить x и y в программе.Что мне нужно, это только матрица со значениями, по которым я мог бы искать значения, задавая функции 'GetValue', 'x' и 'y'.

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

/*
 * algorytm.cpp
 * implementacja algorytmu
 *
 * Autor: Mateusz
 *
 */

#include <cstdlib>
#include <iostream>
#include <string>
#include <stdio.h>
#include <fstream>
#include <vector>
#include "matryca_sub.h"
#include <sstream>
#include <istream>
#include <sstream>

using namespace std;

int ScoreMatrix::MainMatrix(char *mat_file, int x, int y)
{
    cout << "Main matrix function start" << endl;
    CreateMatrix(30);
    ReadMatrix(mat_file);
    int val;
    val=GetValue(x, y);
    return val;
    cout << "Main matrix function end" << endl;
}

void ScoreMatrix::CreateMatrix(int edge)
{
    cout << "Creating sub matrix start" << endl;
   //int** scores = new int* [*edge-1];
   //for (int i=0; i<=23; i++) scores[i] = new int[*edge-1];
   if( scores != 0 ) delete [] scores;
   scores =  new int [edge*edge];
   cols = edge;
   cout << "Sub matrix created" << endl;
}

void ScoreMatrix::SetValue(int x, int y, int val)
{
    cout << "write to sub matrix start" << endl;
    //scores[x][y] = val;
    scores[(cols* y) + x] = val;
    cout << "write to sub matrix end" << endl;
}

int ScoreMatrix::GetValue(int x, int y)
{
    //cout << "GetValue start" << endl;
    //return scores[x][y];
    return scores[(cols * x) + y];
    cout << "GetValue end" << endl;
}

void ScoreMatrix::ReadMatrix(char *mat_file)
{
    cout << "start reading matrix from file" << endl;
    int row=0;
    ifstream mfile;
    mfile.open(mat_file);
    mfile.precision(2);
    mfile.setf(ios::fixed, ios::showpoint);
    while(!mfile.eof())
    {
        for (row=0; row<=23; row++)
        {
        string line;
        getline( mfile, line);
        istringstream iss(line);

        if (line[0] !='#' && line[0] != ' ')
        {
            int s;
            iss >> s;
            for (int i=1; !iss.eof(); i++)
            {
                iss >> s;
                SetValue(i, row, s);
            }

        }
        }
    }
    cout << "end reading matrix from file" << endl;
}

Включен заголовочный файл:

/*
 * File:   mat_sub.h
 * Author: mateusz
 *
 * Created on 6 luty 2011, 14:44
 */

#ifndef MAT_SUB_H
#define MAT_SUB_H
#include <cstdlib>
#include <iostream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <vector>
#include <algorithm>
#include <string.h>

using namespace std;

class ScoreMatrix
{
public:
    ScoreMatrix():
    cols (0)
    ,scores (0)
    {}

    char mat_file;
    int MainMatrix(char *mat_file, int x, int y);
    int GetValue(int x, int y);

private:
    int cols, rows;
    int* scores;

    void CreateMatrix(int edge);
    void SetValue(int x, int y, int val);
    void ReadMatrix(char *mat_file);
};



#endif  /* MAT_SUB_H */

Перед функцией seagfoult выведите один из многих start reading matrix from file.

Ответы [ 5 ]

3 голосов
/ 06 февраля 2011

О боже.Я надеюсь, что вы простите меня, если я буду звучать грубо, но у этого кода есть много проблем, начиная от базового дизайна и заканчивая деталями, такими как циклы, которые вы используете для чтенияданные из файла.

Прежде всего, мне кажется, что вашему классу "матрицы" нужна здоровая доза "единственной ответственности".Я бы сократил его до двухмерной матрицы, ничего больше.

Во-вторых, я бы избавился от управления памятью самостоятельно.Все, что вам действительно нужно, это std::vector, с достаточным количеством внешнего интерфейса для обеспечения 2D-адресации.

В-третьих, я бы избавился от "getValue" / "setValue" и использовал бы подписку, как и всеПрилично спроектированная матрица, поскольку научные программисты перешли с ассемблера на Фортран в 1950-х годах.

Принимая это во внимание, мы получаем упрощенный класс матрицы, что-то вроде этого:для простоты, когда вы подписываете это, вы используете () примерно так же, как в Fortran или BASIC, вместо того, чтобы использовать [], как вы это обычно делаете в C или C ++.Вы можете поддержать последнее, но это займет намного больше (и уродливее) код .Также обратите внимание, что вы делаете , а не , хотите cols * (y+x), вам нужно (cols * y) + x, если вы настаиваете на использовании скобок (хотя думаете, что это довольно глупо, учитывая, что относительный приоритет умножения и сложения довольно хорошо известен. Наконец,Я сделал этот шаблон просто потому, что это легко сделать - если вы хотите указать тип напрямую, это, очевидно, довольно легко сделать.

Наконец, я бы сделал чтение данных изфайл в матрицу в свободную функцию. При этом я избавлюсь от всех while (!whatever.eof()), потому что они гарантированно работают неправильно.

template <class T>
void read_matrix(std::string const &filename, matrix<T> &m) { 
    std::ifstream infile(filename);
    std::string line;
    int x = 0, y=0;

    while (std::getline(infile, line)) {
        if (line[0] == '#' || line[0] == ' ')
            continue;

        int value;
        std::istringinstream converter(&line[1]); // &line[1] to skip leading letter
        while (converter >> value)
            m(x++, y) = value;
        ++y;
    }            
}

Технически, &line[1]не гарантируется работа C ++ 03, но C ++ 11 действительно гарантирует это, в основном потому, что он работает со всеми известными реализациями.

1 голос
/ 15 мая 2011

(в случае, если ваш код не работает) Код AC, который читает этот (и только этот) формат:

int base2num(char b)
// just a numbering scheme for the input characters. This indexing will be used
// in the matrix into which it is read
{
    switch (b) 
    {
    case 'A': case 'a': return 0; break;
    case 'C': case 'c': return 1; break;
    case 'G': case 'g': return 2; break;
    case 'T': case 't': return 3; break;
    case 'P': case 'p': return 4; break;
    case 'V': case 'v': return 5; break;
    case 'L': case 'l': return 6; break;
    case 'I': case 'i': return 7; break;
    case 'M': case 'm': return 8; break;
    case 'F': case 'f': return 9; break;
    case 'Y': case 'y': return 10; break;
    case 'W': case 'w': return 11; break;
    case 'H': case 'h': return 12; break;
    case 'K': case 'k': return 13; break;
    case 'R': case 'r': return 14; break;
    case 'Q': case 'q': return 15; break;
    case 'N': case 'n': return 16; break;
    case 'E': case 'e': return 17; break;
    case 'D': case 'd': return 18; break;
    case 'S': case 's': return 19; break;
    default: return -1;
    }
}

void str2int(char *line, int i, int *mat, char *arr)
{
    int m,k;
    char * endptr;
    endptr=line+1;
    for (m=0;m<23;m++)
    {
        k=base2num(arr[m]);
        if (k==-1)
            continue;
        mat[i*20+k]=strtol(endptr,&endptr,0);


    }
 }
void parseinp(FILE *fp, int *mat)
{
    int i,j;
    char line[256];
    char arr[23];

    while (fgets(line,256,fp)!=NULL)
    {    
        if (line[0]=='#')
            continue;

        i=3;
        j=0;
        if (base2num(line[3])!=-1) 
            //assumption: the first character is
        //part of the 20 bases
        {
            while(line[i]!='*') 
             // this is the first line of the table,
            // that which contains  A R N D etc.
            // store the chars in arr
            {
                arr[j]=line[i];
                j++;
                i+=3;
            }   
            continue;
        }   
        i=base2num(line[0]);
        if (i<0) // not one of the 20 core bases
        {
            continue;
        }
        else
        {
          //  printf("%d\n",i);
            str2int(line,i,mat,arr);
        }
    }
}

int * get_blosum()
{
    FILE *fp;
    int  *mat;
    int n,m;

    mat=(double *) calloc(400, sizeof(double));
    fp =fopen("BLOSUM62","r");
    if (fp==NULL)
    {
        perror("failed to open protein matrix file!");
    }
    parseinp(fp, mat);

    fclose(fp);
    return mat;
}
1 голос
/ 06 февраля 2011

Это:

scores = new int[[*edge] [*edge]];

- недопустимый синтаксис C ++.Вы имеете в виду это:

scores = new int[*edge * *edge];

Точно так же, когда вы пытаетесь получить доступ к элементу scores, вы должны сделать что-то вроде:int указателем на функцию, если вы не собираетесь изменять исходное значение.Я бы переписал CreateMatrix() как:

void ScoreMatrix::CreateMatrix(int edge)
{
   scores =  new int[edge*edge];
   cols = edge;
}
0 голосов
/ 06 февраля 2011

Чтобы оценивать что-то раньше других, вы не используете [], а парантез.Это должно выглядеть так:

void ScoreMatrix::CreateMatrix(int *edge)
{
   scores =  new int[(*edge) * (*edge)];
   cols = *edge;
}

void ScoreMatrix::SetValue(int x, int y, int val)
{
    scores[cols * (y + x)] = val;
}

int ScoreMatrix::GetValue(int x, int y)
{
    return *scores[cols * (x + y)];
}
0 голосов
/ 06 февраля 2011

Похоже, вы неправильно используете синтаксис []. Я думаю, что вы хотите изменить следующие строки:

scores =  new int[[*edge] [*edge]];
scores[cols *[y + x]] = val;
return *scores[cols *[x + y]];

до

scores =  new int[(*edge) * (*edge)];
scores[cols * (y + x)] = val;
return *scores[cols * (x + y)];

Обратите внимание на использование скобок () вместо [].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...