in src/core/symbolic.cpp [598:652]
Constraint isolate(const Constraint& c, const Symbol& sym) {
const auto& lhs = c.first;
const auto& rhs = c.second;
if (!lhs.contains(sym) && rhs.contains(sym)) {
return isolate(std::make_pair(rhs, lhs), sym);
}
ASSERT(lhs.contains(sym) && !rhs.contains(sym))
<< "cannot isolate with variable on both rhs and lhs of constraint yet: "
<< lhs.dump() << " = " << rhs.dump() << " for sym " << Expr(sym).dump();
if (lhs == Expr(sym)) {
return std::make_pair(lhs, rhs);
}
if (lhs.type() == Expr::Type::function) {
ASSERT(can_isolate(lhs, sym))
<< "cannot isolate " << sym.name() << " through " << lhs.dump()
<< ", you may need to update the can_isolate function";
switch (lhs.op()) {
case Op::add: {
auto llhs = lhs.args().at(0);
auto lrhs = lhs.args().at(1);
if (llhs.contains(sym)) {
return isolate(std::make_pair(llhs, rhs - lrhs), sym);
}
return isolate(std::make_pair(lrhs, rhs - llhs), sym);
}
case Op::multiply: {
auto llhs = lhs.args().at(0);
auto lrhs = lhs.args().at(1);
if (llhs.contains(sym)) {
return isolate(std::make_pair(llhs, rhs / lrhs), sym);
}
ASSERT(lrhs.contains(sym));
return isolate(std::make_pair(lrhs, rhs / llhs), sym);
}
case Op::divide: {
auto llhs = lhs.args().at(0);
auto lrhs = lhs.args().at(1);
if (llhs.contains(sym)) {
return isolate(std::make_pair(llhs, rhs * lrhs), sym);
}
return isolate(std::make_pair(lrhs, rhs * llhs), sym);
}
case Op::negate:
return isolate(std::make_pair(lhs.args().at(0), -rhs), sym);
case Op::reciprocal:
return isolate(std::make_pair(lhs.args().at(0), Expr(1) / rhs), sym);
default:
ASSERT(0) << "cannot isolate through " << lhs.dump();
}
}
ASSERT(0) << "error isolating for " << sym.name() << " in constraint "
<< lhs.dump() << " = " << rhs.dump();
return std::make_pair(Expr(0), Expr(0));
}