двумерная динамическая матрица
От: serg_stratos  
Дата: 28.11.03 13:06
Оценка:
Подскажите идею, плз.

Как лучше реализовать двумерную матрицу, в строках которой находятся элементы (точки в многомерном пространстве), а в колонках — соответствующие координаты этих точек.

Особенность состоит в том, что нужна возможность добавлять точки,
и в то же время работать с целыми колонками (имеется ввиду не тип данных, а вся колонка). Чтобы можно было добавить новую координату(и не одну), которая вычисляется из предыдущих по указанному правилу (например, линейная комбинация- x1+0.5*x2+0.2*x4).

Как такое можно в достаточной мере оптимально (по скорости) организовать?

Заранее спасибо,
Сергей.
... << RSDN@Home 1.1 beta 2 >>
Re: двумерная динамическая матрица
От: Bell Россия  
Дата: 28.11.03 13:35
Оценка:
Здравствуйте, serg_stratos, Вы писали:

std::vector<std::vector<double> >
Любите книгу — источник знаний (с) М.Горький
Re: двумерная динамическая матрица
От: Кодт Россия  
Дата: 28.11.03 13:43
Оценка:
Здравствуйте, serg_stratos, Вы писали:

_>Как лучше реализовать двумерную матрицу, в строках которой находятся элементы (точки в многомерном пространстве), а в колонках — соответствующие координаты этих точек.


_>Особенность состоит в том, что нужна возможность добавлять точки,

_>и в то же время работать с целыми колонками (имеется ввиду не тип данных, а вся колонка). Чтобы можно было добавить новую координату(и не одну), которая вычисляется из предыдущих по указанному правилу (например, линейная комбинация- x1+0.5*x2+0.2*x4).

_>Как такое можно в достаточной мере оптимально (по скорости) организовать?


Максимум скорости: линейный массив и адаптеры координат.
Примерно так.
enum access_mode { _ro_, _rw_ };

struct matrix
{
  int xdim, ydim;
  vector<double> data;

  int xy2i(int x, int y) const { return x*ydim + y; }

  double at(int x, int y) const { return data[xy2i(x,y)]; }
  double& at(int x, int y) { return data[xy2i(x,y)]; }

  template<access_mode> struct traits {};
  template<> struct traits<_ro_> { typedef const matrix matrix_t; typedef double  data_t; };
  template<> struct traits<_rw_> { typedef       matrix matrix_t; typedef double& data_t; };

  col<_ro_> operator[](int x) const { return col<_ro_>(this, x); }
  col<_rw_> operator[](int x) { return col<_rw_>(this, x); }

  col<_ro_> col_at(int x) const { return col<_ro_>(this,x); }
  row<_ro_> row_at(int y) const { return row<_ro_>(this,y); }
  // остальные - аналогично :)

  template<access_mode am>
  void insert_col(int x, const col<am>& src)
  {
    assert(src.mtx->ydim == ydim);

    // столбец занимает сплошной фрагмент
    data.insert(data.begin()+x*ydim, ydim, double());
    ++xdim;

    col<_rw_> dst = (*this)[x];
    for(int y = 0; y < ydim; ++y) dst[y] = src[y];
  }

  template<access_mode am>
  void insert_row(int y, const row<am>& src)
  {
    assert(src.mtx->xdim == xdim);

    // строка - раскидана по столбцам
    for(int x = 0; x < xdim; ++x) data.insert(data.begin()+x*(ydim+1)+y, double());
    ++ydim;

    row<_rw_> dst = row_at(y);
    for(int x = 0; x < xdim; ++x) dst[x] = src[x];
  }
};

template<access_mode am>
struct col
{
  typedef matrix::traits<am>::matrix_t matrix_t;
  typedef matrix::traits<am>::data_t data_t;

  matrix_t* mtx;
  int x;

  col(matrix_t* _m, int _x) : mtx(_m), x(_x) {}

  // из RW всегда можно получить RO
  col(const col<_rw_>& src) : mtx(src.mtx), x(src.x) {}
  // а конструктор копирования - по умолчанию.

  data_t operator[](int y) const { return mtx->at(x,y); }
};
Перекуём баги на фичи!
Re[2]: двумерная динамическая матрица
От: Andy Panda США  
Дата: 29.11.03 19:15
Оценка:
К>Максимум скорости: линейный массив и адаптеры координат.
К>Примерно так.
К>
К>enum access_mode { _ro_, _rw_ };

К>struct matrix
К>{
К>  int xdim, ydim;
К>  vector<double> data;

К>  int xy2i(int x, int y) const { return x*ydim + y; }

К>  double at(int x, int y) const { return data[xy2i(x,y)]; }
К>  double& at(int x, int y) { return data[xy2i(x,y)]; }

К>  template<access_mode> struct traits {};
К>  template<> struct traits<_ro_> { typedef const matrix matrix_t; typedef double  data_t; };
К>  template<> struct traits<_rw_> { typedef       matrix matrix_t; typedef double& data_t; };

К>  col<_ro_> operator[](int x) const { return col<_ro_>(this, x); }
К>  col<_rw_> operator[](int x) { return col<_rw_>(this, x); }

К>  col<_ro_> col_at(int x) const { return col<_ro_>(this,x); }
К>  row<_ro_> row_at(int y) const { return row<_ro_>(this,y); }
К>  // остальные - аналогично :)

К>  template<access_mode am>
К>  void insert_col(int x, const col<am>& src)
К>  {
К>    assert(src.mtx->ydim == ydim);

К>    // столбец занимает сплошной фрагмент
К>    data.insert(data.begin()+x*ydim, ydim, double());
К>    ++xdim;

К>    col<_rw_> dst = (*this)[x];
К>    for(int y = 0; y < ydim; ++y) dst[y] = src[y];
К>  }

К>  template<access_mode am>
К>  void insert_row(int y, const row<am>& src)
К>  {
К>    assert(src.mtx->xdim == xdim);

К>    // строка - раскидана по столбцам
К>    for(int x = 0; x < xdim; ++x) data.insert(data.begin()+x*(ydim+1)+y, double());
К>    ++ydim;

К>    row<_rw_> dst = row_at(y);
К>    for(int x = 0; x < xdim; ++x) dst[x] = src[x];
К>  }
К>};

К>template<access_mode am>
К>struct col
К>{
К>  typedef matrix::traits<am>::matrix_t matrix_t;
К>  typedef matrix::traits<am>::data_t data_t;

К>  matrix_t* mtx;
К>  int x;

К>  col(matrix_t* _m, int _x) : mtx(_m), x(_x) {}

К>  // из RW всегда можно получить RO
К>  col(const col<_rw_>& src) : mtx(src.mtx), x(src.x) {}
К>  // а конструктор копирования - по умолчанию.

К>  data_t operator[](int y) const { return mtx->at(x,y); }
К>};
К>


К> template<access_mode> struct traits {};

К> template<> struct traits<_ro_> { typedef const matrix matrix_t; typedef double data_t; };
Этот шаблон позволяет не делать const_cast если в функции аргумент-матрица константный?

А можно вопрос расширить. Если задачу придется рассматривать с другой точки зрения. матрицу можно хранить по разному.

Подобная вещь уже была сделана, отчасти. А если теперь хочется отделить представление матриц от того, как они хранятся?

Пока что — только идея объявить интерфейс самой матрицы.
class IMatrix {
size x,y;
myType& operator()(int row,col)
}

class IOperationMatrix{
IMatrix someMatr;
inverse();
другие операции..
}

Но — возникает проблема. От матрицы могут потребоваться специфические операции, которые могут быть удобны для одного случая хранения матрицы, и не так удобны для другого.
Как удобнее может быть объявлять подобные операции (как описанные выше — доступ к колонке или строке)?
Re: двумерная динамическая матрица
От: What Беларусь  
Дата: 30.11.03 12:54
Оценка:
Здравствуйте, serg_stratos, Вы писали:

_>Подскажите идею, плз.


_>Как лучше реализовать двумерную матрицу, в строках которой находятся элементы (точки в многомерном пространстве), а в колонках — соответствующие координаты этих точек.


_>Особенность состоит в том, что нужна возможность добавлять точки,

_>и в то же время работать с целыми колонками (имеется ввиду не тип данных, а вся колонка). Чтобы можно было добавить новую координату(и не одну), которая вычисляется из предыдущих по указанному правилу (например, линейная комбинация- x1+0.5*x2+0.2*x4).

_>Как такое можно в достаточной мере оптимально (по скорости) организовать?


_>Заранее спасибо,

_>Сергей.

IMHO, для колонок (осбенно для зависимых!) можно использовать proxy-объекты, а не хранить зависимые колонки внутри матрицы.
На эту тему очень толково написано в книге "Шаблоны С++", не помню кто автор, появилась совсем недавно.

Примерно в таком духе:

template <class TElement, template <class> class TStorage = TStorageInMemory> class CVector
{
TStorage<TElement> m_Data;
};


Написать несколько классов-стратегий TStorage:

1. Хранить элементы
2. Брать столбец матрицы

template <class TElement, class TMatrix> class CStorageMatrixColumn
{
UINT m_nColumn;
TMatrix& Matrix;
TElement& operator[](UINT n)
{
return Matrix[n][m_nColumn];
}
const TElement operator[](UINT n) const
{
return Matrix[n][m_nColumn];
}
};


3. TStorage, умноженный на константу

template <class TElement, class TStorage> class CStorageMultByConst
{
TElement m_Factor;
const TStorage& m_Storage;
const TElement operator[](UINT n) const
{
return m_Storage[n]*m_Factor;
}
};


4. Сумма TStorage, скалярное произведение и т.д.

И соответствующим образом перегрузить арифметические операторы, присваивание и т.д. Тогда без дополнительных затрат на создание промежуточных массивов можно будет писать так:
CMatrix<double> M;
CVector<double> V = M.Col(1) + M.Col(2)*0.5 + M.Col(4)*0.2;
Re[3]: двумерная динамическая матрица
От: Кодт Россия  
Дата: 01.12.03 08:59
Оценка:
Здравствуйте, Andy Panda, Вы писали:

AP>Но — возникает проблема. От матрицы могут потребоваться специфические операции, которые могут быть удобны для одного случая хранения матрицы, и не так удобны для другого.

AP>Как удобнее может быть объявлять подобные операции (как описанные выше — доступ к колонке или строке)?

Операции имеют вид
some_matrix unop(const IMatrix& a);
some_matrix binop(const IMatrix& a, const IMatrix& b);

где some_matrix — наиболее удобное для данной операции представление.

Можно определить семейство операций клонирования
template<class some_matrix>
some_matrix clone(const IMatrix& src, some_matrix*=NULL)
{
  some_matrix dst (src.xsize(), src.ysize());
  for(int x=0;x<src.xsize();++x)
    for(int y=0;y<src.ysize();++y)
      dst.at(x,y) = src.at(x,y);
  return dst;
}

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

Также может оказаться полезным адаптер
class refmatrix
{
  boost::shared_ptr<IMatrix> m_;
public:
  // IMatrix
  const int xsize() const { return m_->xsize(); }
  const int ysize() const { return m_->ysize(); }
  double at(int x, int y) const { return m_->at(x,y); }
  double& at(int x, int y) { return m_->at(x,y); }

  // construction
public:
  refmatrix(int x, int y) : m_(new default_matrix(x,y)) {}
  refmatrix(const IMatrix& m) : m_(new default_matrix(m.xsize(), m.ysize())) { *m_ = m; }
  // copy ctor is default
private:
  refmatrix(IMatrix* pm) : m_(pm) {}
public:
  template<class matrix_type>
  static refmatrix make(int x, int y, matrix_type*=NULL) { return refmatrix(new matrix_type(x,y)); }
  template<>
  static refmatrix make<refmatrix> make(int x, int y, refmatrix*=NULL) { return refmatrix(x,y); }

  // assignment
public:
  refmatrix& operator=(const IMatrix& src) { *m_ = m; }
  // copy assign is default
};

(это эскиз! не гарантирую компилябельность... )
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.