#pragma once
#include <ostream>
#include <span>
#include "util/vector.h"
class permutation {
unsigned_vector m_p;
unsigned_vector m_inv_p;
public:
permutation(unsigned size = 0);
void reset(unsigned size = 0);
unsigned operator()(unsigned i) const { return m_p[i]; }
unsigned inv(unsigned i_prime) const { return m_inv_p[i_prime]; }
void swap(unsigned i, unsigned j) noexcept;
void move_after(unsigned i, unsigned j);
void display(std::ostream & out) const;
bool check_invariant() const;
};
void swap(unsigned i, unsigned j) noexcept;
inline std::ostream & operator<<(std::ostream & out, permutation const & p) {
p.display(out);
return out;
}
template<typename T>
void apply_permutation_core(std::span<T> data, std::span<unsigned> p) {
SASSERT(data.size() == p.size());
int * p1 = reinterpret_cast<int*>(p.data());
int sz = static_cast<int>(data.size());
for (int i = 0; i < sz; ++i) {
if (p1[i] < 0)
continue; int j = i;
while (true) {
SASSERT(j >= 0);
int p_j = p1[j];
SASSERT(p_j >= 0);
SASSERT(p_j < sz);
p1[j] = - p1[j] - 1; if (p_j == i)
break; swap(data[j], data[p_j]);
j = p_j;
}
}
}
template<typename T>
void apply_permutation_core(unsigned sz, T * data, unsigned * p) {
apply_permutation_core(std::span<T>(data, sz), std::span<unsigned>(p, sz));
}
template<typename T>
void apply_permutation(std::span<T> data, std::span<unsigned const> p) {
SASSERT(data.size() == p.size());
apply_permutation_core(data, std::span<unsigned>(const_cast<unsigned*>(p.data()), p.size()));
int * p1 = reinterpret_cast<int*>(const_cast<unsigned*>(p.data()));
int sz = static_cast<int>(p.size());
for (int i = 0; i < sz; ++i) {
p1[i] = - p1[i] - 1;
}
}
template<typename T>
void apply_permutation(unsigned sz, T * data, unsigned const * p) {
apply_permutation(std::span<T>(data, sz), std::span<unsigned const>(p, sz));
}