what happened in this auto loop? - c++

vector<int> nums = {1, 2, 3};
vector<vector<int>> subsets = {{}};
for(int i=0; i<3; i++)
for(auto subset : subsets)
{
subset.push_back(nums[i]);
subsets.push_back(subset);
}
The content of subsets, after running, turns out to be:
[[] [1] [2] [2] [3] [3] [3] [3]]
However, I was expecting:
[[] [1] [2] [1 2] [3] [1 3] [2 3] [1 2 3]]
It seems like only the first element, which is an empty vector<int>, being considered.
Could you please tell me what exactly happened in terms of memory allocation?
PS: I also changed subsets.push_back(subset) into subsets.push_back(vector<int>(subset)), but it still gives the same incorrect result.

There are a few things that will not work as expected:
for(auto subset : subsets) Says "Give me a modifiable copy of the element."
Change auto to auto& to receive a modifiable reference.
Range-based for-loops are intended to be used to view a constant range of elements. If you modify the range the iterators will be invalidated. Use a standard for loop instead.

Related

Sorting pairs of elements from vectors to maximize a function

I am working on a vector sorting algorithm for my personal particle physics studies but I am very new to coding.
Going through individual scenarios (specific vector sizes and combinations) by brute force becomes extremely chaotic for greater numbers of net vector elements, especially since this whole code will be looped up to 1e5 times.
Take four vectors of 'flavors' A and B: A+, A-, B+, and B-. I need to find two total pairs of elements such that some value k(V+, V-) is maximized with the restriction that different flavors cannot be combined! (V is just a flavor placeholder)
For example:
A+ = {a1+}
A- = {a1-}
B+ = {b1+, b2+}
B- = {b1-}
Since A+ and A- only have one element each, the value k(A+, A-) -> k(a1+, a1-). But for flavor B, there are two possible combinations.
k(b1+, b1-) OR k(b2+, b1-)
I would like to ensure that the combination of elements with the greater value of k is retained. As I said previously, this specific example is not TOO bad by brute force, but say B+ and B- had two elements each? The possible values would be:
k(b1+, b1-) or k(b2+,b2-) or k(b1+, b2-) or k(b2+, b1-)
where only one of these is correct. Furthermore, say two of those four B+B- combinations had greater k than that of A+A-. This would also be valid!
Any help would be appreciated!!! I can clarify if anything above is overly confusing!
I tried something like this,
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
static bool sortbypair(const pair<double, double> &a, const pair<double, double> &b)
{
return (k(a.first, a.second) > k(b.first, b.second)) && k(a.first, b.second) < k(a.second, b.first);
}
But I can't flesh it out.
If I understand your question correctly,
you have a function k which maps two doubles (or a std::pair<double, double>) to a single double. I am assuming double, it wasn't clear from the question. It also isn't strictly at the core of your problem.
you have four std::vector<double>s: aplus, aminus, bplus and bminus.
Your domain are all std::pair<double, double>s that you can form by combining the elements in aplus and aminus as well as all combinations from bplus and bminus respectively.
you want to either
find the pair in your domain that maximizes k
get a collection of all pairs in your domain, sorted by the value of k
Did I get this right? You state in your question
I need to find two total pairs of elements such that some value k(V+, V-) is maximized [...]
which confuses me a bit.
My suggestion is to break down your problem into three subtasks:
Create a range of all combinations of elements in the vectors Vplus and Vminus. This is often denoted as a cartesian product Vplus x Vminus.
Concatenate the ranges created in step 1 for aplus x aminus and bplus x bminus to get a range of all viable pairs in your domain.
Maximize/sort the range from step 2.
Implementation using range-v3
The range-v3 library provides some very convenient tools for this kind of task. Let's assume your k function looks like this:
double k(double x, double y) { return x*x + y*y; }
and your vectors look like this:
std::vector<double> ap{0., 4., 2., 3., 1.};
std::vector<double> am{2., -1.};
std::vector<double> bp{1., 0.5};
std::vector<double> bm{-1., 2.};
Let's define a range representing our domain:
using namespace ranges;
auto pairs_view = view::concat(
view::cartesian_product(ap, am),
view::cartesian_product(bp, bm)
);
The pairs_view instance doesn't actually create the pairs anywhere in memory. It is just an adaptor object that let's you iterate over all pairs that you can construct in the specified way. The pairs are created "lazily" on the fly as you - or an algorithm - iterates over it.
Let's print all pairs from our domain:
auto print = [](auto const& p){
auto first = std::get<0>(p);
auto second = std::get<1>(p);
std::cout << "[" << first << ", " << second << "] k = " << k(first, second) << std::endl;
};
for_each(pairs_view, print);
Output:
[0, 2] k = 4
[0, -1] k = 1
[4, 2] k = 20
[4, -1] k = 17
[2, 2] k = 8
[2, -1] k = 5
[3, 2] k = 13
[3, -1] k = 10
[1, 2] k = 5
[1, -1] k = 2
[1, -1] k = 2
[1, 2] k = 5
[0.5, -1] k = 1.25
[0.5, 2] k = 4.25
Finding the maximum element
Let's start by defining a convenience function (here, in the form of a lambda expression) that evaluates k for a tuple of doubles:
auto k_proj = [](auto const& p){
return k(std::get<0>(p), std::get<1>(p));
};
You can find an iterator to the pair in your domain that maximizes k with just the single line:
auto it = max_element(pairs_view, less{}, k_proj);
print(*it);
Output:
[4, 2] k = 20
The function max_element gets two additional arguments. The first is a comparison function that returns true, if two elements are in order. We provide the default less functor. The second argument is an optional projection that is to be applied on each element before the comparison. We pass k_proj.
Read the above line of code as "Find the element in pairs_view of which the projection onto its k value is maximal, where we want to compare the projected values with the standard less function."
Getting a sorted range of your domain
If you want to have all sorted range of all pairs in your domain, we must create an std::vector<std::pair<double, double>> for your domain first and then sort it. You cannot sort views created with the range-v3 library, because they are just a view into existing objects, they cannot be mutated. In addition, we have to map the special pair types created by the range-v3 library in the cartesian_product functions to actual std::pair<double, double to copy the values into our new container:
auto to_std_pair = [](auto const& p){
return std::pair<double, double>{std::get<0>(p), std::get<1>(p)};
};
auto pairs_vec = pairs_view | view::transform(to_std_pair) | to_vector;
Note that the "pipe" operator | is short-hand notation for the function composition to_vector(view::transform(pairs_view, to_std_pair)).
The invokation of the sorting algorithm looks very similar to the invokation of the max_element algorithm:
sort(pairs_vec, less{}, k_proj);
Let's print the result:
for_each(pairs_vec, print);
Output:
[0, -1] k = 1
[0.5, -1] k = 1.25
[1, -1] k = 2
[1, -1] k = 2
[0, 2] k = 4
[0.5, 2] k = 4.25
[2, -1] k = 5
[1, 2] k = 5
[1, 2] k = 5
[2, 2] k = 8
[3, -1] k = 10
[3, 2] k = 13
[4, -1] k = 17
[4, 2] k = 20
Here is a complete live code example: https://godbolt.org/z/6zo8oj3ah
If you don't want to use the range-v3 library you have two options:
You can wait. Large parts of the range-v3 library have been added to the standard library in C++20. The relevant functions concat, cartesian_product and to_vector will presumably be added in the upcoming standard C++23.
The standard library has max_element and sort. So you could just implement the concatenation and cartesian product on your own: https://godbolt.org/z/7Y5dG16WK
Thank you to everyone who commented!!! I really appreciate your effort. The solution ended up being much simpler than I was making it out to be.
Essentially, from the physics program I'm using, the particles are given in a listed form (ie. 533 e-, 534
p+, 535 e+, etc.). I couldn't figure out how to get range-v3 working (or any external libraries for that matter but thank you for the suggestion) so I figured out to make a tuple out of the indices of combined particles and their associated k value.
#include <iostream>
#include <vector>
#include <algorithm>
#include <tuple>
using namespace std;
static bool weirdsort(const tuple<int, int, double> &a, const tuple<int, int, double> &b)
{
return get<2>(a) > get<2>(b);
}
int main()
{
vector<tuple<int, int, double>> net;
// Sample ptcl list
//
// A+ A- B+ B-
// 0 a1+
// 1 a1-
// 2 b1-
// 3 b1+
// 4 a2+
// 5 a2-
for(int i = 0; i < A+.size(); i++)
{
for (int j = 0; j < A-.size(); j++)
{
net.push_back(A+[i], A-[j], k(A+[i], A-[j]));
}
}
sort(net.begin(), net.end(), weirdsort);
//Now another for loop that erases a tuple (with a lower k value) if it has a repeated ptcl index.
for (int i = 0; i < net.size(); i++)
{
if (get<0>(net[i]) == get<0>(net[i + 1]) || get<1>(net[i]) == get<1>(net[i + 1]))
{
net.erase(net.begin() + i + 1);
}
}
//Now can plot third tuple element of net[0] and net[1]
return 0;
}
It's not quite perfect but since I'm only looking for the first two highest k values it works out just fine. Thanks again!

(wx)Maxima: how to iterate an action over every member of a list?

I'm wondering if there is a functional way to apply an action to every element of list, in Maxima, without necessarily looping over the list?
e.g. if I would like to remove every element of the list a:[1,2,3] from the list b:[5,4,3,2,1]. Obviously, something like:
f(a,b):=
block(
[aList:a, newList:b],
for k thru length(aList)
do newList: delete(aList[k],newList)
);
I just wondered if there was a more direct way? I thought apply might work, but couldn't figure it out, as it seems to take the whole list as the argument (vs. list elements).
There are a few different ways to accomplish that. One way is to treat the arguments as sets and apply setdifference.
(%i2) a: [1, 2, 3] $
(%i3) b: [5, 4, 3, 2, 1] $
(%i4) setify(a);
(%o4) {1, 2, 3}
(%i5) setify(b);
(%o5) {1, 2, 3, 4, 5}
(%i6) setdifference (setify(b), setify(a));
(%o6) {4, 5}
(%i7) listify(%);
(%o7) [4, 5]
That works if a and b are really sets, i.e. order doesn't matter, and elements are unique.
Another way:
(%i8) sublist (b, lambda ([x], not member(x, a)));
(%o8) [5, 4]
I guess the sublist approach makes fewer assumptions, so it is more generally applicable.

why I cannot change the value in loop of `set<set<int>>`

Here is the minimum function of my question:
void solve(void)
{
set<set<int> > test;
for(set<set<int> >::iterator it = test.begin(); it != test.end(); ++it) {
// (*it)'s type is set<int> right? but why I cannot insert a int into this?
it -> insert(1);
}
}
The compiler tell me that no matching function for call to 'std::set<int>::insert(int) const'.
It really confuse me that why it do not use std::set<int>::insert(int) without the const? How can I do this? Can I make it really?
*** first edited ***
I know that I can erase an element like it = test.erase(it) and I also know that I can use test.insert(<a set<int> value>), so is it possible to insert firstly and then delete the original element? but it looks troublesome right?
*** seconed edited ***
About the use-case: Before I know the Disjoint-set data structure, I want to slove its problem, so I need to deal with the set<int> type data in set<set<int>> type data. It upset me that I find I cannot change the inner set in the loop so I cannot union those inner sets - (or maybe I can, I try to put those elements of inner set's value into a temp set and then I remove the original sets, then I insert the temp set into set<set>. BUT it does look ugly). So I know to make it but I do not know why the iterators are const, and I also want t know a better way to deal with sets in set.
*** third edited ***
Thank you #anurag-dhadse for pointing the grammar error.
Thanks.
Your it->insert(1) attempts to change a set<int> inside the outer set<set<int>>, and in so doing might change the position in which *it should be stored in the outer set, which would breach the class invariants by not keeping the elements sorted. To avoid that, the outer set only gives it const access to the set<int> elements
If you want to modify a set<int> element, you need to extract it from the outer set, modify it, then insert it back wherever it should now go.
You realize that if you insert many sets inside an "outer" set, those inner sets will be placed in lexicographical order:
#include <set>
#include <vector>
#include <iostream>
using namespace std;
int main () {
set A1 = {2, 7};
set A2 = {1, 8, 3, 4};
set A3 = {1, 4, 3};
set<set<int>> set_of_sets;
set_of_sets.insert(A1);
set_of_sets.insert(A2);
set_of_sets.insert(A3);
for ( auto& inner_set : set_of_sets ) {
std::cout << "[ " ;
for ( auto &element : inner_set ) {
std::cout << element << " ";
}
std::cout << "]\n";
}
}
Will produce the following response:
[ 1 3 4 ]
[ 1 3 4 8 ]
[ 2 7 ]
They changed the order, not only the integers inside each set, but A1 was swapped by A3 (following lexicographical order )
https://godbolt.org/z/nacxrn
If you insert 1 to each set, the [1 3 4] will not change, the [1 3 4 8] will also not change, but [2 7] will become [1 2 7] wich means that A1 should be swappped by A3 again since [1 2 7] < [1 3 4], therefore C++ does not allow you to change the position of the inner sets inside the outer set during iteration ( by making iterators const ).
So, it´s not clear why you are using a set.
it´s easy ( for many applications ) just use a vector of sets so you can change them freely:
vector<set<int> > test { A1, A2, A3 } ;
for(auto& s : test ) {
s.insert(1); /// inserting 1 in all sets
}
https://godbolt.org/z/WMvse9

Iteratively removing elements from ArrayFire array

I am trying to remove elements from an ArrayFire array (af::array) iteratively in a loop. Say I have:
af::array arr = af::range(af::dim4(4), -1, u32) + 1);
// arr = [1 2 3 4] (it's a column vector, though shown as a row vector here)
At each iteration of the loop, I have to remove a value from the array. The value to be removed depends on a computation, the result of which is not always the same. So in 4 iterations of the loop, the process can look like:
// Iter 1: arr = [1 3 4] (removed 2)
// Iter 2: arr = [1 4] (removed 3)
// Iter 3: arr = [4] (removed 1)
// Iter 4: arr = empty (removed 4)
I was wondering if someone had a suggestion on how best to accomplish this. I have a technique working that requires a conversion of arr to a C-array, removing an element, and re-conversion back to a device af::array. Is there a more idiomatic/efficient way to accomplish this?
Assuming the code in your example using columns, I would do the following since there doesn't appear to be any kind of row / column delete function.
i is set to the row we wish to delete, numbering starts at 0:
int i=2;
arr = af::join(0,arr.rows(0,i-1), arr.rows(i+1,end));
af::af_print(arr);
prints:
arr [3 1 1 1]
1
2
4
If you wish to have your data in a column vector, change the 'rows' function to the 'cols' function.

how to organize one vector by placing into another vector using for loop c++

I was wondering how I could possibly organize one vector by placing it into an another. (Note: They are vector of objects). What i have so far is:
double done;
for ( int i = 0; i < id; i++ )
{
done = guy[i].done();
int smallest = i;
for( int j = i + 1; j < id; j++ ){
if( done > guy[j].done() )
{
done = guy[j].done();
smallest = j;
}
}
newGuy.push_back( guy[smallest] );
}
This doesn't organize every part of the vector, and sometimes even copies the same guy into the newGuy. Any ideas?
If you are trying to sort the vector, you could define a custom less-than comparator for your objects, and use std::sort.
bool myComparison(const MyType& lhs, const MyType& rhs) {
return lhs.done() < rhs.done();
}
std::vector<MyType> guy = ....;
std::sort(guy.begin(), guy.end(), myComparison);
If you want it all to go to a new vector, then just copy the original, then sort the copy:
std::vector<MyType> newGuy = guy;
std::sort(newGuy.begin(), newGuy.end(), myComparison);
Because you are not removing your smallest person from the old array when you put it into the new one. Consider the values [5,4,3,2,1]
Your algorithm will on the first value for i find that the smallest is j=4 (value 1) and push 1 onto the new array, then it will do this for i=2 and so on until you have only [1,1,1,1,1]
Here is what you are doing, where the bold numbers are the ones being looped over, and the second array is the output array.
Pass 1:
[5 ,4, 3, 2, 1]
[1]
Pass 2:
[5, 4, 3, 2, 1]
[1,1]
Pass 3:
[5, 4, 3, 2, 1]
[1,1,1]
Pass 4:
[5, 4, 3, 2, 1]
[1,1,1,1]
Pass 5:
[5, 4, 3, 2, 1]
[1,1,1,1,1]
Just remove the item that you just found to be the smallest from the old vector when you add it to the new one each time. Of course as other people have pointed out it would actually be better to just use std's sorting algorithms