I am trying to use the Sundials ODE solver libraries in order to approximate the dynamics of an extension to the multi species Lotka-Volterra competition equations. E.g. in the case of two species
dx1/dt = r1 * x1 * (1 - (x1 + a12 * x2))
dx2/dt = r2 * x2 * (1 - (x2 + a21 * x1))
or...
dx/dt = r * x * (1 - A * x)
(where K = a11 = a22 = 1)
From what I understand the Sundials ODE solver expects an object of class ODE_vector, the elements of which represent the various state variables of the system, in this case x1 and x2 and I have no problem getting the solver to approximate the trajectories of the two species' populations if I program each parameter (r1, r2, a12, a21) as unique objects as in the following code:
int community::dynamics(ODE_vector const & state, ODE_vector & time_derivative) {
double r1 = 0.5;
double r2 = 0.2;
double a12 = 0.2;
double a21 = 0.2;
time_derivative[0] = r1 * state[0] * (1 - (state[0] + a12 * state[1]));
time_derivative[1] = r2 * state[1] * (1 - (state[1] + a21 * state[0]));
return 0;
};
... where time_derivative and state are members of the Sundials class ODE.
Can anyone show me how to adapt the code to get the system of ODEs into matrix form, i.e. so that r1, r2, a12 and a21 are in the form r and A? I've been told to convert from ODE_vector to armadillo vector/matrix objects using "Advanced constructors" (e.g. 1) but it's one thing to know that and another to successfully implement it!!
Thanks!
Where you thinking of something like this? I implemented that naively in 30 min. There is a lot of optimisation, but it will never be as performant as your stripped down code. Even if you used Armadillo, Blitz++ etc.
#include <algorithm>
#include <iostream>
#include <vector>
template<class T> class Matrix {
public:
Matrix() {}
Matrix(size_t m, size_t n) : m_(m), n_(n) { v_.resize(m*n); }
Matrix& operator*= (const Matrix& other) {
if (other.m_ != n_) {
throw std::length_error("dimesions don't match");
}
Matrix<T> nv(m_,other.n_);
for (size_t j = 0; j < other.n_; ++j) {
for (size_t i = 0; i < m_; ++i) {
for (size_t k = 0; k < n_; ++k)
nv(i,j) += operator()(i,k) * other(k,j);
}
}
*this = nv;
return *this;
}
Matrix operator* (const Matrix& other) const {
Matrix ret = *this;
return ret *= other;
}
Matrix& operator+= (const Matrix& other) {
if (other.m_ != m_ || other.n_ != n_) {
throw std::length_error("dimesions don't match");
}
std::transform(v_.begin(), v_.end(), other.v_.begin(), v_.begin(), std::plus<T>());
return *this;
}
Matrix operator+ (const Matrix& other) const {
Matrix ret = *this;
return ret += other;
}
Matrix operator- () const {
Matrix<T> res (m_,n_);
std::transform (v_.begin(), v_.end(), res.v_.begin(), std::negate<T>());
return res;
}
Matrix& operator-= (const Matrix& other) {
return *this += -other;
}
Matrix operator- (const Matrix& other) const {
Matrix ret = *this;
return ret -= other;
}
Matrix operator->* (const Matrix& other) const {
if (other.m_ != m_ || other.n_ != n_) {
throw std::length_error("dimesions don't match");
}
Matrix res = *this;
std::transform(res.v_.begin(), res.v_.end(), other.v_.begin(),
res.v_.begin(), std::multiplies<T>());
return res;
}
Matrix operator=(std::vector<std::initializer_list<T>> const& other) {
n_ = other.size();
if (n_ == 0) {
throw std::bad_alloc();
}
m_ = other.front().size();
if (m_ == 0) {
throw std::bad_alloc();
}
for (auto const& i : other) {
if (i.size() != m_) {
throw std::bad_alloc();
}
}
v_.resize(m_*n_);
size_t j = 0;
for (const auto& i : other) {
std::copy(i.begin(), i.end(), v_.begin()+j);
j+=m_;
}
return *this;
}
T& operator() (size_t m, size_t n) {
return v_[n*m_+m];
}
const T& operator() (size_t m, size_t n) const {
return v_[n*m_+m];
}
size_t m() const {return m_;}
size_t n() const {return n_;}
private:
size_t m_, n_;
std::vector<T> v_;
};
template<class T> inline std::ostream&
operator<< (std::ostream& os, const Matrix<T>& v) {
size_t i,j;
for (i = 0; i < v.m(); ++i) {
for (j = 0; j < v.n(); ++j) {
os << v(i,j);
os << " ";
}
if (i<v.m()-1)
os << std::endl;
}
return os;
}
int main() {
Matrix<double> A, r, x, one, dxdt;
A = {{1,.2},
{.2,1}};
r = {{0.5,0.2}};
x = {{0.1,-0.1}};
one = {{1,1}};
dxdt = (r ->* x ->* (one - A * r));
std::cout << dxdt << std::endl;
return 0;
}
Related
This weekend I followed the wiki to implement the basic big integer multiplication. I use the Toom-3 algorithm to implement. But the time spends unexpectedly at the beginning is slower than long multiplication(grade-school multiplication) and gone forever. I hope the program can over the grade-school multiplication within 500 digits, How should I do, please?
I try to optimize, I reserve the vector capacity and remove the supernumerary code. But is not very effective.
And should I use the vector<long long> to be my base digits?
The whole source code in Github:
typedef long long BigIntBase;
typedef vector<BigIntBase> BigIntDigits;
// ceil(numeric_limits<BigIntBase>::digits10 / 2.0) - 1;
static const int digit_base_len = 9;
// b
static const BigIntBase digit_base = 1000000000;
class BigInt {
public:
BigInt(int digits_capacity = 0, bool nega = false) {
negative = nega;
digits.reserve(digits_capacity);
}
BigInt(BigIntDigits _digits, bool nega = false) {
negative = nega;
digits = _digits;
}
BigInt(const span<const BigIntBase> &range, bool nega = false) {
negative = nega;
digits = BigIntDigits(range.begin(), range.end());
}
BigInt operator+(const BigInt &rhs) {
if ((*this).negative == rhs.negative)
return BigInt(plus((*this).digits, rhs.digits), (*this).negative);
if (greater((*this).digits, rhs.digits))
return BigInt(minus((*this).digits, rhs.digits), (*this).negative);
return BigInt(minus(rhs.digits, (*this).digits), rhs.negative);
}
BigInt operator-(const BigInt &rhs) { return *this + BigInt(rhs.digits, !rhs.negative); }
BigInt operator*(const BigInt &rhs) {
if ((*this).digits.empty() || rhs.digits.empty()) {
return BigInt();
} else if ((*this).digits.size() == 1 && rhs.digits.size() == 1) {
BigIntBase val = (*this).digits[0] * rhs.digits[0];
return BigInt(val < digit_base ? BigIntDigits{val} : BigIntDigits{val % digit_base, val / digit_base}, (*this).negative ^ rhs.negative);
} else if ((*this).digits.size() == 1)
return BigInt(multiply(rhs, (*this).digits[0]).digits, (*this).negative ^ rhs.negative);
else if (rhs.digits.size() == 1)
return BigInt(multiply((*this), rhs.digits[0]).digits, (*this).negative ^ rhs.negative);
return BigInt(toom3(span((*this).digits), span(rhs.digits)), (*this).negative ^ rhs.negative);
}
string to_string() {
if (this->digits.empty())
return "0";
stringstream ss;
if (this->negative)
ss << "-";
ss << std::to_string(this->digits.back());
for (auto it = this->digits.rbegin() + 1; it != this->digits.rend(); ++it)
ss << setw(digit_base_len) << setfill('0') << std::to_string(*it);
return ss.str();
}
BigInt from_string(string s) {
digits.clear();
negative = s[0] == '-';
for (int pos = max(0, (int)s.size() - digit_base_len); pos >= 0; pos -= digit_base_len)
digits.push_back(stoll(s.substr(pos, digit_base_len)));
if (s.size() % digit_base_len)
digits.push_back(stoll(s.substr(0, s.size() % digit_base_len)));
return *this;
}
private:
bool negative;
BigIntDigits digits;
const span<const BigIntBase> toom3_slice_num(const span<const BigIntBase> &num, const int &n, const int &i) {
int begin = n * i;
if (begin < num.size()) {
const span<const BigIntBase> result = num.subspan(begin, min((int)num.size() - begin, i));
return result;
}
return span<const BigIntBase>();
}
BigIntDigits toom3(const span<const BigIntBase> &num1, const span<const BigIntBase> &num2) {
int i = ceil(max(num1.size() / 3.0, num2.size() / 3.0));
const span<const BigIntBase> m0 = toom3_slice_num(num1, 0, i);
const span<const BigIntBase> m1 = toom3_slice_num(num1, 1, i);
const span<const BigIntBase> m2 = toom3_slice_num(num1, 2, i);
const span<const BigIntBase> n0 = toom3_slice_num(num2, 0, i);
const span<const BigIntBase> n1 = toom3_slice_num(num2, 1, i);
const span<const BigIntBase> n2 = toom3_slice_num(num2, 2, i);
BigInt pt0 = plus(m0, m2);
BigInt pp0 = m0;
BigInt pp1 = plus(pt0.digits, m1);
BigInt pn1 = pt0 - m1;
BigInt pn2 = multiply(pn1 + m2, 2) - m0;
BigInt pin = m2;
BigInt qt0 = plus(n0, n2);
BigInt qp0 = n0;
BigInt qp1 = plus(qt0.digits, n1);
BigInt qn1 = qt0 - n1;
BigInt qn2 = multiply(qn1 + n2, 2) - n0;
BigInt qin = n2;
BigInt rp0 = pp0 * qp0;
BigInt rp1 = pp1 * qp1;
BigInt rn1 = pn1 * qn1;
BigInt rn2 = pn2 * qn2;
BigInt rin = pin * qin;
BigInt r0 = rp0;
BigInt r4 = rin;
BigInt r3 = divide(rn2 - rp1, 3);
BigInt r1 = divide(rp1 - rn1, 2);
BigInt r2 = rn1 - rp0;
r3 = divide(r2 - r3, 2) + multiply(rin, 2);
r2 = r2 + r1 - r4;
r1 = r1 - r3;
BigIntDigits result = r0.digits;
if (!r1.digits.empty()) {
shift_left(r1.digits, i);
result = plus(result, r1.digits);
}
if (!r2.digits.empty()) {
shift_left(r2.digits, i << 1);
result = plus(result, r2.digits);
}
if (!r3.digits.empty()) {
shift_left(r3.digits, i * 3);
result = plus(result, r3.digits);
}
if (!r4.digits.empty()) {
shift_left(r4.digits, i << 2);
result = plus(result, r4.digits);
}
return result;
}
BigIntDigits plus(const span<const BigIntBase> &lhs, const span<const BigIntBase> &rhs) {
if (lhs.empty())
return BigIntDigits(rhs.begin(), rhs.end());
if (rhs.empty())
return BigIntDigits(lhs.begin(), lhs.end());
int max_length = max(lhs.size(), rhs.size());
BigIntDigits result;
result.reserve(max_length + 1);
for (int w = 0; w < max_length; ++w)
result.push_back((lhs.size() > w ? lhs[w] : 0) + (rhs.size() > w ? rhs[w] : 0));
for (int w = 0; w < result.size() - 1; ++w) {
result[w + 1] += result[w] / digit_base;
result[w] %= digit_base;
}
if (result.back() >= digit_base) {
result.push_back(result.back() / digit_base);
result[result.size() - 2] %= digit_base;
}
return result;
}
BigIntDigits minus(const span<const BigIntBase> &lhs, const span<const BigIntBase> &rhs) {
if (lhs.empty())
return BigIntDigits(rhs.begin(), rhs.end());
if (rhs.empty())
return BigIntDigits(lhs.begin(), lhs.end());
BigIntDigits result;
result.reserve(lhs.size() + 1);
for (int w = 0; w < lhs.size(); ++w)
result.push_back((lhs.size() > w ? lhs[w] : 0) - (rhs.size() > w ? rhs[w] : 0));
for (int w = 0; w < result.size() - 1; ++w)
if (result[w] < 0) {
result[w + 1] -= 1;
result[w] += digit_base;
}
while (!result.empty() && !result.back())
result.pop_back();
return result;
}
void shift_left(BigIntDigits &lhs, const int n) {
if (!lhs.empty()) {
BigIntDigits zeros(n, 0);
lhs.insert(lhs.begin(), zeros.begin(), zeros.end());
}
}
BigInt divide(const BigInt &lhs, const int divisor) {
BigIntDigits reminder(lhs.digits);
BigInt result(lhs.digits.capacity(), lhs.negative);
for (int w = reminder.size() - 1; w >= 0; --w) {
result.digits.insert(result.digits.begin(), reminder[w] / divisor);
reminder[w - 1] += (reminder[w] % divisor) * digit_base;
}
while (!result.digits.empty() && !result.digits.back())
result.digits.pop_back();
return result;
}
BigInt multiply(const BigInt &lhs, const int multiplier) {
BigInt result(lhs.digits, lhs.negative);
for (int w = 0; w < result.digits.size(); ++w)
result.digits[w] *= multiplier;
for (int w = 0; w < result.digits.size(); ++w)
if (result.digits[w] >= digit_base) {
if (w + 1 == result.digits.size())
result.digits.push_back(result.digits[w] / digit_base);
else
result.digits[w + 1] += result.digits[w] / digit_base;
result.digits[w] %= digit_base;
}
return result;
}
bool greater(const BigIntDigits &lhs, const BigIntDigits &rhs) {
if (lhs.size() == rhs.size()) {
int w = lhs.size() - 1;
while (w >= 0 && lhs[w] == rhs[w])
--w;
return w >= 0 && lhs[w] > rhs[w];
} else
return lhs.size() > rhs.size();
}
};
Digits
Grade-school
Toom-3
10
4588
10003
50
24147
109084
100
52165
286535
150
92405
476275
200
172156
1076570
250
219599
1135946
300
320939
1530747
350
415655
1689745
400
498172
1937327
450
614467
2629886
500
863116
3184277
The problem is that you do a million allocations in among others toom3_slice_num, here you could use a std::span (or a std::pair of iterator to the actual part) as the number you give is a const. toom3 is also allocator hell.
The multiply might allocate 1 more time. Count the bits needed or just add 1 to the size.
And the vectors should be pmr (with appropriate allocator) for nearly lock free allocations.
All this is wasted if not compiled with -O2 or -O3.
I'm trying to binary read png's.
Reading images that only use the None, sub, up or average filter work fine.
I used the documentation as described here: http://www.libpng.org/pub/png/spec/1.2/PNG-Filters.html
Original picure:
* Pixel struct *
struct Pixel
{
unsigned char r,g,b;
int all() const { return r + g + b; }
Pixel& operator+=(const Pixel& rhs)
{
this->r = (this->r + rhs.r) % 256;
this->g = (this->g + rhs.g) % 256;
this->b = (this->b + rhs.b) % 256;
return *this;
}
Pixel& operator-=(const Pixel& rhs)
{
this->r = (this->r - rhs.r) % 256;
this->g = (this->g - rhs.g) % 256;
this->b = (this->b - rhs.b) % 256;
return *this;
}
bool operator<=(const Pixel& rhs)
{
return ((this->r <= rhs.r) && (this->g <= rhs.g) && (this->b <= rhs.b));
}
friend Pixel& operator+(Pixel lhs, const Pixel& rhs)
{
lhs += rhs;
return lhs;
}
friend Pixel& operator-(Pixel lhs, const Pixel& rhs)
{
lhs -= rhs;
return lhs;
}
};
* First possibility *
void INC_Image::Paeth(std::vector<Pixel>& thesePixels, std::vector<Pixel>& priorPixels) const
{
for (int i{ 1 }; i < thesePixels.size(); i++)
{
Pixel tempPixel = thesePixels[i];
tempPixel.r = (thesePixels[i].r + PaethPredictor(thesePixels[i - 1].r, priorPixels[i].r, priorPixels[i - 1].r)) % 256;
tempPixel.g = (thesePixels[i].g + PaethPredictor(thesePixels[i - 1].g, priorPixels[i].g, priorPixels[i - 1].g)) % 256;
tempPixel.b = (thesePixels[i].b + PaethPredictor(thesePixels[i - 1].b, priorPixels[i].b, priorPixels[i - 1].b)) % 256;
thesePixels[i] = tempPixel;
}
}
unsigned char INC_Image::PaethPredictor(const unsigned char& previous, const unsigned char& prior, const unsigned char& priorPrevious) const
{
auto p = (previous + prior - priorPrevious) ;
auto pa = abs(p - previous) ;
auto pb = abs(p - prior) ;
auto pc = abs(p - priorPrevious) ;
if (pa <= pb && pa <= pc) return previous ;
else if (pb <= pc) return prior;
else return (priorPrevious );
}
With thesePixels == vector of 1 image line.
With priorPixels == vector of previous image line.
Result:
* Second possibility *
void INC_Image::Paeth(std::vector<Pixel>& thesePixels, std::vector<Pixel>& priorPixels) const
{
for (int i{ 1 }; i < thesePixels.size(); i++)
{
thesePixels[i] += PaethPredictor(thesePixels[i - 1], priorPixels[i], priorPixels[i - 1]);
}
}
Pixel INC_Image::PaethPredictor(const Pixel& previous, const Pixel& prior, const Pixel& priorPrevious) const
{
auto p = previous.all() + prior.all() - priorPrevious.all();
auto pa = abs(p - previous.all());
auto pb = abs(p - prior.all());
auto pc = abs(p - priorPrevious.all());
if (pa <= pb && pa <= pc) return previous;
else if (pb <= pc) return prior;
else return priorPrevious;
}
With thesePixels == vector of 1 image line.
With priorPixels == vector of previous image line.
Result:
I don't know what's wrong with the calculation.
I have a Matrix3 class which has an overloaded * operator so i should be able to go:
Matrix3 m1, m2, m3
m2.setRotateX(3.98f); //values are not important just setting a value.
m3.setRotateZ(9.62f);
m1 = m2 * m3
Expected result:
m1 is assigned the result of m2 * m3 calculation. Instead it appears to be still assigned whatever was in memory when it was created.
I have looked at it in the debugger and the result code at the end of the operator * method is assigned to the correct values but it never is assigned for some reason.
I am running Visual Studio 2017 (I tried updating to latest version) and currently running with the Debug x86 profile.
I should also point out I am not using a pre-made maths library because this is part of an assignment.
Here is the full code for the class:
matrix3.h
#pragma once
#include "vector3.h"
class Matrix3
{
public:
union
{
struct
{
Vector3 xAxis;
Vector3 yAxis;
union {
Vector3 zAxis;
Vector3 translation;
};
};
Vector3 axis[3];
float data[3][3];
};
static const Matrix3 identity;
Matrix3(Vector3 x, Vector3 y, Vector3 z) : xAxis{ x }, yAxis{ y }, zAxis{ z } { }
Matrix3(float f1, float f2, float f3, float f4, float f5, float f6, float f7, float f8, float f9) : data{ f1, f2, f3, f4, f5, f6, f7, f8, f9 } {}
Matrix3() : Matrix3{ identity } {}
Matrix3(const Matrix3 &other)
{
for (int i = 0; i > 3; i++)
axis[i] = other.axis[i];
}
Matrix3& operator= (const Matrix3& other);
Vector3& operator[] (int index);
const Vector3& operator[] (int index) const;
Matrix3 operator * (const Matrix3& other) const;
Vector3 operator * (const Vector3& v) const;
Matrix3 operator + (const Matrix3& other) const;
Matrix3 operator - (const Matrix3& other) const;
operator float*() { return reinterpret_cast<float*>(data); }
Matrix3 transpose() const;
void setScaled(float x, float y, float z);
void setScaled(const Vector3& v);
void scale(float x, float y, float z);
void scale(const Vector3 v);
void setRotateX(float radians);
void setRotateY(float radians);
void setRotateZ(float radians);
void rotateX(float radians);
void rotateY(float radians);
void rotateZ(float radians);
void setEuler(float pitch, float yaw, float roll);
operator std::string() const;
friend std::ostream& operator<< (std::ostream& os, const Matrix3& matrix);
};
matrix3.cpp
#include "Matrix3.h"
const Matrix3 Matrix3::identity = Matrix3({ 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 });
static const int MATRIX_DIMS = 3;
Vector3& Matrix3::operator[] (int index)
{
return axis[index];
}
const Vector3& Matrix3::operator[] (int index) const
{
return axis[index];
}
Matrix3& Matrix3::operator=(const Matrix3& other)
{
xAxis = other.xAxis;
yAxis = other.yAxis;
zAxis = other.zAxis;
return *this;
}
Matrix3 Matrix3::operator * (const Matrix3& other) const
{
Matrix3 result;
for (int r = 0; r < 3; r++)
for (int c = 0; c < 3; c++)
result.data[c][r] = data[0][r] * other.data[c][0] +
data[1][r] * other.data[c][1] +
data[2][r] * other.data[c][2];
return result;
}
Vector3 Matrix3::operator * (const Vector3& v) const
{
Vector3 result;
for (int r = 0; r < 3; ++r)
{
result[r] = 0;
for (int i = 0; i < MATRIX_DIMS; ++i)
result[r] += data[i][r] * v[i];
}
return result;
}
Matrix3 Matrix3::operator+(const Matrix3& other) const
{
Matrix3 result;
for (int x = 0; x < MATRIX_DIMS; x++)
for (int y = 0; y < MATRIX_DIMS; y++)
result[x][y] = data[x][y] + other[x][y];
return result;
}
Matrix3 Matrix3::operator-(const Matrix3& other) const
{
Matrix3 result;
for (int x = 0; x < MATRIX_DIMS; x++)
for (int y = 0; y < MATRIX_DIMS; y++)
result[x][y] = data[x][y] - other[x][y];
return result;
}
Matrix3 Matrix3::transpose() const
{
Matrix3 result;
for (int r = 0; r < MATRIX_DIMS; ++r)
for (int c = 0; c < MATRIX_DIMS; ++c)
result.data[r][c] = data[c][r];
return result;
}
void Matrix3::setScaled(const Vector3& v)
{
// set scale of each axis
xAxis = { v.x, 0, 0 };
yAxis = { 0, v.y, 0 };
zAxis = { 0, 0, v.z };
}
void Matrix3::setScaled(float x, float y, float z)
{
// set scale of each axis
xAxis = { x, 0, 0 };
yAxis = { 0, y, 0 };
zAxis = { 0, 0, z };
}
void Matrix3::scale(const Vector3 v)
{
Matrix3 m;
m.setScaled(v.x, v.y, v.z);
*this = *this * m;
}
void Matrix3::scale(float x, float y, float z)
{
Matrix3 m;
m.setScaled(x, y, z);
*this = *this * m;
}
void Matrix3::rotateX(float radians)
{
Matrix3 m;
m.setRotateX(radians);
*this = *this * m;
}
void Matrix3::rotateY(float radians)
{
Matrix3 m;
m.setRotateY(radians);
*this = *this * m;
}
void Matrix3::rotateZ(float radians)
{
Matrix3 m;
m.setRotateZ(radians);
*this = *this * m;
}
void Matrix3::setRotateX(float radians)
{
xAxis = { 1, 0, 0 };
yAxis = { 0, cosf(radians), sinf(radians) };
zAxis = { 0, -sinf(radians), cosf(radians) };
}
void Matrix3::setRotateY(float radians)
{
xAxis = { cosf(radians), 0, -sinf(radians) };
yAxis = { 0, 1, 0 };
zAxis = { sinf(radians), 0, cosf(radians) };
}
void Matrix3::setRotateZ(float radians)
{
xAxis = { cosf(radians), sinf(radians), 0 };
yAxis = { -sinf(radians), cosf(radians), 0 };
zAxis = { 0, 0, 1 };
}
void Matrix3::setEuler(float pitch, float yaw, float roll)
{
Matrix3 x, y, z;
x.setRotateX(pitch);
y.setRotateY(yaw);
z.setRotateZ(roll);
*this = z * y * x;
}
Matrix3::operator std::string() const
{
std::string result = "";
for (int r = 0; r < MATRIX_DIMS; ++r)
{
result += "{";
for (int c = 0; c < MATRIX_DIMS; ++c)
{
result += std::to_string(data[r][c]);
if (r != MATRIX_DIMS - 1 || c != MATRIX_DIMS - 1)
result += ",";
}
result += "}";
}
return result;
}
std::ostream& operator<< (std::ostream& os, const Matrix3& matrix)
{
os << static_cast<std::string>(matrix);
return os;
}
The supplied code exhibits undefined behavior. In c++ only up to one member of a union is active at any time. Only a union's active member can be read from. Assigning to a union member makes it active and makes all other members inactive. For example, if you assign a value to identity.data it's undefined behavior to try to read from identity.axis until you assign a value to identity.axis, after which you can no longer read from identity.data. This is different from how it works in c.
By calling void Matrix3::setRotateX(float radians) you assign values to the union's xAxis, yAxis and zAxis members, making the struct component of the union active. Then, when you multiply m2 with m3 you call Matrix3 Matrix3::operator * (const Matrix3& other) const which reads from the union's data member which is not active, which leads to undefined behavior.
The easiest solution would likely to be to dispose of the union all together and use only one of the representations.
I am a Java developer, but now I need a C++ library and I am not so experienced in this language. In particular, I always get confused about pointers, references and memory allocation. This I think is the reason why I am getting an error at a matrix class I am developing.
The main code:
#include "stdafx.h"
#include "matrix.cpp"
void matrixtest();
int main()
{
matrixtest();
system("pause");
return 0;
}
void matrixtest()
{
// let's try 3x3 matrices
static const int arr1[] = {1, 2, 1, -1, 1, 2, 2, 3, -4};
static const int arr2[] = {0, 2, 2, 1, -1, 0, 3, 2, -2};
vector<int> values1(arr1, arr1 + sizeof(arr1) / sizeof(arr1[0]));
vector<int> values2(arr2, arr2 + sizeof(arr2) / sizeof(arr2[0]));
matrix A(values1, 3);
matrix B(values2, 3);
matrix sum = A + B;
sum.show();
matrix diff = A - B;
diff.show();
matrix prod = A * B;
prod.show();
}
matrix.cpp interesting code:
matrix::matrix(vector<int> v, int r) : values(v), rows(r) {
values = v;
rows = r;
}
// [...]
matrix& matrix::operator += (const matrix& rhs) {
matrix result = (*this) + rhs;
(*this) = result;
return *this;
}
matrix matrix::operator + (const matrix& rhs) {
if (rows != rhs.rows || values.size() != rhs.values.size()) {
throw std::length_error("Matrices shapes mismatch");
}
matrix result(values, rows);
for (auto& i : values) {
result.values[i] = this->values[i] + rhs.values[i];
}
return result;
}
// [...]
void matrix::show() {
string delimiter = "";
for (auto& i : values) {
delimiter = "";
for (auto j = 0; j < values.size()/rows; j++) {
cout << delimiter << values[i * values.size()/rows + j]; // this is the line giving the error
delimiter = ",";
}
std::cout << std::endl;
}
}
full matrix.hpp file:
#ifndef matrix_hpp
#define matrix_hpp
class matrix {
private:
std::vector<int> values; // size is found by values.size()
int rows; // columns is values.size()/rows
public:
matrix(vector<int>, int); // base ctor.
matrix(const matrix& rhs); // copy ctor.
matrix& operator=(const matrix& rhs); // assign. ctor.
~matrix(); // dtor.
int& operator () (int row, int column);
const int& operator () (int row, int column) const;
matrix operator + (int scalar) const;
matrix operator - (int scalar) const;
matrix operator * (int scalar) const;
matrix& operator += (int scalar);
matrix& operator -= (int scalar);
matrix& operator *= (int scalar);
matrix operator + (const matrix&);
matrix operator - (const matrix&);
matrix operator * (const matrix&);
matrix& operator += (const matrix&);
matrix& operator *= (const matrix&);
// should be private ??
void reshape(int newRows, int newColumns);
void show(); //used for dev. only
void range(int start, int defaultStep = 1);
void fill(int value);
void randint(int lowerBound, int upperBound);
};
#endif /* CMatrix_hpp */
This class is based on an example given at matrix example.
The error says '0xC0000005: Access violation reading location 0x5820A694.'
So I am guessing the memory allocation is wrong and/or there is an out of bounds array and/or I am messing with the '&' operators.
Edit: I get the following trace:
this 0x00dffe24 {values={ size=9 } rows=3 } matrix *
So, the matrix does exist, but for some reason I am getting the error.
The for loop that you are using, before the one causing the error
for (auto& i : values)
is a range-based for loop.
With this you will get the values present in vector(values).
But based on the logic you have written what you want here is an index that represents the row you are working with.
You should go for the normal for loop.
for(int i =0; i<rows; ++i)
I am trying to use a symMatrixBlock representation for the cloth simulation.
The following class stores a symmetric matrix nxn who's each element is a 3x3 matrix (represented as Mat33 class)
class SymMatrixBlocks
{
public:
int size;
int *rowstart;
std::vector<int> col_lookup;
std::vector<Mat33 *> matBlock;
bool bAllZero;
public:
SymMatrixBlocks(int size);
SymMatrixBlocks(const SymMatrixBlocks &src);
~SymMatrixBlocks();
void Zero(void);
SymMatrixBlocks& operator=(const SymMatrixBlocks &src);
SymMatrixBlocks& operator+=(const SymMatrixBlocks &src);
SymMatrixBlocks& operator-=(const SymMatrixBlocks &src);
SymMatrixBlocks& operator*=(double con);
Mat33* getMatBlock(int row, int col);
void SetDiag(DiagonalMatrix &src, DiagonalMatrix &ret);
void print();
Mat33* operator() (int row, int col);
};
inline const SymMatrixBlocks operator +(const SymMatrixBlocks &lhs, const SymMatrixBlocks &rhs)
{
return SymMatrixBlocks(lhs) += rhs;
}
inline const SymMatrixBlocks operator -(const SymMatrixBlocks &lhs, const SymMatrixBlocks &rhs)
{
return SymMatrixBlocks(lhs) -= rhs;
}
inline const SymMatrixBlocks operator *(const SymMatrixBlocks &lhs, double rhs)
{
return SymMatrixBlocks(lhs) *= rhs;
}
inline const SymMatrixBlocks operator *(double lhs, const SymMatrixBlocks &rhs)
{
return SymMatrixBlocks(rhs) *= lhs;
}
}
SymMatrixBlocks& SymMatrixBlocks::operator+=(const SymMatrixBlocks &src)
{
if (size != src.size)
return *this;
if (src.bAllZero)
return *this;
int i, j, start, length;
for (i = 0; i<src.size; i++)
{
start = src.rowstart[i];
length = src.rowstart[i + 1] - start;
for (j = 0; j<length; j++)
(*((*this)(i, src.col_lookup[start + j]))) += (*(src.matBlock[start + j]));
}
return *this;
}
Mat33* SymMatrixBlocks::operator() (int row, int col)
{
int i, start, l, length;
bAllZero = false;
if (row > col)
{
start = row;
row = col;
col = start;
}
start = rowstart[row];
length = rowstart[row + 1] - start;
for (l = 0; l<length; l++)
if (col_lookup[start + l] == col)
break;
if ((length != 0) && (l != length))
{
return matBlock[start + l];
}
else
{
for (l = 0; l<length; l++)
if (col_lookup[start + l] >= col)
break;
col_lookup.insert(col_lookup.begin() + start + l, col);
Mat33 *tempmat = new Mat33();
matBlock.insert(matBlock.begin() + start + l, tempmat);
for (i = row + 1; i <= size; i++)
rowstart[i]++;
return matBlock[start + l];
}
}
when I run the following line it gives memory leakage. Can anyone spot it out?
*tm1 = *df_dx * h; // all these are object of the SymMtrixBlocks class.