Skip to content

Support P2F and F2P Convertors with multiple field arguments. #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 158 additions & 75 deletions test_generator/F2PConvertor.cpp
Original file line number Diff line number Diff line change
@@ -1,101 +1,184 @@
#include "json.hpp"
#include "universal/include/universal/posit/posit.hpp"
#include <algorithm>
#include <cstdlib>
#include <fstream>
#include <getopt.h>
#include <iostream>
#include <map>
#include <string>
#include <algorithm>

#include "universal/include/universal/posit/posit.hpp"
#include "json.hpp"
#include <unistd.h>
#include <vector>

using json_t = nlohmann::json;

void print_helper() {
std::cout << "Usage: F2P <json> <field> <dimension> \n"
"Converts a JSON file with floating point numbers to posits\n";
struct Args {
json_t json;
int posit_width;
std::vector<std::string> one_dim_fields;
std::vector<std::string> two_dim_fields;
Args() = delete;
};

const static struct option long_options[] = {{"1d", required_argument, 0, 'o'},
{"2d", required_argument, 0, 't'},
{0, 0, 0, 0}};

template <class T> struct tag { using type = T; };
template <class Tag> using type = typename Tag::type;
template <class T, size_t n>
struct n_dim_vec : tag<std::vector<type<n_dim_vec<T, n - 1>>>> {};
template <class T> struct n_dim_vec<T, 0> : tag<T> {};
template <class T, size_t n> using n_dim_vec_t = type<n_dim_vec<T, n>>;

void print_usage(std::string command) {
std::cerr << "Usage: \n\t" << command
<< " <json> <posit-width> --1d <one-dim field_1>,<one-dim "
"field_2> --2d <two-dim field_1>,<two-dim field_2>\n\t"
"Converts a JSON file with floating points to posits \n";
}

template <size_t nbits, size_t es>
void convert_float_to_posit(std::vector<double> &input,
std::vector<unsigned long> &output) {
std::transform(input.cbegin(), input.cend(), output.begin(),
[](double v) -> unsigned long {
sw::unum::posit<nbits, es> p(v);
return p.get().to_ulong();
});
}

json_t parse_data(int argc, char **argv) {
if (argc != 4)
{
print_helper();
template <size_t nbits, size_t es>
void convert_path(json_t json, std::string field, int dim,
json_t &transformed) {
try {
switch (dim) {
case 1: {
auto data = json[field]["data"].get<n_dim_vec_t<double, 1>>();
std::vector<unsigned long> data_posit(data.size());
convert_float_to_posit<nbits, es>(data, data_posit);
transformed[field]["data"] = data_posit;
} break;
case 2: {
auto data = json[field]["data"].get<n_dim_vec_t<double, 2>>();
std::vector<std::vector<unsigned long>> data_posit(
data.size(), std::vector<unsigned long>(data[0].size(), 0));
for (int i = 0; i < data.size(); i++) {
convert_float_to_posit<nbits, es>(data[i], data_posit[i]);
}
transformed[field]["data"] = data_posit;
} break;
default:
std::cerr << "[Error] The value of the dimension should be 1 or 2"
<< std::endl;
}
} catch (nlohmann::json::type_error err) {
std::cerr << "[Error] Expected `" << field
<< ".data' field with type float[]" << std::endl;
exit(2);
}
std::ifstream file(argv[1]);
json_t j;
try {
file >> j;
} catch (nlohmann::detail::parse_error err) {
std::cerr << err.what() << std::endl;
}

void convert_to_posit(json_t json, std::string field, int posit_width, int dim,
json_t &transformed) {
switch (posit_width) {
case 8:
convert_path<8, 1>(json, field, dim, transformed);
case 16:
convert_path<16, 1>(json, field, dim, transformed);
break;
case 32:
convert_path<32, 2>(json, field, dim, transformed);
break;
case 64:
convert_path<64, 3>(json, field, dim, transformed);
break;
// TODO: Currently 128 bit is not supported as we are using unsigned
// long. case 128:
// convert_path<128, 4>(json, field, dim, transformed);
// break;

default:
std::cerr
<< "[Error] The supported posit standards are 8, 16, 32 and 64"
<< std::endl;
exit(2);
}
return j;
}

template<class T>struct tag{using type=T;};
template<class Tag>using type=typename Tag::type;
std::vector<std::string> split_strings(const std::string &input,
char delimiter) {
std::vector<std::string> fields;
std::stringstream stream(input);
std::string field;

template<class T, size_t n>
struct n_dim_vec:tag< std::vector< type< n_dim_vec<T, n-1> > > > {};
template<class T>
struct n_dim_vec<T, 0>:tag<T>{};
template<class T, size_t n>
using n_dim_vec_t = type<n_dim_vec<T,n>>;
while (!stream.eof()) {
std::getline(stream, field, delimiter);
fields.push_back(field);
}
return fields;
}

void convert_path_1d(json_t json, std::string field) {
Args parse_data(int argc, char **argv) {
json_t json;
std::ifstream file(argv[1]);
try {
auto data = json[field]["data"].get<n_dim_vec_t<double, 1>>();
std::vector<unsigned long> data_posit(data.size());
std::transform(
data.cbegin(),
data.cend(),
data_posit.begin(),
[](double v) -> unsigned long {
sw::unum::posit <32, 2> p (v);
return p.get().to_ulong();
});
json_t transformed;
transformed = json;
transformed[field]["data"] = data_posit;
std::cout << transformed.dump(2);
} catch(nlohmann::json::type_error err) {
std::cerr << "[Error] Expected `" << field << ".data' field with type float[]" << std::endl;
file >> json;
} catch (nlohmann::detail::parse_error err) {
std::cerr << err.what() << std::endl;
exit(2);
}
}

void convert_path_2d(json_t json, std::string field) {
try {
auto data = json[field]["data"].get<n_dim_vec_t<double, 2>>();
std::vector<std::vector<unsigned long>> data_posit(data.size(), std::vector<unsigned long>(data[0].size(), 0));
for( int i = 0; i < data.size() ; i++) {
std::transform(
data[i].cbegin(),
data[i].cend(),
data_posit[i].begin(),
[](float v) -> unsigned long {
sw::unum::posit <32, 2> p (v);
return p.get().to_ulong();
});
}
json_t transformed;
transformed = json;
transformed[field]["data"] = data_posit;
std::cout << transformed.dump(2);
} catch(nlohmann::json::type_error err) {
std::cerr << "[Error] Expected `" << field << ".data' field with type float[]" << std::endl;
exit(2);
}
int posit_width = std::stoi(argv[2]);

int c, option_index;
std::vector<std::string> one_dim_fields, two_dim_fields, split;
while ((c = getopt_long(argc, argv, ":o:t:", long_options,
&option_index)) != 1) {
switch (c) {
case 'o':
split = split_strings(optarg, ',');
one_dim_fields.insert(one_dim_fields.end(), split.begin(),
split.end());
break;
case 't':
split = split_strings(optarg, ',');
two_dim_fields.insert(two_dim_fields.end(), split.begin(),
split.end());
break;
case '?':
std::cerr << "Invalid option" << std::endl;
print_usage(argv[0]);
exit(2);
default:
std::cerr << "Unexpected behaviour" << std::endl;
print_usage(argv[0]);
exit(2);
}
}
if ((optind != argc - 2)) {
std::cerr << "Invalid arguments" << std::endl;
exit(2);
}
return Args{json, posit_width, one_dim_fields, two_dim_fields};
}

int main(int argc, char *argv[]) {
auto j = parse_data(argc, argv);
if(strcmp(argv[3], "1") == 0) {
convert_path_1d(j, argv[2]);
if (!(argc >= 5)) {
print_usage(argv[0]);
return 2;
}
else if(strcmp(argv[3], "2") == 0) {
convert_path_2d(j, argv[2]);
Args input = parse_data(argc, argv);
json_t transformed = input.json;

for (int i = 0; i < input.one_dim_fields.size(); i++) {
convert_to_posit(input.json, input.one_dim_fields[i], input.posit_width,
1, transformed);
}
else {
print_helper();
exit(2);

for (int i = 0; i < input.two_dim_fields.size(); i++) {
convert_to_posit(input.json, input.two_dim_fields[i], input.posit_width,
2, transformed);
}
}
std::cout << transformed.dump(2);
}
Loading