*/
#include <base_properties.h>
+#include <sstream>
#include <string>
+#include <vector>
namespace nntrainer {
const std::string &value) {
return std::stoul(value);
}
+
+template <>
+std::string str_converter<dimension_prop_tag, TensorDim>::to_string(
+ const TensorDim &dimension) {
+ std::stringstream ss;
+ ss << dimension.batch() << ':' << dimension.channel() << ':'
+ << dimension.height() << ':' << dimension.width();
+ return ss.str();
+}
+
+template <>
+TensorDim str_converter<dimension_prop_tag, TensorDim>::from_string(
+ const std::string &value) {
+ std::vector<std::string> tokens;
+ std::string token;
+ std::istringstream iss(value);
+
+ while (std::getline(iss, token, ':')) {
+ tokens.push_back(token);
+ }
+
+ NNTR_THROW_IF(tokens.size() > MAXDIM, std::invalid_argument)
+ << "More than 4 axes is not supported, target string: " << value;
+
+ TensorDim target;
+
+ int cur_axis = 3;
+ for (auto iter = tokens.rbegin(); iter != tokens.rend(); iter++) {
+ target.setTensorDim(cur_axis--, std::stoul(*iter));
+ }
+
+ return target;
+}
+
} // namespace nntrainer
return nntrainer::endswith(v, "good");
}
};
+
+/**
+ * @brief DimensionOfBanana property for example, this has to have batch size of
+ * 1
+ *
+ */
+class DimensionOfBanana : public nntrainer::Property<nntrainer::TensorDim> {
+public:
+ static constexpr const char *key = "banana_size";
+ using prop_tag = nntrainer::dimension_prop_tag;
+
+ bool isValid(const nntrainer::TensorDim &dim) const override {
+ std::cerr << dim;
+ return dim.batch() == 1;
+ }
+};
} // namespace
TEST(BasicProperty, tagCast) {
EXPECT_EQ(nntrainer::to_string(q), "this is good");
}
+ { /** set -> get / to_string, dimension*/
+ DimensionOfBanana q;
+ q.set({1, 2, 3, 4});
+ EXPECT_EQ(q.get(), nntrainer::TensorDim(1, 2, 3, 4));
+ EXPECT_EQ(nntrainer::to_string(q), "1:2:3:4");
+ }
+
+ { /**< from_string -> get / to_string, dimension */
+ DimensionOfBanana q;
+ nntrainer::from_string("1:2:3:4", q);
+ EXPECT_EQ(q.get(), nntrainer::TensorDim(1, 2, 3, 4));
+ EXPECT_EQ(nntrainer::to_string(q), "1:2:3:4");
+ }
+
+ { /**< from_string -> get / to_string, dimension */
+ DimensionOfBanana q;
+ nntrainer::from_string("3:4", q);
+ EXPECT_EQ(q.get(), nntrainer::TensorDim(1, 1, 3, 4));
+ EXPECT_EQ(nntrainer::to_string(q), "1:1:3:4");
+ }
+
{ /**< exporter test */
auto props = std::make_tuple(NumBanana(), QualityOfBanana());
}
{ /**< load from layer */
- auto props = std::make_tuple(NumBanana(), QualityOfBanana());
+ auto props =
+ std::make_tuple(NumBanana(), QualityOfBanana(), DimensionOfBanana());
- auto v =
- nntrainer::loadProperties({"num_banana=2", "quality_banana=thisisgood",
- "num_banana=42", "not_used=key"},
- props);
+ auto v = nntrainer::loadProperties(
+ {"num_banana=2", "quality_banana=thisisgood", "num_banana=42",
+ "banana_size=2:2:3", "not_used=key"},
+ props);
EXPECT_EQ(v, std::vector<std::string>{"not_used=key"});
EXPECT_EQ(std::get<0>(props).get(), 42);
EXPECT_THROW(q.set("invalid_str"), std::invalid_argument);
}
+TEST(BasicProperty, setNotValid_03_n) {
+ DimensionOfBanana d;
+ EXPECT_THROW(d.set({3, 3, 2, 4}), std::invalid_argument);
+}
+
TEST(BasicProperty, fromStringNotValid_01_n) {
NumBanana b;
EXPECT_THROW(nntrainer::from_string("not integer", b), std::invalid_argument);
EXPECT_THROW(nntrainer::from_string("invalid_str", q), std::invalid_argument);
}
+TEST(BasicProperty, fromStringNotValid_04_n) {
+ DimensionOfBanana d;
+ EXPECT_THROW(nntrainer::from_string("1:1:2:3:5", d), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_05_n) {
+ DimensionOfBanana d;
+ EXPECT_THROW(nntrainer::from_string("2:2:3:5", d), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_06_n) {
+ DimensionOfBanana d;
+ EXPECT_THROW(nntrainer::from_string("", d), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_07_n) {
+ DimensionOfBanana d;
+ EXPECT_THROW(nntrainer::from_string(":2:3:5", d), std::invalid_argument);
+}
+
TEST(Exporter, invalidMethods_n) {
auto props = std::make_tuple(NumBanana(), QualityOfBanana());