<commit_before>#include "qif"

using std::cout;
using std::vector;
using std::string;

using namespace qif;
using namespace qif::measure;


void compute_optimal(string method) {
	if(method != "direct" && method != "kostas" && method != "geometric")
		throw std::runtime_error("invalid method: " + method);

	lp::Defaults::method = lp::Method::SIMPLEX_DUAL;
	lp::Defaults::msg_level = lp::MsgLevel::ALL;
	lp::Defaults::presolve = true;

	double unit = 1;
	double eps = std::log(2) / (2*unit);
	uint width = 8,
		 n_inputs = width * width,
		 n_outputs = n_inputs;
	double R = 2.2 * unit;								// the R and rho for
	double rho = unit * std::sqrt(2)/2;					// Kostas' method

	auto d_grid = unit * metric::grid<double>(width);	// d_grid(i, j) = euclidean distance between cell indices i,j
	auto d_loss = d_grid;								// loss metric = euclidean
	auto dx = d_grid;									// privacy metric

	// Note: we're _not_ using a 'chainable' function for d_grid to remove constraints that are reduntant due to transitivity

	if(method == "kostas") {
		// use more relexed dx and update eps
		//
		dx = metric::threshold_inf(d_grid, R);			// inf if above threshold R

		// Catuscia's crazy formula
		double c = R / rho;
		double c2 = c * c;
		double delta = (c - 1) / std::sqrt(
			c2 - 2*c - 3 + 4/c + 1/c2
		);
		cout << "delta: " << delta << "\n";

		eps /= delta;									// update eps to compensate for the use of a bigger dx
	}

	prob pi = probab::uniform<double>(n_inputs);		// uniform prior
	chan C = method == "geometric"
		? mechanism::geo::planar_geometric_grid<double>(width, width, unit, eps)
		: mechanism::d_privacy::min_loss_given_d(pi, n_outputs, eps * dx, d_loss);

	cout << "size: " << C.n_rows << "\n";
	cout << "proper: " << channel::is_proper(C) << "\n";
	cout << "util : " << l_risk::posterior(d_loss, pi, C) << "\n";	// expected d_loss between x and y

	// apply optimal remap (probably does nothing for uniform priors)
	mat Loss = l_risk::metric_to_mat(d_loss, n_inputs);
	chan Remap = channel::deterministic<double>(l_risk::strategy(Loss, pi, C), Loss.n_rows);	// compute remap
	cout << "util after remap : " << l_risk::posterior(d_loss, pi, (chan)(C*Remap)) << "\n";
}

int main(int argc, char *argv[]) {
	vector<string> args(argv+1, argv + argc);


//	compute_optimal("direct");
//	compute_optimal("geometric");
	compute_optimal("kostas");
}

<commit_msg>optimal-ValueTools17: adapt to API change<commit_after>#include "qif"

using std::cout;
using std::vector;
using std::string;

using namespace qif;
using namespace qif::measure;


void compute_optimal(string method) {
	if(method != "direct" && method != "kostas" && method != "geometric")
		throw std::runtime_error("invalid method: " + method);

	lp::Defaults::method = lp::Method::SIMPLEX_DUAL;
	lp::Defaults::msg_level = lp::MsgLevel::ALL;
	lp::Defaults::presolve = true;

	double unit = 1;
	double eps = std::log(2) / (2*unit);
	uint width = 8,
		 n_inputs = width * width,
		 n_outputs = n_inputs;
	double R = 2.2 * unit;								// the R and rho for
	double rho = unit * std::sqrt(2)/2;					// Kostas' method

	auto d_grid = unit * metric::grid<double>(width);	// d_grid(i, j) = euclidean distance between cell indices i,j
	auto d_loss = d_grid;								// loss metric = euclidean
	auto dx = d_grid;									// privacy metric

	// Note: we're _not_ using a 'chainable' function for d_grid to remove constraints that are reduntant due to transitivity

	if(method == "kostas") {
		// use more relexed dx and update eps
		//
		dx = metric::threshold_inf(d_grid, R);			// inf if above threshold R

		// Catuscia's crazy formula
		double c = R / rho;
		double c2 = c * c;
		double delta = (c - 1) / std::sqrt(
			c2 - 2*c - 3 + 4/c + 1/c2
		);
		cout << "delta: " << delta << "\n";

		eps /= delta;									// update eps to compensate for the use of a bigger dx
	}

	prob pi = probab::uniform<double>(n_inputs);		// uniform prior
	chan C = method == "geometric"
		? mechanism::geo::planar_geometric_grid<double>(width, width, unit, eps)
		: mechanism::d_privacy::min_loss_given_d(pi, n_outputs, eps * dx, d_loss);

	cout << "size: " << C.n_rows << "\n";
	cout << "proper: " << channel::is_proper(C) << "\n";
	cout << "util : " << l_risk::posterior(d_loss, pi, C) << "\n";	// expected d_loss between x and y

	// apply optimal remap (probably does nothing for uniform priors)
	mat Loss = metric::to_distance_matrix(d_loss, n_inputs);
	chan Remap = channel::deterministic<double>(l_risk::strategy(Loss, pi, C), Loss.n_rows);	// compute remap
	cout << "util after remap : " << l_risk::posterior(d_loss, pi, (chan)(C*Remap)) << "\n";
}

int main(int argc, char *argv[]) {
	vector<string> args(argv+1, argv + argc);


//	compute_optimal("direct");
//	compute_optimal("geometric");
	compute_optimal("kostas");
}


{'fraction_non_alphanumeric': 0.1623770663318686, 'fraction_numerical': 0.007532956685499058, 'mean_word_length': 3.732673267326733, 'pattern_counts': {'":': 0, '<': 73, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5537451', 'n_tokens_mistral': 1895, 'n_tokens_neox': 1696, 'n_words': 480}