{"id":95115,"date":"2017-01-04T07:00:00","date_gmt":"2017-01-04T22:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=95115"},"modified":"2023-08-21T09:17:05","modified_gmt":"2023-08-21T16:17:05","slug":"20170104-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170104-00\/?p=95115","title":{"rendered":"Applying a permutation to a vector, part 3"},"content":{"rendered":"<p>We spent the last two days looking at the <code>apply_permutation<\/code> function and arguing pros and cons of various implementation choices. Today&#8217;s we&#8217;re going to look at generalization.<\/p>\n<p>One of the things you are taught in mathematics is that after you&#8217;ve proved something, you should try to strengthen the conclusion and weaken the hypotheses. Can we apply that principle here?<\/p>\n<p>I don&#8217;t see much that can be done to strengthen the conclusion, but I see a way to weak the hypotheses: The inputs don&#8217;t actually have to be vectors. Anything that supports random access will do. So let&#8217;s use a random access iterator.<\/p>\n<p>And the indices don&#8217;t have to be integers. Anything that can be used to index the random access iterator will do. So let&#8217;s not require to to be an integer; we&#8217;ll take whatever it is.<\/p>\n<pre>template&lt;typename Iter1, typename Iter2&gt;\r\nvoid\r\napply_permutation(\r\n    Iter1 first,\r\n    Iter1 last,\r\n    Iter2 indices)\r\n{\r\n using T = std::iterator_traits&lt;Iter1&gt;::value_type;\r\n using Diff = std::iterator_traits&lt;Iter2&gt;::value_type;\r\n Diff length = last - first;\r\n for (Diff i = 0; i &lt; length; i++) {\r\n  Diff current = i;\r\n  if (i != indices[current]) {\r\n   T t{std::move(first[i])};\r\n   while (i != indices[current]) {\r\n    Diff next = indices[current];\r\n    first[current] = std::move(first[next]);\r\n    indices[current] = current;\r\n    current = next;\r\n   }\r\n   first[current] = std::move(t);\r\n   indices[current] = current;\r\n  }\r\n }\r\n}\r\n<\/pre>\n<p>Note that we used <code>std::iterator_traits<\/code> to determine the appropriate types for the indices and the underlying type. This is significant when the iterator returns a proxy type (such as the infamous <code>vector&lt;bool&gt;<\/code>).<\/p>\n<p>Another observation is that the <code>indices<\/code> don&#8217;t have to be in the range [0, <var>N<\/var> \u2212 1]; as long as we can map the values into that range. But we don&#8217;t need to generalize that, because that can already be generalized in another way: By creating a custom iterator whose <code>*<\/code> operator returns a proxy object that does the conversion.<\/p>\n<p>Okay, I think I&#8217;ve run out of things to write about this <code>apply_permutation<\/code> function. But we&#8217;ll use it later.<\/p>\n<p><b>Exercise<\/b>: Write an <code>apply_inverse_permutation<\/code> which applies the inverse of the specified permutation: Instead of each element of the <code>indices<\/code> telling you where the item comes from, it specifies where the item <i>goes to<\/i>. In other words, if <code>v<\/code> is a copy of the original vector and <code>v2<\/code> is a copy of the result vector, then <code>v2[indices[i]] = v[i]<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Permuting more than just vectors.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-95115","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Permuting more than just vectors.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/95115","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=95115"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/95115\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=95115"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=95115"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=95115"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}