Z3 최적화 프로그램을 사용하여 그래프 분할 문제를 해결하려고 할 때 문제가 있습니다. 나는 minimize
명령을 제거하면Z3 Optimizer C++ API를 사용하여 실제 제약 조건으로 불만족 가능
namespace z3 {
expr ite(context& con, expr cond, expr then_, expr else_) {
return to_expr(con, Z3_mk_ite(con, cond, then_, else_));;
}
}
bool smtPart(void) {
// Graph setup
vector<int32_t> nodes = {{ 4, 2, 1, 1 }};
vector<tuple<node_pos_t, node_pos_t, int32_t>> edges;
GraphType graph(nodes, edges);
// Z3 setup
z3::context con;
z3::optimize opt(con);
string n_str = "n", sub_p_str = "_p";
// Re-usable constants
z3::expr zero = con.int_val(0);
// Create the sort representing the different partitions.
const char* part_sort_names[2] = { "P0", "P1" };
z3::func_decl_vector part_consts(con), part_preds(con);
z3::sort part_sort =
con.enumeration_sort("PartID",
2,
part_sort_names,
part_consts,
part_preds);
// Create the constants that represent partition choices.
vector<z3::expr> part_vars;
part_vars.reserve(graph.numNodes());
z3::expr p0_acc = zero,
p1_acc = zero;
typename GraphType::NodeData total_weight = typename GraphType::NodeData();
for (const auto& node : graph.nodes()) {
total_weight += node.data;
ostringstream name;
name << n_str << node.id << sub_p_str;
z3::expr nchoice = con.constant(name.str().c_str(), part_sort);
part_vars.push_back(nchoice);
p0_acc = p0_acc + z3::ite(con,
nchoice == part_consts[0](),
con.int_val(node.data),
zero);
p1_acc = p1_acc + z3::ite(con,
nchoice == part_consts[1](),
con.int_val(node.data),
zero);
}
z3::expr imbalance = con.int_const("imbalance");
opt.add(imbalance ==
z3::ite(con,
p0_acc > p1_acc,
p0_acc - p1_acc,
p1_acc - p0_acc));
z3::expr imbalance_limit = con.real_val(total_weight, 100);
opt.add(imbalance <= imbalance_limit);
z3::expr edge_cut = zero;
for(const auto& edge : graph.edges()) {
edge_cut = edge_cut +
z3::ite(con,
(part_vars[edge.node0().pos()] ==
part_vars[edge.node1().pos()]),
zero,
con.int_val(edge.data));
}
opt.minimize(edge_cut);
opt.minimize(imbalance);
z3::check_result opt_result = opt.check();
if (opt_result == z3::check_result::sat) {
auto mod = opt.get_model();
size_t node_id = 0;
for (z3::expr& npv : part_vars) {
cout << "Node " << node_id++ << ": " << mod.eval(npv) << endl;
}
return true;
} else if (opt_result == z3::check_result::unsat) {
cerr << "Constraints are unsatisfiable." << endl;
return false;
} else {
cerr << "Result is unknown." << endl;
return false;
}
}
을하고 0 불균형 만족스러운 모델을 찾을 것이다 optimize
대신 solver
를 사용 특히, 코드 우는 소리는 만족스러운 모델을 생산하기 위해 실패합니다.
- 는 정수로 불균형 제한 환원 확인 제약
imbalance <= imbalance_limit
또는 를 제거 : 나는 또한 어느 경우
optimize
가 만족스러운 모델을 찾을 수 있습니다. 이 예에서 총 무게는 8입니다. 불균형 한도를 8/1, 8/2, 8/4 또는 8/8로 설정하면 옵티마이 저가 만족스러운 모델을 찾습니다.
나는 to_real(imbalance) <= imbalance_limit
을 사용해 보았습니다. 나는 또한 Z3이 실수 논리에 대한 이론을 포함하지 않는 잘못된 논리를 사용하고있을 가능성을 고려했지만 C/C++ API를 사용하여이를 설정하는 방법을 찾지 못했습니다.
누가 내게 진정한 가치가있는 제약 조건 하에서 최적화가 실패했는지 또는 내 인코딩의 개선을 제안 할 수 있는지 말해 줄 수 있다면 많은 도움이 될 것입니다. 미리 감사드립니다.
코드를 컴파일하는 데 문제가 있습니다. #include 지시문은 무엇을 사용하고 있습니까? 어떤 네임 스페이스입니까? 어떤 컴파일러와 링커 플래그? –
필자는이 코드를 컴파일하고 컴파일하기위한 것이 아닙니다. 이것은 여기에 사용 된 많은 것들을 정의하는 훨씬 더 큰 프로젝트의 일부입니다. 이것에 시간을내어 주셔서 감사합니다. 그러나 이것은 버그였습니다. 자세한 내용은 내 대답을 참조하십시오. –
OK, Z3에서 버그를 찾는 데 좋은 작업입니다. –