I am trying to rotate a vector of Vectors of chars.
I made a 2d vector matrix setup. right now the matrix takes input from a file, I use vector.push_back(c) to add the characters to the vvc;
An example of the vvc array would be something like this
aaaaa
azzza
azaza
azzza
azaaa
azaaa
azaaa
aaaaa
I have the vvc setup, But I am trying to rotate it 90 degrees. I rotated it 90 degrees counter clockwise but I need to rotate it 90 degrees clockwise.
as of right now my code does this
90 counter clock
aaaaaaaa
azzzzzza
azazaaaa
azzzaaaa
aaaaaaaa
and it does it through this loop;
cout <<"\n90 counter clock"<<endl;
for (size_t colNo = 0; colNo < kvsize2; colNo++)
{
for (const auto &row : twovector)
{
char colVal = row.at(colNo);
cout << colVal;
}
cout << endl;
}
I am just learning about vectors, and the range for. Trying to do a decrement loop almost works, but keeps throwing me into a segfault.
"Solved"
I was using
twovector.push_back(temp);
using
twovector.insert(twovector.begin(),temp);
gives me
90 counter clock
aaaaaaaa
azzzzzza
aaaazaza
aaaazzza
aaaaaaaa
Tackling a specific part of the question :
If anyone has any tips or suggestions on how to rotate a M*N 2d vector array
C++ is good at segregating algorithms from data.
Kindly note that the answer is a bit lengthy and has been written with the objective of a tutorial.
Lets begin !!
We want 3 features from our rotate_2d_matrix_clockwise algorithm :
It should work with all datatypes, i.e. int, char, double or any user defined type.
It should work with different types of containers, such as std::array and std::vector
It should be chain-able, i.e. user should be able to call rotate_2d_matrix_clockwise on the result returned by rotate_2d_matrix_clockwise, to achieve 2 times rotation.
Once we are clear with our requirements, we can draft some use-cases for our algorithm.
std::vector<std::vector<char>> data = { {'a', 'b', 'c', 'd'},
{'e', 'f', 'g', 'h'},
{'i', 'j', 'k', 'l'} };
rotate_2d_matrix_clockwise(data); // rotating 2d-matrix of vector<char>
std::array<std::array<int, 4>, 3> data2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
// rotating 2d-matrix of array<int>, twice
rotate_2d_matrix_clockwise(rotate_2d_matrix_clockwise(data2)));
So lets use some templates to create a generic 2d-clockwise-rotate function.
Our rotate_2d_matrix_clockwise will :
take the original_matrix and return a new rotated_matrix.
automatically deduce the dimensions i.e. M x N of the container passed to it.
create the rotated_matrix and pass it to a helper function rotate_2d_matrix_clockwise_impl where the actual work would be done.
So how will the implementation of rotate_2d_matrix_clockwise for std::array look ?
template<typename T, size_t M, size_t N>
auto rotate_2d_matrix_clockwise(std::array<std::array<T, M>, N> const & original_matrix)
-> std::array<std::array<T, N>, M>
{
std::array<std::array<T, N>, M> rotated_matrix;
rotate_2d_matrix_clockwise_impl(original_matrix, rotated_matrix, M, N); // rotate
return rotated_matrix;
}
Neat and precise.
The implementation of rotate_2d_matrix_clockwise for std::vector is a bit messy, though.
template<typename Matrix2D>
auto rotate_2d_matrix_clockwise(Matrix2D const & original_matrix) -> Matrix2D
{
int const M = original_matrix[0].size(); // deduce M and N
int const N = original_matrix.size();
Matrix2D rotated_matrix; // vector has no form, hence we have to resize it for `N x M`
rotated_matrix.resize(M);
for (auto x = 0; x < M; ++x) {
rotated_matrix[x].resize(N);
}
rotate_2d_matrix_clockwise_impl(original_matrix, rotated_matrix, M, N); // rotate
return rotated_matrix;
}
Now lets look at how the actual rotation algorithm rotate_2d_matrix_clockwise_impl would look.
It should be noted, that the algorithm is independent of the container and/or the data contained. It just focuses on rotating.
template<typename OriginalMatrix2D, typename RotatedMatrix2D>
void rotate_2d_matrix_clockwise_impl(OriginalMatrix2D const & original_matrix,
RotatedMatrix2D & rotated_matrix,
int const M,
int const N)
{
for (auto x = 0; x < N; ++x) {
for (auto y = 0; y < M; ++y) {
// Source : https://stackoverflow.com/questions/4780119/2d-euclidean-vector-rotations
rotated_matrix[y][-x -1 +N] = original_matrix[x][y];
}
}
}
Here is a full working example compiled in C++11.
#include <iostream>
#include <vector>
#include <array>
template<typename Matrix2D>
void print_matrix(Matrix2D const & vec)
{
std::cout << "size of matrix is [" << vec[0].size() << " x " << vec.size() << "]\n";
for (auto const & inner_vec : vec) {
for (auto const & item : inner_vec) {
std::cout << item << ", ";
}
std::cout << std::endl;
}
}
template<typename OriginalMatrix2D, typename RotatedMatrix2D>
void rotate_2d_matrix_clockwise_impl(OriginalMatrix2D const & matrix,
RotatedMatrix2D & rotated_matrix,
int const M,
int const N)
{
for (auto x = 0; x < N; ++x) {
for (auto y = 0; y < M; ++y) {
// Source : https://stackoverflow.com/questions/4780119/2d-euclidean-vector-rotations
rotated_matrix[y][-x -1 +N] = matrix[x][y];
}
}
}
template<typename T, size_t M, size_t N>
auto rotate_2d_matrix_clockwise(std::array<std::array<T, M>, N> const & original_matrix)
-> std::array<std::array<T, N>, M>
{
std::array<std::array<T, N>, M> rotated_matrix;
rotate_2d_matrix_clockwise_impl(original_matrix, rotated_matrix, M, N);
return rotated_matrix;
}
template<typename Matrix2D>
auto rotate_2d_matrix_clockwise(Matrix2D const & original_matrix) -> Matrix2D
{
int const M = original_matrix[0].size();
int const N = original_matrix.size();
Matrix2D rotated_matrix;
rotated_matrix.resize(M);
for (auto x = 0; x < M; ++x) {
rotated_matrix[x].resize(N);
}
rotate_2d_matrix_clockwise_impl(original_matrix, rotated_matrix, M, N);
return rotated_matrix;
}
int main()
{
std::array<std::array<int, 4>, 3> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
std::cout << "\nBefore Rotation :\n";
print_matrix(data);
std::cout << "\nAfter 2nd Clockwise Rotation :\n";
print_matrix(rotate_2d_matrix_clockwise(rotate_2d_matrix_clockwise(data)));
std::vector<std::vector<char>> data2 = { {'a', 'b', 'c', 'd'}, {'e', 'f', 'g', 'h'}, {'i', 'j', 'k', 'l'}};
std::cout << "Before Rotation :\n";
print_matrix(data2);
std::cout << "\nAfter Clockwise Rotation :\n";
print_matrix(rotate_2d_matrix_clockwise(data2));
return 0;
}
If I got you right, and all you want is to print the matrix 90 degrees clockwise, try this code:
for (int colNo = 0; colNo < vec[0].size(); colNo++)
{
for (int i = vec.size() - 1; i >= 0; i--)
{
const auto& row = vec[i];
int colVal = row.at(colNo);
cout << colVal;
}
cout << endl;
}
Related
Is there a simple method in C++ that allows to sum up the vectors componing a matrix element by element? I mean, if I have the matrix M[3][4], I want the sum[3] vector with this components:
sum[0]=M[0][0]+M[1][0]+M[2][0]
sum[1]=M[0][1]+M[1][1]+M[2][1]
sum[2]=M[0][2]+M[1][2]+M[2][2]
I find out that exists this method for two vectors, I would like to extend it to many vectors, in particular to the std::vector<type>rows componing the matrix std::vector<vector<type> > M, not knowing a-priori the dimomension of M.
Is there a simple method in C++ that allows to sum up the vectors componing a matrix element by element? I mean, if I have the matrix M[3][4], I want the sum[3] vector with this components:
sum[0]=M[0][0]+M[1][0]+M[2][0]
sum[1]=M[0][1]+M[1][1]+M[2][1]
sum[2]=M[0][2]+M[1][2]+M[2][2]
Unfortunately, there is no simple method in the C++ standard library for adding
a container's elements column-wise.
There is std::accumulate(), but naturally, it would add up the row elements together, not the column elements, but we can fix that by iterating through each column index inside the matrix and adding up the elements one by one:
#include <iostream>
#include <numeric>
#include <cstddef>
#include <vector>
// The below function assumes that all columns of your matrix have the same length
template <typename T>
std::vector<T> m_col_add(std::vector<std::vector<T>> const& mat) {
std::vector<T> res;
const auto column_size = mat[0].size();
for (size_t x = 0; x < column_size; ++x)
res.push_back(std::accumulate(mat.begin(), mat.end(), T{}, [x](T const& a, std::vector<T> const& row) {
return a + row[x];
}));
return res;
}
int main() {
std::vector<std::vector<int>> mat {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
auto res = m_col_add(mat);
for (auto const& elem : res)
std::cout << elem << " ";
}
Output:
15 18 21 24
Alternatively, if you already know the sizes of the rows and columns during compile-time and are using C++17 or above, you can use fold expressions and std::index_sequence<> to add up the elements faster by compile-time expansion:
#include <iostream>
#include <utility>
#include <cstddef>
#include <array>
template <size_t Column, typename T, size_t Rows, size_t Columns, size_t ...Sizes>
T m_col_add_impl2(std::index_sequence<Sizes...>, std::array<std::array<T, Columns>, Rows> const& mat) {
return (mat[Sizes][Column] + ...);
}
template <typename T, size_t Rows, size_t Columns, size_t ...Sizes>
std::array<T, Columns> m_col_add_impl1(std::index_sequence<Sizes...>, std::array<std::array<T, Columns>, Rows> const& mat) {
std::array<T, Columns> sum;
((sum[Sizes] = m_col_add_impl2<Sizes>(std::make_index_sequence<Rows>(), mat)), ...);
return sum;
}
template <typename T, size_t Rows, size_t Columns>
std::array<T, Columns> m_col_add(std::array<std::array<T, Columns>, Rows> const& mat) {
return m_col_add_impl1(std::make_index_sequence<Columns>(), mat);
}
int main() {
std::array mat {
std::array {1, 2, 3, 4},
std::array {5, 6, 7, 8},
std::array {9, 10, 11, 12}
};
auto res = m_col_add(mat);
for (auto const& elem : res)
std::cout << elem << " ";
}
Output:
15 18 21 24
You could define operator+= for vectors which allows you to define a generalized Sum function that receives begin and end operators of a range to sum that works for iterators with any value type that works with the += operator like primitive types or (possibly nested) vectors of types that provide a += operator:
template<typename T>
std::vector<T>& operator+=(std::vector<T>& lhs, std::vector<T> const& rhs)
{
if (lhs.empty())
{
lhs = rhs; // first summand; 0 + x = x
}
else
{
for (size_t i = 0; i < lhs.size(); ++i)
{
lhs[i] += rhs.at(i); // component-wise add
}
}
return lhs;
}
// sum up elements in a given range
template<typename IteratorType>
typename std::iterator_traits<IteratorType>::value_type Sum(IteratorType summandBegin, IteratorType summandEnd)
{
typename std::iterator_traits<IteratorType>::value_type sum {}; // 0 or object created with default constructor depending on the type
while (summandBegin != summandEnd)
{
sum += *summandBegin;
++summandBegin;
}
return sum;
}
// sums the first count elements of a vector
template<typename T>
T PartialSum(std::vector<T> const& vec, size_t count)
{
assert(vec.size() >= count);
return Sum(vec.begin(), vec.begin() + count);
}
// logic for displaying
template<typename T>
std::ostream& operator<<(std::ostream& s, std::vector<T> const& vec)
{
s << '{';
for (auto& val : vec)
{
s << val << ", ";
}
s << '}';
return s;
}
int main(int argc, char *argv[]) {
std::vector<std::vector<std::vector<int>>> matrix { {{1, 2},{ 3, 4},{ 5, 6}},{{7, 8},{ 9, 10},{11, 12}},{{13, 14},{ 15, 16},{ 17, 18}}};
auto partialSum = PartialSum(matrix, 2);
std::cout << matrix << '\n' << partialSum << '\n';
std::cout << "\nSomething extra:\n";
std::vector<std::vector<std::string>> m2 = {{"Hell" , "Wo"} , {"o ", "rld!"}, {"foo", "bar"}};
auto message = PartialSum(m2, 2);
for (auto& msg : message)
{
std::cout << msg;
}
std::cout << '\n';
return 0;
}
I have found on the internet (here and here), that the inheritance doesn't affect the performance of the class. I have become curious about that as I have been writing a matrices module for a render engine, and the speed of this module is very important for me.
After I have written:
Base: general matrix class
Derived from the base: square implementation
Derived from derived: 3-dim and 4-dim implementations of the square matrix
I decided to test them and faced performance issues with instantiation
And so the main questions are:
What's the reason of these performance issues in my case and why may they happen in general?
Should I forget about inheritance in such cases?
This is how these classes look like in general:
template <class t>
class Matrix
{
protected:
union {
struct
{
unsigned int w, h;
};
struct
{
unsigned int n, m;
};
};
/** Changes flow of accessing `v` array members */
bool transposed;
/** Matrix values array */
t* v;
public:
~Matrix() {
delete[] v;
};
Matrix() : v{}, transposed(false) {};
// Copy
Matrix(const Matrix<t>& m) : w(m.w), h(m.h), transposed(m.transposed) {
v = new t[m.w * m.h];
for (unsigned i = 0; i < m.g_length(); i++)
v[i] = m.g_v()[i];
};
// Constructor from array
Matrix(unsigned _w, unsigned _h, t _v[], bool _transposed = false) : w(_w), h(_h), transposed(_transposed) {
v = new t[_w * _h];
for (unsigned i = 0; i < _w * _h; i++)
v[i] = _v[i];
};
/** Gets matrix array */
inline t* g_v() const { return v; }
/** Gets matrix values array size */
inline unsigned g_length() const { return w * h; }
// Other constructors, operators, and methods.
}
template<class t>
class SquareMatrix : public Matrix<t> {
public:
SquareMatrix() : Matrix<t>() {};
SquareMatrix(const Matrix<t>& m) : Matrix<t>(m) {};
SquareMatrix(unsigned _s, t _v[], bool _transpose) : Matrix<t>(_s, _s, _v, _transpose) {};
// Others...
}
template<class t>
class Matrix4 : public SquareMatrix<t> {
public:
Matrix4() : SquareMatrix<t>() {};
Matrix4(const Matrix<t>& m) : SquareMatrix<t>(m) {}
Matrix4(t _v[16], bool _transpose) : SquareMatrix<t>(4, _v, _transpose) {};
// Others...
}
To conduct tests I used this
void test(std::ofstream& f, char delim, std::function<void(void)> callback) {
auto t1 = std::chrono::high_resolution_clock::now();
callback();
auto t2 = std::chrono::high_resolution_clock::now();
f << std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() << delim;
//std::cout << "test took " << std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() << " microseconds\n";
}
Performance problems
With single class initialization, there're no problems - it goes under 5 microseconds almost every time for every class.
But then I decided to scale up the number of initializations and their several troubles occurred
I ran every test 100 times, with arrays of length 500
1. Class initialization with the default constructor
Raw results
I just tested the initialization of arrays
The results were (avg time in microseconds):
Matrix 25.19
SquareMatrix 40.37 (37.60% loss)
Matrix4 58.06 (30.47% loss from SquareMatrix)
And here we can already see a huge difference
Here's the code
int main(int argc, char** argv)
{
std::ofstream f("test.csv");
f << "Matrix\t" << "SquareMatrix\t" << "Matrix4\n";
for (int k = 0; k < 100; k++) {
test(f, '\t', []() {
Matrix<long double>* a = new Matrix<long double>[500];
});
test(f, '\t', []() {
SquareMatrix<long double>* a = new SquareMatrix<long double>[500];
});
test(f, '\n', []() {
Matrix4<long double>* a = new Matrix4<long double>[500];
});
}
f.close();
return 0;
}
2. Class initialization with default constructor and filling
Raw results
Tested the initialization of arrays of class instances and filling them after with custom matrices
The results (avg time in microseconds):
Matrix 402.8
SquareMatrix 475 (15.20% loss)
Matrix4 593.86 (20.01% loss from SquareMatrix)
Code
int main(int argc, char** argv)
{
long double arr[16] = {
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14,15,16
};
std::ofstream f("test.csv");
f << "Matrix\t" << "SquareMatrix\t" << "Matrix4\n";
for (int k = 0; k < 100; k++) {
test(f, '\t', [&arr]() {
Matrix<long double>* a = new Matrix<long double>[500];
for (int i = 0; i < 500; i++)
a[i] = Matrix<long double>(4, 4, arr);
});
test(f, '\t', [&arr]() {
SquareMatrix<long double>* a = new SquareMatrix<long double>[500];
for (int i = 0; i < 500; i++)
a[i] = SquareMatrix<long double>(4, arr);
});
test(f, '\n', [&arr]() {
Matrix4<long double>* a = new Matrix4<long double>[500];
for (int i = 0; i < 500; i++)
a[i] = Matrix4<long double>(arr);
});
}
f.close();
return 0;
}
3. Filling vector with class instances
Raw results
Pushed back custom matrices to vector
The results (avg time in microseconds):
Matrix 4498.1
SquareMatrix 4693.93 (4.17% loss)
Matrix4 4960.12 (5.37% loss from its SquareMatrix)
Code
int main(int argc, char** argv)
{
long double arr[16] = {
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14,15,16
};
std::ofstream f("test.csv");
f << "Matrix\t" << "SquareMatrix\t" << "Matrix4\n";
for (int k = 0; k < 100; k++) {
test(f, '\t', [&arr]() {
std::vector<Matrix<long double>> a = std::vector<Matrix<long double>>();
for (int i = 0; i < 500; i++)
a.push_back(Matrix<long double>(4, 4, arr));
});
test(f, '\t', [&arr]() {
std::vector<SquareMatrix<long double>> a = std::vector<SquareMatrix<long double>>();
for (int i = 0; i < 500; i++)
a.push_back(SquareMatrix<long double>(4, arr));
});
test(f, '\n', [&arr]() {
std::vector<Matrix4<long double>> a = std::vector<Matrix4<long double>>();
for (int i = 0; i < 500; i++)
a.push_back(Matrix4<long double>(arr));
});
}
f.close();
return 0;
}
If you need all the source code, you can look here into matrix.h and matrix.cpp
Does inheritance really not affect performance?
Yes. Inheritance won't affect runtime performance as long as virtual method isn't involved. (Cuz only then will you have to deduce the type at runtime and call corresponding virtual method override). In fact, if you have a sight into lower details, you will know that c++ inheritance is mostly just static things, that is, done at compilation time.
What's the reason of these performance issues in my case and why may they happen in general?
It seems these work well when optimization is enabled?
Should I forget about inheritance in such cases?
The only thing you need to do in such performance-sensitive cases is to avoid virtual method.
Something not related to this question. I have read your code. Perhaps it will be better to implement your templates in header file?
I have a simple program:
#include <array>
#include <iostream>
#include <functional>
#include <algorithm>
using namespace std;
int main(){
array<int, 5> myArr = {3, 10, 0, 5, 7};
int badNum = 0;
for(int item : myArr){
cout << item << endl;
}
cout << "\n" << endl;
cout << "\n" << endl;
sort(myArr.begin(), myArr.end(), greater<int>());
for(int item : myArr){
cout << item << endl;
}
array<int, 4> goodFour;
for (unsigned int i = 0; i < myArr.size(); i++){
if(myArr[i] != badNum){
// goodThree.append(myArr[i]); <-- This is where I am stuck
}
}
}
I am stuck on trying to assign an element to a std::array. I know in std::vector I can use push_back method, but on a std:array, how to assign to the next (not yet assigned) element? I am coming from Python 3.x where we have the append method for a list. I am not attempting to change the size of the array, instead, I am trying to fill in the allocated spaces with values.
I have looked at:
http://www.cplusplus.com/forum/beginner/67707/
http://www.cplusplus.com/forum/beginner/86394/
http://www.cplusplus.com/forum/beginner/152125/
But these are all for vectors or the primitive int[5] myArr types, not std::array.
If you only want the first three good numbers you would maintain a pointer to the next index to insert at:
for (int i = 0, k = 0; k < 3 && i < myArr.size(); i++) {
if (myArr[i] != badNum) {
goodThree[k++] = myArr[i];
}
}
If you want all the numbers that are good you would use a std::vector and call its push_back method:
std::vector<int> goodThree;
for (int i = 0; i < myArr.size(); i++) {
if (myArr[i] != badNum) {
goodThree.push_back(myArr[i]);
}
}
The size of std::array is fixed at compile time. If you need to append another value at run time, then you have to use std::vector (or something like it). The closest you can get to "appending" to a std::array is if you copy its contents into an array with one more element that contains the "appended" value. You can use some template metaprogramming techniques to make this easier:
template <typename T, std::size_t N, typename X, std::size_t... I>
std::array<T, N + 1> push_back(std::array<T, N> const& a, X&& x, std::index_sequence<I...>) {
return {std::get<I>(a)..., std::forward<X>(x)};
}
template <typename T, std::size_t N, typename X>
std::array<T, N + 1> push_back(std::array<T, N> const& a, X&& x) {
return detail::push_back(a, std::forward<X>(x), std::make_index_sequence<N>());
}
Example of use:
std::array<int, 2> a = {1, 2};
std::array<int, 3> b = push_back(a, 3);
for (int x : b) {
std::cout << x << "\n";
}
The size of a std::array is set at compile time. This means that you cannot "append" values to a std::array at run time. However, you could track how many values your array "contains" by your own program logic. For example:
std::array<int, 5> a = {1, 2, 3, 4, 5};
std::array<int, 4> b;
std::size_t n = 0;
for (int x : a) {
if (x != 2) {
if (n < std::size(a) - 1) {
b[n++] = x;
} else {
throw std::out_of_range("array is full");
}
}
}
I am writing a c++ implementation of convolution with the following function
vector<double> Conv(vector<double> a, vector<double> b)
{
// a and b are the same size
int n = a.size() * 2 - 1;
vector<double> c;
for (int i = 0; i < n; i++) {
c.push_back(0);
for (int j = 0; j <= i; j++) {
c[i] += a[j] * b[i - j];
}
}
return c;
}
The problem is that all the convolution values are correct except for the last one. I checked using a convolution calculator I found online.
Example input:
Vector a = <0.961232, 0.00685581, 0.905588, 0.914544>
Vector b = <0.719889, 0.675933, 0.0571511, 0.148412>
Returned vector = <0.691981, 0.654664, 0.711493, 1.41354, 0.670944, 0.186668, 0.653971>
Expected = <0.691980343248, 0.65466385166109, 0.71149237410793, 1.413537159886891, 0.67094330437252, 0.1866673218544, 0.135729304128>
The accuracy of the floats in the returned vector is fine, but the last result doesn't match up.
According to comments of other community members, I believe that your algorithm is not quite correct. Instead of debugging, I decided to find a correct one by google.
These two links gave me the clue:
Convolution of Vectors (Mlmode)
Convolution of two vectors in R
I used these links to make a small sample in C++:
#include <iostream>
#include <vector>
template <typename VALUE>
void convolve(
std::vector<VALUE> &c, // out
const std::vector<VALUE> &a, const std::vector<VALUE> &b) // in
{
const size_t nA = a.size(), nB = b.size();
const size_t nC = nA + nB - 1;
c.clear(); c.resize(nC, (VALUE)0);
for (size_t i = 0; i < nA; ++i) {
for (size_t j = 0; j < nB; ++j) {
c[i + j] += a[i] * b[j];
}
}
}
template <typename VALUE>
inline std::vector<VALUE> convolve(
const std::vector<VALUE> &a, const std::vector<VALUE> &b)
{
std::vector<VALUE> c; convolve(c, a, b); return c;
}
template <typename VALUE>
void print(
std::ostream &out, const char *label, const std::vector<VALUE> &vec)
{
out << label << '[' << vec.size() << "]: {";
const char *sep = " ";
for (const VALUE &v : vec) {
out << sep << v;
sep = ", ";
}
out << " }" << std::endl;
}
int main()
{
// test 1
// http://www.omatrix.com/manual/mlmode_conv.htm
{ std::cout << "Test 1:" << std::endl;
const std::vector<int> a = {
1, 1, 1, 1, 1
};
std::vector<int> c;
convolve(c, a, a);
print(std::cout, "a", a);
std::cout << "Convolution of a and a:" << std::endl;
print(std::cout, "c", c);
}
// test 2
{ std::cout << "Test 2:" << std::endl;
const std::vector<float> a = {
0.961232f, 0.00685581f, 0.905588f, 0.914544f
};
const std::vector<float> b = {
0.719889f, 0.675933f, 0.0571511f, 0.148412f
};
std::vector<float> c;
convolve(c, a, b);
print(std::cout, "a", a);
print(std::cout, "b", b);
std::cout << "Convolution of a and b:" << std::endl;
print(std::cout, "c", c);
}
// done
return 0;
}
Notes:
To copy a vector (as it is done in return) might be expensive for large vectors. Therefore, I provide the result vector by reference. (For those, who prefer return I wrote an inline wrapper but I didn't use it.)
Instead of vector::push_back(), I used vector::resize(). It is usually less expensive to do allocation at once (especially if size is known from beginning). The vector::resize() is also used for initialization. To discard possible previous values, a vector::clear() is done before. (vector::clear() is a cheap method because it does not free storage but simply resets internal number of elements.)
I made convolve a template. This makes the usage more flexible.
I compiled and tested it with g++ in cygwin on Windows 10 (64 bit):
$ g++ -std=c++11 -o vector-convolution vector-convolution.cc
$ ./vector-convolution.exe
Test 1:
a[5]: { 1, 1, 1, 1, 1 }
Convolution of a and a:
c[9]: { 1, 2, 3, 4, 5, 4, 3, 2, 1 }
Test 2:
a[4]: { 0.961232, 0.00685581, 0.905588, 0.914544 }
b[4]: { 0.719889, 0.675933, 0.0571511, 0.148412 }
Convolution of a and b:
c[7]: { 0.69198, 0.654664, 0.711492, 1.41354, 0.670943, 0.186667, 0.135729 }
$
This looks quite good:
Test 1 matches the expected values according to Convolution of Vectors (Mlmode).
Test 2 matches the expected values of your question.
Problem: I want to get an array A[6] = {6, 5, 4, 3, 2, 1} to be A[6] = {5, 3, 1, 1, 1, 1}. In other words - "delete" every second value starting with 0th and shift all other values to the left.
My Attempt:
To do that I would use this code, where a - length of the relevant part of an array A (the part with elements that are not deleted), ind - index of the value that I want to delete.
for (int j = ind; j < n; j++)
A[j] = A[j+1];
However, I couldn't get this to work, using the code like that:
void deleting(int A[], int& a, int ind){
for (int j = ind; j < a; j++)
A[j] = A[j+1];
a--;
}
int A[6] = {6, 5, 4, 3, 2, 1};
a = 6
for (int i = 0; i < a; i+=2)
deleting(A, a, i);
After running this code I was getting A[6] = {5, 4, 2, 1, 1507485184, 1507485184}. So, it deleted the elements at indexes 0, 3. Why did it delete the 3rd index?
There are two ways to do this:
walk the array, copying the last n-i elements forward one place for every even i, or
figure out the eventual state and just go straight to that. The eventual state is the first n/2 places are array[i]=array[2*i + 1], and the last n/2 places are just copies of the last element.
The first method is what you asked for, but it does multiple redundant copy operations, which the second avoids.
As for your implementation problems, examine what happens when j=n-1, and remember A[n] is not a valid element of the array.
I suggest making the copy-everything-forward operation its own function anyway (or you can just use memcpy)
For these kinds of problems (in-place array manipulation), it's a good idea to just keep an index or pointer into the array for where you are "reading" and another where you are "writing." For example:
void odds(int* a, size_t len) {
int* writep = a;
int* readp = a + 1;
while (readp < a + len) { // copy odd elements forward
*writep++ = *readp;
readp += 2;
}
while (writep < a + len - 1) { // replace rest with last
*writep++ = a[len - 1];
}
}
Just for kicks, here is a version which doesn't use a loop:
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <iterator>
#include <utility>
#include <initializer_list>
template <typename T, std::size_t Size>
std::ostream& print(std::ostream& out, T const (&array)[Size]) {
out << "[";
std::copy(std::begin(array), std::end(array) -1,
std::ostream_iterator<T>(out, ", "));
return out << std::end(array)[-1] << "]";
}
template <std::size_t TI, std::size_t FI, typename T, std::size_t Size>
bool assign(T (&array)[Size]) {
array[TI] = array[FI];
return true;
}
template <typename T, std::size_t Size,
std::size_t... T0>
void remove_even_aux(T (&array)[Size],
std::index_sequence<T0...>) {
bool aux0[] = { assign<T0, 2 * T0 + 1>(array)... };
bool aux1[] = { assign<Size / 2 + T0, Size - 1>(array)... };
}
template <typename T, std::size_t Size>
void remove_even(T (&array)[Size]) {
remove_even_aux(array, std::make_index_sequence<Size / 2>());
}
int main() {
int array[] = { 6, 5, 4, 3, 2, 1 };
print(std::cout, array) << "\n";
remove_even(array);
print(std::cout, array) << "\n";
}
If C++ algorithms are an option, I tend to prefer them by default:
auto *const end_A = A + (sizeof(A)/sizeof(*A));
auto *new_end = std::remove_if(
A, end_A,
[&A](int const& i) { return (&i - A) % 2 == 0; });
// Now "erase" the remaining elements.
std::fill(new_end, end_A, 0);
The std::remove_if algorithm simply moves the elements that do not match the predicate (in our case, test if the address is MOD(2)=0), and std::moves them to the end. This is in place. The new "end" is return, which I then indexed over and set the elements to 0.
So if it has to be an array the solution would be like this:
void deleting(int A[size], int size){
for (int i = 0; i < size / 2; i++)
A[i] = A[2 * i + 1];
for (int i = size / 2; i < size; i++)
A[i] = A[size / 2];
}
You first loop through first half of the array "moving" every second number to the front, and then you loop through the rest filling it with the last number.
For a more versatile version of other's answers:
#include <iostream>
template<typename InputIt, typename T>
void filter(InputIt begin, InputIt end, T const& defaultvalue)
{
InputIt fastforward = begin;
InputIt slowforward = begin;
fastforward++; // starts at [1], not [0]
while (fastforward < end)
{
*slowforward = *fastforward;
++slowforward;
++ ++fastforward;
}
while (slowforward < end) // fill with default value
{
*slowforward++ = defaultvalue;
}
}
int main()
{
int A[6] = {6, 5, 4, 3, 2, 1};
std::cout << "before: ";
for (auto n : A)
std::cout << n << ", ";
std::cout << std::endl;
filter(A, A+6, 1);
std::cout << "after: ";
for (auto n : A)
std::cout << n << ", ";
std::cout << std::endl;
}
Outputs:
before: 6, 5, 4, 3, 2, 1,
after: 5, 3, 1, 1, 1, 1,
And this works with std::array<bool>, std::vector<std::string>, std::unordered_set<void*>::iterator, etc.
The common way of doing this would be keeping two indices: one to the entry you're modifying and the other to the entry you intend to process
const auto size = sizeof(A) / sizeof(int);
// N.b. if size == 1 entire array is garbage
int i = 0;
for (int nv = 1; nv < size; ++i, nv += 2)
A[i] = A[nv];
--i;
// Significative array is now [0;N/2[, fill with last now
for (int j = i + 1; j < size; ++j)
A[j] = A[i];
This grants an in-place-modify fashion.
you can combine std::remove_if and std::fill to do this
example code:
#include <algorithm>
#include <iostream>
#include <iterator>
int main()
{
int A[6] = {6, 5, 4, 3, 2, 1};
auto endX = std::remove_if(std::begin(A),std::end(A),[&A](const int& i){return (&i-A)%2==0;});
if(endX!=std::begin(A))//in case nothing remained, although not possible in this case
std::fill(endX,std::end(A),*(endX-1));
//else /*something to do if nothing remained*/
for(auto a : A)std::cout<<a<<' ';
}