Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
18604da
experiments
Zylence Jul 6, 2024
8625df4
added some mean and standard deviation math helpers to utils.hh
Zylence Jul 7, 2024
9d35499
added new fields to FlatModelStatistics
Zylence Jul 7, 2024
972bdab
Added calculations for the new fields of FlatModelStatistics and adde…
Zylence Jul 7, 2024
240eca9
Added new cmdline option for feature-vector extraction: --feature-vector
Zylence Jul 20, 2024
7b4765b
Introduced feature vector struct which will take all the new stats th…
Zylence Jul 20, 2024
30a9246
Removed potentially truncating cast from mean helper function.
Zylence Jul 21, 2024
d4377a3
Introduced a Domain class to the feature_extraction to be able to wor…
Zylence Jul 21, 2024
90322ae
added a constraint graph as easy representation for the relations bet…
Zylence Jul 27, 2024
47e4a45
added constraint histogram and annotation histogram
Zylence Jul 28, 2024
9b654a6
added average decision variables used in constraints as metric to fe…
Zylence Jul 28, 2024
2f1eeb8
Added meta constraints counter to feature vector. meta constraints ar…
Zylence Jul 28, 2024
756d4b4
Added methods to StatisticsStream to print an array or map as json an…
Zylence Aug 4, 2024
2157b72
Customized usage of StatisticsStream for FeatureVector. All calculate…
Zylence Aug 4, 2024
bd56a12
fixed an index out of bounds in is_var_defined_by_call. Furhter now f…
Zylence Aug 4, 2024
4ea78b0
Now outputting the individual domain widths as array. array indices m…
Zylence Aug 4, 2024
8e66bf6
Fixed nullpointer in feature extraction.
Zylence Aug 7, 2024
53a9cf9
Added some optional commandlineoptions to the feature vector extraction.
Zylence Aug 23, 2024
2fbfd32
better json serialization of numeric values for maps and arrays
Zylence Aug 23, 2024
1fcf165
fixed nullpointer in feature vector extraction that ocurred when used…
Zylence Aug 30, 2024
8d5036e
feature vector extraction now allows for constraints and variable lim…
Zylence Sep 8, 2024
b1c067a
Found a rare case where domain retireved from int is nullptr. happens…
Zylence Sep 29, 2024
d60cc6d
fixed an include in feature_extraction.cpp
Zylence Mar 21, 2025
1ab88b8
* fixing problems during build for macos
Mar 26, 2025
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ build/
res/
vendor/
CMakeCache.txt
CMakeSettings.json
CMakeFiles
CMakeScripts
cmake_install.cmake
Expand All @@ -24,6 +25,7 @@ CMakeLists.txt.user
*.err
.vscode/c_cpp_properties.json
.vscode/ipch
.vs/
tests/output
tests/env
tests/.pytest_cache
Expand Down
2 changes: 2 additions & 0 deletions cmake/targets/libmzn.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ add_library(mzn
lib/copy.cpp
lib/exception.cpp
lib/eval_par.cpp
lib/feature_extraction.cpp
lib/file_utils.cpp
lib/flatten.cpp
lib/flatten/flat_exp.cpp
Expand Down Expand Up @@ -81,6 +82,7 @@ add_library(mzn
include/minizinc/copy.hh
include/minizinc/eval_par.hh
include/minizinc/exception.hh
include/minizinc/feature_extraction.hh
include/minizinc/file_utils.hh
include/minizinc/flat_exp.hh
include/minizinc/flatten.hh
Expand Down
7 changes: 7 additions & 0 deletions docs/en/command_line.rst
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ These options control the general behaviour of the ``minizinc`` tool.

Print statistics for compilation.

.. option:: --feature-vector, --feature-vector <(\\d*v)?(\\d*c)?(f)?>

Extract and print feature vector of the FlatZinc model.
Allows configuration of the feature-extraction process.
[0-9]+v limits variables in constraint graph, [0-9]+c limits constraints in constraint graph, f ignores floats.
By default uses ""0v0cf"" which will not apply padding / cropping to the constraint graph and will ignore floats.

.. option:: -c, --compile

Compile only (do not run solver).
Expand Down
110 changes: 110 additions & 0 deletions include/minizinc/feature_extraction.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#pragma once
#include <minizinc/model.hh>
#include <regex>

namespace MiniZinc {

static std::regex featureVectorOptionsRegex("(\\d*v)?(\\d*c)?(f)?", std::regex_constants::ECMAScript |
std::regex_constants::icase);

/// Feature Vector of the FlatModel
struct FlatModelFeatureVector {
/// Number of integer variables
int n_int_vars; // NOLINT(readability-identifier-naming)
/// Number of bool variables
int n_bool_vars; // NOLINT(readability-identifier-naming)
/// Number of set variables
int n_set_vars; // NOLINT(readability-identifier-naming)
/// Number of bool constraints
int n_bool_ct; // NOLINT(readability-identifier-naming)
/// Number of integer constraints
int n_int_ct; // NOLINT(readability-identifier-naming)
/// Number of set constraints
int n_set_ct; // NOLINT(readability-identifier-naming)

double std_dev_domain_size;
double avg_domain_size;
double median_domain_size;
double avg_domain_overlap;
double avg_decision_vars_in_cts;
int n_disjoint_domain_pairs;
int n_meta_ct;
int n_total_ct;
std::string constraint_graph;
std::map<std::string, int> ct_histogram;
std::map<std::string, int> ann_histogram;
std::vector<long long> domain_widths; // indices in this array match keys in customIdToVarNameMap

// mainly for debugging purposes
// it's important that the IDs are consecutive [0, 1, ..] , so we can not use idn() here
// example: we want the first variable defined in the file to have id 0, the second one 1 ...
// same goes for constraints, the first constraint gets id 0
std::map<int, std::string> customIdToVarNameMap;
std::map<int, std::string> customIdToConstraintNameMap;


/// Constructor
FlatModelFeatureVector()
: n_int_vars(0),
n_bool_vars(0),
n_set_vars(0),
n_bool_ct(0),
n_int_ct(0),
n_set_ct(0),
std_dev_domain_size(0),
avg_domain_size(0),
median_domain_size(0),
avg_domain_overlap(0),
avg_decision_vars_in_cts(0),
n_disjoint_domain_pairs(0),
n_meta_ct(0),
n_total_ct(0),
constraint_graph(""),
customIdToVarNameMap(),
customIdToConstraintNameMap(),
ct_histogram(),
ann_histogram(),
domain_widths()
{}

struct Options {
int vDimensions = -1; // for making uniform dimensions of the constraint graph. -1 will not apply padding / cropping
int cDimensions = -1;
bool ignoreFloats = true; // decide whether to ignore floats in all features

static Options parse_from_string(const std::string input) {
Options opts;

std::smatch match;
std::regex_match(input, match, featureVectorOptionsRegex);
std::string vars_limit = match[1].str();
std::string constraints_limit = match[2].str();

auto vpos = vars_limit.find_last_of('v');
auto cpos = constraints_limit.find_last_of('c');

if (vpos != std::string::npos) {
vars_limit = vars_limit.erase(vpos, std::string::npos);
}
if (cpos != std::string::npos) {
constraints_limit = constraints_limit.erase(cpos, std::string::npos);
}

opts.vDimensions = atoi(vars_limit.c_str());
opts.cDimensions = atoi(constraints_limit.c_str());
opts.ignoreFloats = match[3].matched;

return opts;
}

static bool is_valid_options_regex(const std::string input) {
return std::regex_match(input, featureVectorOptionsRegex);
}
};
};

/// Extract the features for flat model in \a m
FlatModelFeatureVector extract_feature_vector(Env& m, FlatModelFeatureVector::Options& o);

}

16 changes: 15 additions & 1 deletion include/minizinc/flatten.hh
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ struct FlatModelStatistics {
int n_imp_del; // NOLINT(readability-identifier-naming)
/// Number of linear expressions eliminated using path compression
int n_lin_del; // NOLINT(readability-identifier-naming)

double* std_dev_domain_size;
double* avg_domain_size;
double* median_domain_size;
double* avg_domain_overlap;
int* n_disjoint_domain_pairs;
int n_total_ct;

/// Constructor
FlatModelStatistics()
: n_int_vars(0),
Expand All @@ -163,7 +171,13 @@ struct FlatModelStatistics {
n_reif_ct(0),
n_imp_ct(0),
n_imp_del(0),
n_lin_del(0) {}
n_lin_del(0),
std_dev_domain_size(nullptr), // nullptrs instead 0, because 0 is within the valid range of values
avg_domain_size(nullptr),
median_domain_size(nullptr),
avg_domain_overlap(nullptr),
n_disjoint_domain_pairs(nullptr),
n_total_ct(0) {}
};

/// Compute statistics for flat model in \a m
Expand Down
6 changes: 6 additions & 0 deletions include/minizinc/flattener.hh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <minizinc/timer.hh>
#include <minizinc/typecheck.hh>
#include <minizinc/utils.hh>
#include <minizinc/feature_extraction.hh>

#include <ctime>
#include <iomanip>
Expand Down Expand Up @@ -65,6 +66,10 @@ public:
bool getFlagVerbose() const { return _flags.verbose; }
void setFlagStatistics(bool f) { _flags.statistics = f; }
bool getFlagStatistics() const { return _flags.statistics; }
void setFlagFeatureVector(FlatModelFeatureVector::Options* options) {
_flags.featureVector = options;
}
FlatModelFeatureVector::Options* getFlagFeatureVector() { return _flags.featureVector; }
void setFlagEncapsulateJSON(bool f) { _flags.encapsulateJSON = f; }
bool getFlagEncapsulateJSON() const { return _flags.encapsulateJSON; }
void setRandomSeed(long unsigned int r) { _fopts.randomSeed = r; }
Expand Down Expand Up @@ -102,6 +107,7 @@ private:
bool allowUnboundedVars = false;
bool noMIPdomains = false;
bool statistics = false;
FlatModelFeatureVector::Options* featureVector = nullptr;
bool stdinInput = false;
bool allowMultiAssign = false;
bool gecode = false;
Expand Down
4 changes: 4 additions & 0 deletions include/minizinc/solver.hh
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
#include <minizinc/flattener.hh>
#include <minizinc/solver_config.hh>
#include <minizinc/solver_instance_base.hh>
#include <minizinc/feature_extraction.hh>

#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include <vector>


namespace MiniZinc {

class SolverInitialiser {
Expand Down Expand Up @@ -164,6 +166,8 @@ public:
bool flagStatistics = false;
bool flagCompilerVerbose = false;
bool flagCompilerStatistics = false;
bool flagFeatureVector = false;
FlatModelFeatureVector::Options featureVectorOptions;
bool flagEncapsulateJSON = false;
bool flagIsSolns2out = false;
std::chrono::milliseconds flagOverallTimeLimit = std::chrono::milliseconds(0);
Expand Down
91 changes: 89 additions & 2 deletions include/minizinc/statistics.hh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#pragma once

#include <iterator>
#include <map>

namespace MiniZinc {

Expand All @@ -22,6 +23,18 @@ private:
bool _json;
bool _first = true;
std::ios _ios;
std::string _jsonType;
std::string _prefix;
std::string _endMarker;

template <typename T>
void serializeValue(std::ostream& os, const T& value) {
if constexpr (std::is_arithmetic<T>::value) {
os << value;
} else {
os << "\"" << value << "\"";
}
}

template <class T>
void addInternal(const std::string& stat, const T& value) {
Expand All @@ -33,12 +46,76 @@ private:
}
_os << "\"" << Printer::escapeStringLit(stat) << "\": " << value;
} else {
_os << "%%%mzn-stat: " << stat << "=" << value << "\n";
_os << _prefix << stat << "=" << value << "\n";
}
}

template <class T>
void addArrayInternal(const std::string& stat, const std::vector<T>& value) {
if (_json) {
if (_first) {
_first = false;
} else {
_os << ", ";
}
_os << "\"" << Printer::escapeStringLit(stat) << "\": [";
for (size_t i = 0; i < value.size(); ++i) {
if (i > 0) {
_os << ", ";
}
serializeValue(_os, value[i]);
}
_os << "]";
} else {
_os << _prefix << stat << "=[";
for (size_t i = 0; i < value.size(); ++i) {
if (i > 0) {
_os << ", ";
}
_os << value[i];
}
_os << "]\n";
}
}

template <class K, class V>
void addMapInternal(const std::string& stat, const std::map<K, V>& value) {
if (_json) {
if (_first) {
_first = false;
} else {
_os << ", ";
}
_os << "\"" << Printer::escapeStringLit(stat) << "\": {";
bool firstElem = true;
for (const auto& pair : value) {
if (!firstElem) {
_os << ", ";
}
firstElem = false;
_os << "\"" << pair.first << "\": ";
serializeValue(_os, pair.second);
}
_os << "}";
} else {
_os << _prefix << stat << "={";
bool firstElem = true;
for (const auto& pair : value) {
if (!firstElem) {
_os << ", ";
}
firstElem = false;
_os << pair.first << ": " << pair.second;
}
_os << "}\n";
}
}

public:
StatisticsStream(std::ostream& os, bool json = false);
StatisticsStream(std::ostream& os, bool json = false,
std::string jsonType = "statistics",
std::string linePrefix = "%%%mzn-stat: ",
std::string outputEndMarker = "%%%mzn-stat-end");
~StatisticsStream();

void precision(std::streamsize prec, bool fixed = false);
Expand All @@ -52,6 +129,16 @@ public:
void add(const std::string& stat, double value);
void add(const std::string& stat, const std::string& value);
void addRaw(const std::string& stat, const std::string& value);

template <class T>
void addArray(const std::string& stat, const std::vector<T>& value) {
addArrayInternal(stat, value);
}

template <class K, class V>
void addMap(const std::string& stat, const std::map<K, V>& value) {
addMapInternal(stat, value);
}
};

class Statistics {
Expand Down
Loading