blocky/conv/fcprob_fcode.cc

148 lines
3.4 KiB
C++

#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <vector>
#include <args.hxx>
#include "conv/common.hh"
namespace param {
using namespace ::args;
ArgumentParser parser {
"converter: feature code probability matrix -> feature code"
};
HelpFlag help {
parser, "help", "display this menu", {'h', "help"},
};
enum StepAlgo {
kIncrement,
};
const std::unordered_map<std::string, StepAlgo> kStepAlgo = {
{"inc", kIncrement},
};
MapFlag<std::string, StepAlgo> algo {
parser, "inc", "step algorithm (inc)", {"algorithm", "algo"}, kStepAlgo,
};
Group inc {
parser, "increment algorithm parameters"
};
ValueFlag<uint32_t> inc_min {
inc, "1", "max stride of increment algorithm", {"inc-min"}, 1,
};
ValueFlag<uint32_t> inc_max {
inc, "1", "max stride of increment algorithm", {"inc-max"}, 1,
};
Flag output_prob {
parser, "output-prob", "prints path probability at last", {"output-prob", "prob"},
};
} // namespace param
static auto GenerateLegalStepMap(size_t dur, size_t n) {
const auto inc_max = args::get(param::inc_max);
const auto inc_min = args::get(param::inc_min);
Enforce(0 <= inc_min && inc_min <= inc_max, "invalid increment stride");
std::vector<std::vector<int32_t>> ret;
ret.resize(dur*n);
auto legals = &ret[0];
for (size_t t = 0; t < dur; ++t) {
for (size_t i = 0; i < n; ++i) {
switch (args::get(param::algo)) {
case param::kIncrement:
legals->reserve(inc_max-inc_min+1);
for (uint32_t j = inc_min; j <= inc_max; ++j) {
legals->push_back(static_cast<int32_t>((i+j)%n));
}
break;
}
++legals;
}
}
return ret;
}
static void Exec() {
const auto cprobs = ReadMatrix<double>(std::cin);
Enforce(cprobs.size() > 0 && cprobs[0].size() > 0, "empty matrix");
const auto dur = cprobs.size();
const auto n = cprobs[0].size();
const auto lmap = GenerateLegalStepMap(dur, n);
struct Step {
double prob = -1;
size_t from = 0;
};
std::vector<Step> steps((dur+1)*n);
for (size_t i = 0; i < n; ++i) {
steps[i].prob = cprobs[0][i];
}
for (size_t t = 1; t < dur; ++t) {
Enforce(cprobs[t].size() == n, "ill-formed matrix");
for (size_t i = 0; i < n; ++i) {
const auto& cur = steps[(t-1)*n + i];
for (auto j : lmap[t*n+i]) {
auto& next = steps[t*n + j];
const auto sum = cur.prob + cprobs[t][j];
if (next.prob < sum) {
next.prob = sum;
next.from = i;
}
}
}
}
double max_prob = -1;
size_t max_idx = 0;
for (size_t i = 0; i < n; ++i) {
const auto& step = steps[(dur-1)*n + i];
if (max_prob < step.prob) {
max_prob = step.prob;
max_idx = i;
}
}
std::vector<size_t> path = {max_idx};
path.reserve(dur);
for (size_t t = dur-1; t > 0; --t) {
path.push_back(steps[t*n + path.back()].from);
}
for (auto itr = path.rbegin(); itr < path.rend(); ++itr) {
std::cout << *itr << '\n';
}
if (param::output_prob) {
std::cout << max_prob/static_cast<double>(path.size())*100 << "%" << std::endl;
}
}
int main(int argc, char** argv)
try {
param::parser.ParseCLI(argc, argv);
Exec();
return EXIT_SUCCESS;
} catch (const args::Help&) {
std::cout << param::parser << std::endl;
return EXIT_SUCCESS;
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}