blob: 8fb06e2e34349e8d5c474fe35f3e1c5f01123a00 [file] [edit]
// Copyright (c) Google LLC 2019
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
// Library to compute the Lehmer code of a permutation and to reconstruct the
// permutation from its Lehmer code. For more details on Lehmer codes, see
// http://en.wikipedia.org/wiki/Lehmer_code
#ifndef BRUNSLI_COMMON_LEHMER_CODE_H_
#define BRUNSLI_COMMON_LEHMER_CODE_H_
#include <brunsli/types.h>
#include <algorithm>
#include <utility>
#include <vector>
#include "./platform.h"
namespace brunsli {
// Computes the Lehmer code of the permutation sigma[0..len) and puts the
// result into code[0..len).
void ComputeLehmerCode(const uint32_t* sigma, size_t len, uint32_t* code);
// Decodes the Lehmer code in code[0..len) and puts the resulting permutation
// into sigma[0..len).
bool DecodeLehmerCode(const uint32_t* code, size_t len, uint32_t* sigma);
// This class is an optimized Lehmer-like coder that takes the remaining
// number of possible values into account to reduce the bit usage.
// TODO(eustas): in worst case (always removing the first element), O(N^2)
// elements are moved; "Fenwick tree" is simple to implement and could reduce
// the complexity to O(N * log(N)).
class PermutationCoder {
public:
PermutationCoder() {}
void Init(std::vector<uint8_t> values) { values_ = std::move(values); }
void Clear() { std::vector<uint8_t>().swap(values_); }
// number of bits needed to represent the next code.
int num_bits() const {
uint32_t num_values = static_cast<uint32_t>(values_.size());
BRUNSLI_DCHECK(num_values > 0);
if (num_values <= 1) return 0;
return static_cast<int>(Log2FloorNonZero(num_values - 1) + 1);
}
// Copy value at position 'code' and remove it. Returns false in
// case of error (invalid slot).
bool Remove(size_t code, uint8_t* value) {
if (code >= values_.size()) {
return false;
}
*value = values_[code];
values_.erase(values_.begin() + code);
return true;
}
// Removes 'value' from the list and assign a code + number-of-bits
// for it. Returns false if value could not be encoded.
bool RemoveValue(uint8_t value, int* code, int* nbits) {
std::vector<uint8_t>::iterator it =
std::find(values_.begin(), values_.end(), value);
if (it == values_.end()) {
return false; // invalid/non-existing value was passed.
}
*code = static_cast<int>(it - values_.begin());
*nbits = num_bits();
values_.erase(it);
return true;
}
private:
std::vector<uint8_t> values_;
};
} // namespace brunsli
#endif // BRUNSLI_COMMON_LEHMER_CODE_H_