examples/ar-vineyard/ar-function-kernel.hpp
author Christos Mantoulidis <cmad@stanford.edu>
Tue, 04 Aug 2009 13:23:16 -0700
branchdev
changeset 156 f75fb57d2831
parent 74 79ee020341aa
permissions -rw-r--r--
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;
}