Changed implementation of WeightedRips to store simplex values (max distance between simplices' vertices) as an invisible layer on top of each simplex object, so that the data() field of WeightedRips has been freed for use by the users again.
#include <utilities/log.h>
#include <cmath>
#if LOGGING
static rlog::RLogChannel* rlARFunctionKernel = DEF_CHANNEL("ar/function-kernel", rlog::Log_Debug);
static rlog::RLogChannel* rlARFunctionKernelValue = DEF_CHANNEL("ar/function-kernel/value", rlog::Log_Debug);
#endif
/* For now only rho and phi are implemented */
void
ARFunctionKernel::
solve(const Function& f, RootStack& stack)
{
AssertMsg(stack.empty(), "Stack must be empty before solving");
AssertMsg((f.form() != Function::none) && (f.form2() != Function::none), "Solving possible only for differences");
FunctionForm f1 = f.form(), f2 = f.form2();
const ARSimplex3D *s1 = f.simplex(),
*s2 = f.simplex2();
if (f1 < f2) { std::swap(f1,f2); std::swap(s1,s2); } // for simplicity enforce function order
// to handle fewer cases explicitly
AssertMsg(f1 != Function::lambda && f2 != Function::lambda, "Lambda not implemented yet");
rLog(rlARFunctionKernel, "Solve: function1 = (%i, %p), function2 = (%i, %p)",
f1, s1, f2, s2);
//if (f1 == Function::phi && f2 == Function::phi) return;
//if (f1 == Function::rho && f2 == Function::rho) return;
if (f1 == Function::phi && f2 == Function::rho)
{
SimplexFieldType r = s2->alpha() - s1->phi_const();
rLog(rlARFunctionKernel, " phi = rho => r^2 = %s (%lf)", tostring(r).c_str(), root(r));
stack.push(root(r));
}
if (f1 == Function::phi && f2 == Function::lambda)
{
rLog(rlARFunctionKernel, " phi = lambda");
SimplexFieldType r2 = (s2->rho() + s2->v() - s2->s() - s1->phi_const());
r2 *= r2;
r2 /= 4*s2->v();
r2 += s2->s();
if (r2 >= s2->s() + s2->v())
stack.push(root(r2));
SimplexFieldType r1 = s2->rho() - s1->phi_const();
if (r1 <= s2->s() + s2->v())
stack.push(root(r1));
}
// FIXME: this is far from complete!
if (f1 == Function::lambda && f2 == Function::lambda)
{
rLog(rlARFunctionKernel, " lambda = lambda");
if ((s1->s() + s1->v() < s2->s() + s2->v())) // let f1 be the function with larger break point
{ std::swap(f1,f2); std::swap(s1,s2); }
if (s1->rho() > s2->rho())
{
RootType r = root(s2->s() + s2->v() + s1->rho() - s2->rho()) + 2*sqrt(root(s2->v()*(s1->rho() - s2->rho())));
if (r < root(s1->s() + s1->v()) && r > root(s2->s() + s2->v()))
stack.push(r);
}
}
if (f1 == Function::lambda && f2 == Function::rho)
{
rLog(rlARFunctionKernel, " lambda = rho");
// perhaps no solutions instead of an assertion is the right way to deal with this
AssertMsg(s2->alpha() > s1->rho(), "Rho_0^2 must be greater than Rho^2");
RootType r = sqrt(root(s2->v()*(s2->alpha() - s1->rho()))); // damn square roots
r *= 2;
r += root(s1->s() + s1->v() + s2->alpha() - s1->rho());
}
rLog(rlARFunctionKernel, " Stack size: %i", stack.size());
if (stack.size() > 0) rLog(rlARFunctionKernel, " Top: %lf", stack.top());
}
int
ARFunctionKernel::
sign_at(const Function& f, RootType r)
{
FieldType v = value_at(f,r);
if (v > 0) return true;
else return false;
}
int
ARFunctionKernel::
sign_at_negative_infinity(const Function& f)
{
FunctionForm f1 = f.form(), f2 = f.form2();
const ARSimplex3D *s1 = f.simplex(),
*s2 = f.simplex2();
int multiplier = 1;
if (f1 < f2) { std::swap(f1, f2); std::swap(s1, s2); multiplier = -1; }
AssertMsg(f1 != Function::lambda && f2 != Function::lambda, "Lambda not implemented yet");
if (f1 == Function::phi && f2 == Function::phi)
{
if (s1->phi_const() == s2->phi_const()) return 0;
if (s1->phi_const() > s2->phi_const()) return 1; // multiplier must be 1
else return -1;
}
if (f1 == Function::phi && f2 == Function::rho)
return -multiplier;
if (f1 == Function::rho && f2 == Function::rho)
{
if (s1->alpha() == s2->alpha()) return 0;
if (s1->alpha() > s2->alpha()) return 1; // multiplier must be 1
else return -1;
}
AssertMsg(false, "The case analysis should be exhaustive in sign at -infinity");
return false;
}
ARFunctionKernel::FieldType
ARFunctionKernel::
value_at(const Function& f, RootType v)
{
FunctionForm f1 = f.form(), f2 = f.form2();
ARSimplex3D *s1 = f.simplex(),
*s2 = f.simplex2();
AssertMsg(f2 == Function::none && s2 == 0, "Value_at knows only about functions themselves, not their differences");
AssertMsg(f1 != Function::lambda, "Lambda not implemented yet");
rLog(rlARFunctionKernelValue, "Value_at: function = (%i, %p)", f1, s1);
if (f1 == Function::phi)
return v + root(s1->phi_const());
if (f1 == Function::rho)
return root(s1->alpha());
AssertMsg(false, "The case analysis should be exhaustive in value_at");
return 0;
}