<commit_before>#include <map>

// ignore unused parameters in LLVM libraries
#if (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#include <llvm/IR/Value.h>
#include <llvm/IR/Instruction.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/IntrinsicInst.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/Support/raw_ostream.h>

#if (__clang__)
#pragma clang diagnostic pop // ignore -Wunused-parameter
#else
#pragma GCC diagnostic pop
#endif

#include "llvm/LLVMNode.h"
#include "llvm/LLVMDependenceGraph.h"
#include "llvm/llvm-utils.h"

#include "llvm/analysis/PointsTo/PointsTo.h"
#include "ReachingDefinitions/ReachingDefinitions.h"
#include "DefUse.h"

#include "analysis/PointsTo/PointerSubgraph.h"
#include "analysis/DFS.h"

using dg::analysis::rd::LLVMReachingDefinitions;
using dg::analysis::rd::RDNode;

using namespace llvm;

/// --------------------------------------------------
//   Add def-use edges
/// --------------------------------------------------
namespace dg {

static void handleInstruction(const Instruction *Inst, LLVMNode *node)
{
    LLVMDependenceGraph *dg = node->getDG();

    for (auto I = Inst->op_begin(), E = Inst->op_end(); I != E; ++I) {
        LLVMNode *op = dg->getNode(*I);
        if (op)
            op->addDataDependence(node);
    }
}

static void addReturnEdge(LLVMNode *callNode, LLVMDependenceGraph *subgraph)
{
    // FIXME we may loose some accuracy here and
    // this edges causes that we'll go into subprocedure
    // even with summary edges
    if (!callNode->isVoidTy())
        subgraph->getExit()->addDataDependence(callNode);
}

LLVMDefUseAnalysis::LLVMDefUseAnalysis(LLVMDependenceGraph *dg,
                                       LLVMReachingDefinitions *rd,
                                       LLVMPointerAnalysis *pta,
                                       bool assume_pure_funs)
    : analysis::DataFlowAnalysis<LLVMNode>(dg->getEntryBB(),
                                           analysis::DATAFLOW_INTERPROCEDURAL),
      dg(dg), RD(rd), PTA(pta), DL(new DataLayout(dg->getModule())),
      assume_pure_functions(assume_pure_funs)
{
    assert(PTA && "Need points-to information");
    assert(RD && "Need reaching definitions");
}

void LLVMDefUseAnalysis::handleInlineAsm(LLVMNode *callNode)
{
    CallInst *CI = cast<CallInst>(callNode->getValue());
    LLVMDependenceGraph *dg = callNode->getDG();

    // the last operand is the asm itself, so iterate only to e - 1
    for (unsigned i = 0, e = CI->getNumOperands(); i < e - 1; ++i) {
        Value *opVal = CI->getOperand(i);
        if (!opVal->getType()->isPointerTy())
            continue;

        LLVMNode *opNode = dg->getNode(opVal->stripInBoundsOffsets());
        if (!opNode) {
            // FIXME: ConstantExpr
            llvmutils::printerr("WARN: unhandled inline asm operand: ", opVal);
            continue;
        }

        assert(opNode && "Do not have an operand for inline asm");

        // if nothing else, this call at least uses the operands
        opNode->addDataDependence(callNode);
    }
}

void LLVMDefUseAnalysis::handleIntrinsicCall(LLVMNode *callNode,
                                             CallInst *CI)
{
    static std::set<Instruction *> warnings;
    IntrinsicInst *I = cast<IntrinsicInst>(CI);
    Value *dest, *src = nullptr;

    switch (I->getIntrinsicID())
    {
        case Intrinsic::memmove:
        case Intrinsic::memcpy:
            dest = I->getOperand(0);
            src = I->getOperand(1);
            break;
        case Intrinsic::memset:
            dest = I->getOperand(0);
            break;
        case Intrinsic::vastart:
            dest = I->getOperand(0);
            break;
        case Intrinsic::vaend:
        case Intrinsic::lifetime_start:
        case Intrinsic::lifetime_end:
        case Intrinsic::trap:
        case Intrinsic::bswap:
        case Intrinsic::prefetch:
        case Intrinsic::objectsize:
            // nothing to be done, direct def-use edges
            // will be added later
            return;
        case Intrinsic::stacksave:
        case Intrinsic::stackrestore:
            if (warnings.insert(CI).second)
                llvmutils::printerr("WARN: stack save/restore not implemented", CI);
            return;
        default:
            I->dump();
            assert(0 && "DEF-USE: Unhandled intrinsic call");
            handleUndefinedCall(callNode, CI);
            return;
    }

    // we must have dest set
    assert(dest);

    // these functions touch the memory of the pointers
    addDataDependence(callNode, CI, dest, UNKNOWN_OFFSET /* FIXME */);

    if (src)
        addDataDependence(callNode, CI, src, UNKNOWN_OFFSET /* FIXME */);
}

void LLVMDefUseAnalysis::handleUndefinedCall(LLVMNode *callNode, CallInst *CI)
{
    if (assume_pure_functions)
        return;

    // the function is undefined - add the top-level dependencies and
    // also assume that this function use all the memory that is passed
    // via the pointers
    for (int e = CI->getNumArgOperands(), i = 0; i < e; ++i) {
        if (auto pts = PTA->getPointsTo(CI->getArgOperand(i))) {
            // the passed memory may be used in the undefined
            // function on the unknown offset
            addDataDependence(callNode, CI, pts, UNKNOWN_OFFSET);
        }
    }
}

void LLVMDefUseAnalysis::handleCallInst(LLVMNode *node)
{
    CallInst *CI = cast<CallInst>(node->getKey());

    if (CI->isInlineAsm()) {
        handleInlineAsm(node);
        return;
    }

    Function *func
        = dyn_cast<Function>(CI->getCalledValue()->stripPointerCasts());
    if (func) {
        if (func->isIntrinsic() && !isa<DbgInfoIntrinsic>(CI)) {
            handleIntrinsicCall(node, CI);
            return;
        }

        // for realloc, we need to make it data dependent on the
        // memory it reallocates, since that is the memory it copies
        if (func->size() == 0) {
            const char *name = func->getName().data();
            if (strcmp(name, "realloc") == 0) {
                addDataDependence(node, CI, CI->getOperand(0), UNKNOWN_OFFSET /* FIXME */);
            } else if (strcmp(name, "malloc") == 0 ||
                       strcmp(name, "calloc") == 0 ||
                       strcmp(name, "alloca") == 0) {
                // we do not want to do anything for the memory
                // allocation functions
            } else {
                handleUndefinedCall(node, CI);
            }

            // the function is undefined, so do not even try to
            // add the edges from return statements
            return;
        }
    }

    // add edges from the return nodes of subprocedure
    // to the call (if the call returns something)
    for (LLVMDependenceGraph *subgraph : node->getSubgraphs())
        addReturnEdge(node, subgraph);
}

// Add data dependence edges from all memory location that may write
// to memory pointed by 'pts' to 'node'
void LLVMDefUseAnalysis::addUnknownDataDependence(LLVMNode *node, PSNode *pts)
{
    // iterate over all nodes from ReachingDefinitions Subgraph. It is faster than
    // going over all llvm nodes and querying the pointer to analysis
    for (auto& it : RD->getNodesMap()) {
        RDNode *rdnode = it.second;

        // only STORE may be a definition site
        if (rdnode->getType() != analysis::rd::RDNodeType::STORE)
            continue;

        llvm::Value *rdVal = rdnode->getUserData<llvm::Value>();
        // artificial node?
        if (!rdVal)
            continue;

        // does this store define some value that is in pts?
        for (const analysis::rd::DefSite& ds : rdnode->getDefines()) {
            llvm::Value *llvmVal = ds.target->getUserData<llvm::Value>();
            // is this an artificial node?
            if (!llvmVal)
                continue;

            // if these two sets have an over-lap, we must add the data dependence
            for (const auto& ptr : pts->pointsTo)
                if (ptr.target->getUserData<llvm::Value>() == llvmVal) {
                    addDataDependence(node, rdVal);
            }
        }
    }
}

void LLVMDefUseAnalysis::addDataDependence(LLVMNode *node, llvm::Value *rdval)
{
    LLVMNode *rdnode = dg->getNode(rdval);
    if (!rdnode) {
        // that means that the value is not from this graph.
        // We need to add interprocedural edge
        llvm::Function *F
            = llvm::cast<llvm::Instruction>(rdval)->getParent()->getParent();
        LLVMNode *entryNode = dg->getGlobalNode(F);
        assert(entryNode && "Don't have built function");

        // get the graph where the node lives
        LLVMDependenceGraph *graph = entryNode->getDG();
        assert(graph != dg && "Cannot find a node");
        rdnode = graph->getNode(rdval);
        if (!rdnode) {
            llvmutils::printerr("ERROR: DG has not val: ", rdval);
            return;
        }
    }

    assert(rdnode);
    rdnode->addDataDependence(node);
}

void LLVMDefUseAnalysis::addDataDependence(LLVMNode *node, RDNode *rd)
{
    llvm::Value *rdval = rd->getUserData<llvm::Value>();
    assert(rdval && "RDNode has not set the coresponding value");
    addDataDependence(node, rdval);
}

// \param mem   current reaching definitions point
void LLVMDefUseAnalysis::addDataDependence(LLVMNode *node, PSNode *pts,
                                           RDNode *mem, uint64_t size)
{
    using namespace dg::analysis;
    static std::set<const llvm::Value *> reported_mappings;

    for (const pta::Pointer& ptr : pts->pointsTo) {
        if (!ptr.isValid())
            continue;

        llvm::Value *llvmVal = ptr.target->getUserData<llvm::Value>();
        assert(llvmVal && "Don't have Value in PSNode");

        RDNode *val = RD->getNode(llvmVal);
        if(!val) {
            if (reported_mappings.insert(llvmVal).second)
                llvmutils::printerr("DEF-USE: no information for: ", llvmVal);

            // XXX: shouldn't we set val to unknown location now?
            continue;
        }

        std::set<RDNode *> defs;
        // Get even reaching definitions for UNKNOWN_MEMORY.
        // Since those can be ours definitions, we must add them always
        mem->getReachingDefinitions(rd::UNKNOWN_MEMORY, UNKNOWN_OFFSET, UNKNOWN_OFFSET, defs);
        if (!defs.empty()) {
            for (RDNode *rd : defs) {
                assert(!rd->isUnknown() && "Unknown memory defined at unknown location?");
                addDataDependence(node, rd);
            }

            defs.clear();
        }

        mem->getReachingDefinitions(val, ptr.offset, size, defs);
        if (defs.empty()) {
            llvm::GlobalVariable *GV
                = llvm::dyn_cast<llvm::GlobalVariable>(llvmVal);
            if (!GV || !GV->hasInitializer()) {
                static std::set<const llvm::Value *> reported;
                if (reported.insert(llvmVal).second) {
                    llvm::errs() << "No reaching definition for: " << *llvmVal
                                 << " off: " << *ptr.offset << "\n";
                }
            }

            continue;
        }

        // add data dependence
        for (RDNode *rd : defs) {
            if (rd->isUnknown()) {
                // we don't know what definitions reach this node,
                // se we must add data dependence to all possible
                // write to this memory
                addUnknownDataDependence(node, pts);

                // we can bail out, since we have added all
                break;
            }

            addDataDependence(node, rd);
        }
    }
}

void LLVMDefUseAnalysis::addDataDependence(LLVMNode *node,
                                           const llvm::Value *where, /* in CFG */
                                           const llvm::Value *ptrOp,
                                           uint64_t size)
{
    // get points-to information for the operand
    PSNode *pts = PTA->getPointsTo(ptrOp);
    //assert(pts && "Don't have points-to information for LoadInst");
    if (!pts) {
        llvmutils::printerr("ERROR: No points-to: ", ptrOp);
        return;
    }

    addDataDependence(node, where, pts, size);
}

void LLVMDefUseAnalysis::addDataDependence(LLVMNode *node,
                                           const llvm::Value *where, /* in CFG */
                                           PSNode *pts, /* what memory */
                                           uint64_t size)
{
    using namespace dg::analysis;

    // get the node from reaching definition where we have
    // all the reaching definitions
    RDNode *mem = RD->getMapping(where);
    if(!mem) {
        llvmutils::printerr("ERROR: Don't have mapping: ", where);
        return;
    }

    // take every memory the load inst can use and get the
    // reaching definition
    addDataDependence(node, pts, mem, size);
}

static uint64_t getAllocatedSize(llvm::Type *Ty, const llvm::DataLayout *DL)
{
    // Type can be i8 *null or similar
    if (!Ty->isSized())
            return UNKNOWN_OFFSET;

    return DL->getTypeAllocSize(Ty);
}

void LLVMDefUseAnalysis::handleLoadInst(llvm::LoadInst *Inst, LLVMNode *node)
{
    using namespace dg::analysis;

    uint64_t size = getAllocatedSize(Inst->getType(), DL);
    addDataDependence(node, Inst, Inst->getPointerOperand(), size);
}

bool LLVMDefUseAnalysis::runOnNode(LLVMNode *node, LLVMNode *prev)
{
    Value *val = node->getKey();
    (void) prev;

    if (LoadInst *Inst = dyn_cast<LoadInst>(val)) {
        handleLoadInst(Inst, node);
    } else if (isa<CallInst>(val)) {
        handleCallInst(node);
    /*} else if (StoreInst *Inst = dyn_cast<StoreInst>(val)) {
        handleStoreInst(Inst, node);*/
    }

    /* just add direct def-use edges to every instruction */
    if (Instruction *Inst = dyn_cast<Instruction>(val))
        handleInstruction(Inst, node);

    // we will run only once
    return false;
}

} // namespace dg
<commit_msg>llvm def-use: use getMemAllocationFunc<commit_after>#include <map>

// ignore unused parameters in LLVM libraries
#if (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#include <llvm/IR/Value.h>
#include <llvm/IR/Instruction.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/IntrinsicInst.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/Support/raw_ostream.h>

#if (__clang__)
#pragma clang diagnostic pop // ignore -Wunused-parameter
#else
#pragma GCC diagnostic pop
#endif

#include "llvm/LLVMNode.h"
#include "llvm/LLVMDependenceGraph.h"
#include "llvm/llvm-utils.h"

#include "llvm/analysis/PointsTo/PointsTo.h"
#include "ReachingDefinitions/ReachingDefinitions.h"
#include "DefUse.h"

#include "analysis/PointsTo/PointerSubgraph.h"
#include "analysis/DFS.h"

using dg::analysis::rd::LLVMReachingDefinitions;
using dg::analysis::rd::RDNode;

using namespace llvm;

/// --------------------------------------------------
//   Add def-use edges
/// --------------------------------------------------
namespace dg {

static void handleInstruction(const Instruction *Inst, LLVMNode *node)
{
    LLVMDependenceGraph *dg = node->getDG();

    for (auto I = Inst->op_begin(), E = Inst->op_end(); I != E; ++I) {
        LLVMNode *op = dg->getNode(*I);
        if (op)
            op->addDataDependence(node);
    }
}

static void addReturnEdge(LLVMNode *callNode, LLVMDependenceGraph *subgraph)
{
    // FIXME we may loose some accuracy here and
    // this edges causes that we'll go into subprocedure
    // even with summary edges
    if (!callNode->isVoidTy())
        subgraph->getExit()->addDataDependence(callNode);
}

LLVMDefUseAnalysis::LLVMDefUseAnalysis(LLVMDependenceGraph *dg,
                                       LLVMReachingDefinitions *rd,
                                       LLVMPointerAnalysis *pta,
                                       bool assume_pure_funs)
    : analysis::DataFlowAnalysis<LLVMNode>(dg->getEntryBB(),
                                           analysis::DATAFLOW_INTERPROCEDURAL),
      dg(dg), RD(rd), PTA(pta), DL(new DataLayout(dg->getModule())),
      assume_pure_functions(assume_pure_funs)
{
    assert(PTA && "Need points-to information");
    assert(RD && "Need reaching definitions");
}

void LLVMDefUseAnalysis::handleInlineAsm(LLVMNode *callNode)
{
    CallInst *CI = cast<CallInst>(callNode->getValue());
    LLVMDependenceGraph *dg = callNode->getDG();

    // the last operand is the asm itself, so iterate only to e - 1
    for (unsigned i = 0, e = CI->getNumOperands(); i < e - 1; ++i) {
        Value *opVal = CI->getOperand(i);
        if (!opVal->getType()->isPointerTy())
            continue;

        LLVMNode *opNode = dg->getNode(opVal->stripInBoundsOffsets());
        if (!opNode) {
            // FIXME: ConstantExpr
            llvmutils::printerr("WARN: unhandled inline asm operand: ", opVal);
            continue;
        }

        assert(opNode && "Do not have an operand for inline asm");

        // if nothing else, this call at least uses the operands
        opNode->addDataDependence(callNode);
    }
}

void LLVMDefUseAnalysis::handleIntrinsicCall(LLVMNode *callNode,
                                             CallInst *CI)
{
    static std::set<Instruction *> warnings;
    IntrinsicInst *I = cast<IntrinsicInst>(CI);
    Value *dest, *src = nullptr;

    switch (I->getIntrinsicID())
    {
        case Intrinsic::memmove:
        case Intrinsic::memcpy:
            dest = I->getOperand(0);
            src = I->getOperand(1);
            break;
        case Intrinsic::memset:
            dest = I->getOperand(0);
            break;
        case Intrinsic::vastart:
            dest = I->getOperand(0);
            break;
        case Intrinsic::vaend:
        case Intrinsic::lifetime_start:
        case Intrinsic::lifetime_end:
        case Intrinsic::trap:
        case Intrinsic::bswap:
        case Intrinsic::prefetch:
        case Intrinsic::objectsize:
            // nothing to be done, direct def-use edges
            // will be added later
            return;
        case Intrinsic::stacksave:
        case Intrinsic::stackrestore:
            if (warnings.insert(CI).second)
                llvmutils::printerr("WARN: stack save/restore not implemented", CI);
            return;
        default:
            I->dump();
            assert(0 && "DEF-USE: Unhandled intrinsic call");
            handleUndefinedCall(callNode, CI);
            return;
    }

    // we must have dest set
    assert(dest);

    // these functions touch the memory of the pointers
    addDataDependence(callNode, CI, dest, UNKNOWN_OFFSET /* FIXME */);

    if (src)
        addDataDependence(callNode, CI, src, UNKNOWN_OFFSET /* FIXME */);
}

void LLVMDefUseAnalysis::handleUndefinedCall(LLVMNode *callNode, CallInst *CI)
{
    if (assume_pure_functions)
        return;

    // the function is undefined - add the top-level dependencies and
    // also assume that this function use all the memory that is passed
    // via the pointers
    for (int e = CI->getNumArgOperands(), i = 0; i < e; ++i) {
        if (auto pts = PTA->getPointsTo(CI->getArgOperand(i))) {
            // the passed memory may be used in the undefined
            // function on the unknown offset
            addDataDependence(callNode, CI, pts, UNKNOWN_OFFSET);
        }
    }
}

void LLVMDefUseAnalysis::handleCallInst(LLVMNode *node)
{
    CallInst *CI = cast<CallInst>(node->getKey());

    if (CI->isInlineAsm()) {
        handleInlineAsm(node);
        return;
    }

    Function *func
        = dyn_cast<Function>(CI->getCalledValue()->stripPointerCasts());
    if (func) {
        if (func->isIntrinsic() && !isa<DbgInfoIntrinsic>(CI)) {
            handleIntrinsicCall(node, CI);
            return;
        }

        // for realloc, we need to make it data dependent on the
        // memory it reallocates, since that is the memory it copies
        if (func->size() == 0) {
            using dg::MemAllocationFuncs;
            MemAllocationFuncs type = getMemAllocationFunc(func);

            if (type == MemAllocationFuncs::REALLOC) {
                addDataDependence(node, CI, CI->getOperand(0), UNKNOWN_OFFSET /* FIXME */);
            } else if (type == MemAllocationFuncs::NONEMEM) {
                handleUndefinedCall(node, CI);
            }// else {
             // we do not want to do anything for the memory
             // allocation functions
             // }

            // the function is undefined, so do not even try to
            // add the edges from return statements
            return;
        }
    }

    // add edges from the return nodes of subprocedure
    // to the call (if the call returns something)
    for (LLVMDependenceGraph *subgraph : node->getSubgraphs())
        addReturnEdge(node, subgraph);
}

// Add data dependence edges from all memory location that may write
// to memory pointed by 'pts' to 'node'
void LLVMDefUseAnalysis::addUnknownDataDependence(LLVMNode *node, PSNode *pts)
{
    // iterate over all nodes from ReachingDefinitions Subgraph. It is faster than
    // going over all llvm nodes and querying the pointer to analysis
    for (auto& it : RD->getNodesMap()) {
        RDNode *rdnode = it.second;

        // only STORE may be a definition site
        if (rdnode->getType() != analysis::rd::RDNodeType::STORE)
            continue;

        llvm::Value *rdVal = rdnode->getUserData<llvm::Value>();
        // artificial node?
        if (!rdVal)
            continue;

        // does this store define some value that is in pts?
        for (const analysis::rd::DefSite& ds : rdnode->getDefines()) {
            llvm::Value *llvmVal = ds.target->getUserData<llvm::Value>();
            // is this an artificial node?
            if (!llvmVal)
                continue;

            // if these two sets have an over-lap, we must add the data dependence
            for (const auto& ptr : pts->pointsTo)
                if (ptr.target->getUserData<llvm::Value>() == llvmVal) {
                    addDataDependence(node, rdVal);
            }
        }
    }
}

void LLVMDefUseAnalysis::addDataDependence(LLVMNode *node, llvm::Value *rdval)
{
    LLVMNode *rdnode = dg->getNode(rdval);
    if (!rdnode) {
        // that means that the value is not from this graph.
        // We need to add interprocedural edge
        llvm::Function *F
            = llvm::cast<llvm::Instruction>(rdval)->getParent()->getParent();
        LLVMNode *entryNode = dg->getGlobalNode(F);
        assert(entryNode && "Don't have built function");

        // get the graph where the node lives
        LLVMDependenceGraph *graph = entryNode->getDG();
        assert(graph != dg && "Cannot find a node");
        rdnode = graph->getNode(rdval);
        if (!rdnode) {
            llvmutils::printerr("ERROR: DG has not val: ", rdval);
            return;
        }
    }

    assert(rdnode);
    rdnode->addDataDependence(node);
}

void LLVMDefUseAnalysis::addDataDependence(LLVMNode *node, RDNode *rd)
{
    llvm::Value *rdval = rd->getUserData<llvm::Value>();
    assert(rdval && "RDNode has not set the coresponding value");
    addDataDependence(node, rdval);
}

// \param mem   current reaching definitions point
void LLVMDefUseAnalysis::addDataDependence(LLVMNode *node, PSNode *pts,
                                           RDNode *mem, uint64_t size)
{
    using namespace dg::analysis;
    static std::set<const llvm::Value *> reported_mappings;

    for (const pta::Pointer& ptr : pts->pointsTo) {
        if (!ptr.isValid())
            continue;

        llvm::Value *llvmVal = ptr.target->getUserData<llvm::Value>();
        assert(llvmVal && "Don't have Value in PSNode");

        RDNode *val = RD->getNode(llvmVal);
        if(!val) {
            if (reported_mappings.insert(llvmVal).second)
                llvmutils::printerr("DEF-USE: no information for: ", llvmVal);

            // XXX: shouldn't we set val to unknown location now?
            continue;
        }

        std::set<RDNode *> defs;
        // Get even reaching definitions for UNKNOWN_MEMORY.
        // Since those can be ours definitions, we must add them always
        mem->getReachingDefinitions(rd::UNKNOWN_MEMORY, UNKNOWN_OFFSET, UNKNOWN_OFFSET, defs);
        if (!defs.empty()) {
            for (RDNode *rd : defs) {
                assert(!rd->isUnknown() && "Unknown memory defined at unknown location?");
                addDataDependence(node, rd);
            }

            defs.clear();
        }

        mem->getReachingDefinitions(val, ptr.offset, size, defs);
        if (defs.empty()) {
            llvm::GlobalVariable *GV
                = llvm::dyn_cast<llvm::GlobalVariable>(llvmVal);
            if (!GV || !GV->hasInitializer()) {
                static std::set<const llvm::Value *> reported;
                if (reported.insert(llvmVal).second) {
                    llvm::errs() << "No reaching definition for: " << *llvmVal
                                 << " off: " << *ptr.offset << "\n";
                }
            }

            continue;
        }

        // add data dependence
        for (RDNode *rd : defs) {
            if (rd->isUnknown()) {
                // we don't know what definitions reach this node,
                // se we must add data dependence to all possible
                // write to this memory
                addUnknownDataDependence(node, pts);

                // we can bail out, since we have added all
                break;
            }

            addDataDependence(node, rd);
        }
    }
}

void LLVMDefUseAnalysis::addDataDependence(LLVMNode *node,
                                           const llvm::Value *where, /* in CFG */
                                           const llvm::Value *ptrOp,
                                           uint64_t size)
{
    // get points-to information for the operand
    PSNode *pts = PTA->getPointsTo(ptrOp);
    //assert(pts && "Don't have points-to information for LoadInst");
    if (!pts) {
        llvmutils::printerr("ERROR: No points-to: ", ptrOp);
        return;
    }

    addDataDependence(node, where, pts, size);
}

void LLVMDefUseAnalysis::addDataDependence(LLVMNode *node,
                                           const llvm::Value *where, /* in CFG */
                                           PSNode *pts, /* what memory */
                                           uint64_t size)
{
    using namespace dg::analysis;

    // get the node from reaching definition where we have
    // all the reaching definitions
    RDNode *mem = RD->getMapping(where);
    if(!mem) {
        llvmutils::printerr("ERROR: Don't have mapping: ", where);
        return;
    }

    // take every memory the load inst can use and get the
    // reaching definition
    addDataDependence(node, pts, mem, size);
}

static uint64_t getAllocatedSize(llvm::Type *Ty, const llvm::DataLayout *DL)
{
    // Type can be i8 *null or similar
    if (!Ty->isSized())
            return UNKNOWN_OFFSET;

    return DL->getTypeAllocSize(Ty);
}

void LLVMDefUseAnalysis::handleLoadInst(llvm::LoadInst *Inst, LLVMNode *node)
{
    using namespace dg::analysis;

    uint64_t size = getAllocatedSize(Inst->getType(), DL);
    addDataDependence(node, Inst, Inst->getPointerOperand(), size);
}

bool LLVMDefUseAnalysis::runOnNode(LLVMNode *node, LLVMNode *prev)
{
    Value *val = node->getKey();
    (void) prev;

    if (LoadInst *Inst = dyn_cast<LoadInst>(val)) {
        handleLoadInst(Inst, node);
    } else if (isa<CallInst>(val)) {
        handleCallInst(node);
    /*} else if (StoreInst *Inst = dyn_cast<StoreInst>(val)) {
        handleStoreInst(Inst, node);*/
    }

    /* just add direct def-use edges to every instruction */
    if (Instruction *Inst = dyn_cast<Instruction>(val))
        handleInstruction(Inst, node);

    // we will run only once
    return false;
}

} // namespace dg
<|endoftext|>


<commit_before>#include <stan/math/rev/mat.hpp>
#include <stan/math/rev/mat/fun/typedefs.hpp>
#include <gtest/gtest.h>
#include <vector>

#if defined(STAN_OPENCL) && !defined(STAN_OPENCL_NOCACHE)
#include <CL/cl.hpp>
#endif

TEST(AgradPartialsVari, OperandsAndPartialsScal) {
  using stan::math::operands_and_partials;
  using stan::math::var;

  double d1;
  operands_and_partials<double> o3(d1);
  EXPECT_EQ(5, sizeof(o3));

  var v1 = var(0.0);

  std::vector<var> v_stdvec;
  v_stdvec.push_back(v1);

  operands_and_partials<var> o4(v1);
  o4.edge1_.partials_[0] += 10.0;

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_stdvec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(10.0, grad[0]);
}

TEST(AgradPartialsVari, OperandsAndPartialsVec) {
  using stan::math::operands_and_partials;
  using stan::math::var;
  using stan::math::vector_d;
  using stan::math::vector_v;

  vector_d d_vec(4);
  operands_and_partials<vector_d> o3(d_vec);
  EXPECT_EQ(6, sizeof(o3));

  vector_v v_vec(4);
  var v1 = var(0.0);
  var v2 = var(1.0);
  var v3 = var(2.0);
  var v4 = var(3.0);
  v_vec << v1, v2, v3, v4;

  std::vector<var> v_stdvec;
  v_stdvec.push_back(v1);
  v_stdvec.push_back(v2);
  v_stdvec.push_back(v3);
  v_stdvec.push_back(v4);

  operands_and_partials<vector_v> o4(v_vec);
  o4.edge1_.partials_[0] += 10.0;
  o4.edge1_.partials_[1] += 20.0;
  o4.edge1_.partials_[2] += 30.0;
  o4.edge1_.partials_[3] += 40.0;

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_stdvec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(10.0, grad[0]);
  EXPECT_FLOAT_EQ(20.0, grad[1]);
  EXPECT_FLOAT_EQ(30.0, grad[2]);
  EXPECT_FLOAT_EQ(40.0, grad[3]);
}

TEST(AgradPartialsVari, OperandsAndPartialsStdVec) {
  using stan::math::operands_and_partials;
  using stan::math::var;

  std::vector<double> d_vec(4);
  operands_and_partials<std::vector<double> > o3(d_vec);
  EXPECT_EQ(5, sizeof(o3));

  std::vector<var> v_vec;
  var v1 = var(0.0);
  var v2 = var(1.0);
  var v3 = var(2.0);
  var v4 = var(3.0);
  v_vec.push_back(v1);
  v_vec.push_back(v2);
  v_vec.push_back(v3);
  v_vec.push_back(v4);

  operands_and_partials<std::vector<var> > o4(v_vec);
  o4.edge1_.partials_[0] += 10.0;
  o4.edge1_.partials_[1] += 20.0;
  o4.edge1_.partials_[2] += 30.0;
  o4.edge1_.partials_[3] += 40.0;

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_vec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(10.0, grad[0]);
  EXPECT_FLOAT_EQ(20.0, grad[1]);
  EXPECT_FLOAT_EQ(30.0, grad[2]);
  EXPECT_FLOAT_EQ(40.0, grad[3]);
}

TEST(AgradPartialsVari, OperandsAndPartialsMat) {
  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::operands_and_partials;
  using stan::math::var;

  matrix_d d_mat(2, 2);
  d_mat << 10.0, 20.0, 30.0, 40.0;
  operands_and_partials<matrix_d> o3(d_mat);

  EXPECT_EQ(6, sizeof(o3));

  matrix_v v_mat(2, 2);
  var v1 = var(0.0);
  var v2 = var(1.0);
  var v3 = var(2.0);
  var v4 = var(3.0);
  v_mat << v1, v2, v3, v4;

  std::vector<var> v_stdvec;
  v_stdvec.push_back(v1);
  v_stdvec.push_back(v2);
  v_stdvec.push_back(v3);
  v_stdvec.push_back(v4);

  operands_and_partials<matrix_v> o4(v_mat);
  o4.edge1_.partials_ += d_mat;
  o4.edge1_.partials_vec_[1] += d_mat;
  // Should affect the same vars as the call above
  o4.edge1_.partials_vec_[27] += d_mat;

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_stdvec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(30.0, grad[0]);
  EXPECT_FLOAT_EQ(60.0, grad[1]);
  EXPECT_FLOAT_EQ(90.0, grad[2]);
  EXPECT_FLOAT_EQ(120.0, grad[3]);
}

TEST(AgradPartialsVari, OperandsAndPartialsMatMultivar) {
  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::operands_and_partials;
  using stan::math::var;

  matrix_d d_mat(2, 2);
  d_mat << 10.0, 20.0, 30.0, 40.0;
  std::vector<matrix_d> d_mat_vec;
  d_mat_vec.push_back(d_mat);
  operands_and_partials<std::vector<matrix_d> > o3(d_mat_vec);

  EXPECT_EQ(5, sizeof(o3));

  matrix_v v_mat1(2, 2);
  var v1 = var(0.0);
  var v2 = var(1.0);
  var v3 = var(2.0);
  var v4 = var(3.0);
  v_mat1 << v1, v2, v3, v4;

  matrix_v v_mat2(2, 2);
  var v5 = var(0.1);
  var v6 = var(1.1);
  var v7 = var(2.1);
  var v8 = var(3.1);
  v_mat2 << v5, v6, v7, v8;

  std::vector<matrix_v> v_mat_vec;
  v_mat_vec.push_back(v_mat1);
  v_mat_vec.push_back(v_mat2);

  std::vector<var> v_stdvec;
  v_stdvec.push_back(v1);
  v_stdvec.push_back(v2);
  v_stdvec.push_back(v3);
  v_stdvec.push_back(v4);
  v_stdvec.push_back(v5);
  v_stdvec.push_back(v6);
  v_stdvec.push_back(v7);
  v_stdvec.push_back(v8);

  operands_and_partials<std::vector<matrix_v> > o4(v_mat_vec);
  o4.edge1_.partials_vec_[0] += d_mat;
  // Should NOT affect the same vars as the call above
  o4.edge1_.partials_vec_[1] += d_mat;
  o4.edge1_.partials_vec_[1] += d_mat;

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_stdvec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(10.0, grad[0]);
  EXPECT_FLOAT_EQ(20.0, grad[1]);
  EXPECT_FLOAT_EQ(30.0, grad[2]);
  EXPECT_FLOAT_EQ(40.0, grad[3]);
  EXPECT_FLOAT_EQ(20.0, grad[4]);
  EXPECT_FLOAT_EQ(40.0, grad[5]);
  EXPECT_FLOAT_EQ(60.0, grad[6]);
  EXPECT_FLOAT_EQ(80.0, grad[7]);
}

TEST(AgradPartialsVari, OperandsAndPartialsMultivar) {
  using stan::math::operands_and_partials;
  using stan::math::var;
  using stan::math::vector_d;
  using stan::math::vector_v;

  std::vector<vector_d> d_vec_vec(2);
  vector_d d_vec1(2);
  d_vec1 << 10.0, 20.0;
  vector_d d_vec2(2);
  d_vec2 << 30.0, 40.0;
  d_vec_vec.push_back(d_vec1);
  d_vec_vec.push_back(d_vec2);
  operands_and_partials<std::vector<vector_d> > o3(d_vec_vec);

  EXPECT_EQ(5, sizeof(o3));

  vector_v v_vec1(2);
  var v1 = var(0.0);
  var v2 = var(1.0);
  v_vec1 << v1, v2;
  vector_v v_vec2(2);
  var v3 = var(2.0);
  var v4 = var(3.0);
  v_vec2 << v3, v4;
  std::vector<vector_v> v_vec;
  v_vec.push_back(v_vec1);
  v_vec.push_back(v_vec2);

  std::vector<var> v_stdvec;
  v_stdvec.push_back(v1);
  v_stdvec.push_back(v2);
  v_stdvec.push_back(v3);
  v_stdvec.push_back(v4);

  operands_and_partials<std::vector<vector_v> > o4(v_vec);
  o4.edge1_.partials_vec_[0] += d_vec1;
  o4.edge1_.partials_vec_[1] += d_vec2;

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_stdvec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(10.0, grad[0]);
  EXPECT_FLOAT_EQ(20.0, grad[1]);
  EXPECT_FLOAT_EQ(30.0, grad[2]);
  EXPECT_FLOAT_EQ(40.0, grad[3]);
}

// XXX Test mixed - operands_and_partials<std::vector<matrix_v>,
//                                        vector_d, vector_v>
TEST(AgradPartialsVari, OperandsAndPartialsMultivarMixed) {
  using stan::math::matrix_v;
  using stan::math::operands_and_partials;
  using stan::math::var;
  using stan::math::vector_d;
  using stan::math::vector_v;

  std::vector<vector_d> d_vec_vec(2);
  vector_d d_vec1(2);
  d_vec1 << 10.0, 20.0;
  vector_d d_vec2(2);
  d_vec2 << 30.0, 40.0;
  d_vec_vec.push_back(d_vec1);
  d_vec_vec.push_back(d_vec2);

  vector_v v_vec1(2);
  var v1 = var(0.0);
  var v2 = var(1.0);
  v_vec1 << v1, v2;
  vector_v v_vec2(2);
  var v3 = var(2.0);
  var v4 = var(3.0);
  v_vec2 << v3, v4;
  std::vector<vector_v> v_vec;
  v_vec.push_back(v_vec1);

  std::vector<var> v_stdvec;
  v_stdvec.push_back(v1);
  v_stdvec.push_back(v2);
  v_stdvec.push_back(v3);
  v_stdvec.push_back(v4);

  operands_and_partials<std::vector<vector_v>, std::vector<vector_d>, vector_v>
      o4(v_vec, d_vec_vec, v_vec2);
  o4.edge1_.partials_vec_[0] += d_vec1;
  o4.edge3_.partials_vec_[0] += d_vec2;

#if defined(STAN_OPENCL) && !defined(STAN_OPENCL_NOCACHE)
  EXPECT_EQ(2 * sizeof(d_vec1) + 6 * sizeof(&v_vec) - sizeof(cl::Buffer), sizeof(o4));
#else
  // 2 partials stdvecs, 4 pointers to edges, 2 pointers to operands
  // vecs
  EXPECT_EQ(2 * sizeof(d_vec1) + 6 * sizeof(&v_vec), sizeof(o4));
#endif

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_stdvec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(10.0, grad[0]);
  EXPECT_FLOAT_EQ(20.0, grad[1]);
  EXPECT_FLOAT_EQ(30.0, grad[2]);
  EXPECT_FLOAT_EQ(40.0, grad[3]);

  // when given vector_d in place of vector_v all expressions must
  // still compile
  operands_and_partials<std::vector<vector_v>, std::vector<vector_d>, vector_d>
      o5(v_vec, d_vec_vec, d_vec2);
  o5.edge1_.partials_vec_[0] += d_vec1;
  if (false) {
    // the test here is to make things compile as this pattern to
    // if-out things when terms are const is used in our functions
    o5.edge3_.partials_vec_[0] += vector_d();
    o5.edge3_.partials_vec_[0] -= vector_d();
    o5.edge3_.partials_vec_[0](0) = 0;
  }

  // the same needs to work for the nested case
  operands_and_partials<std::vector<vector_d>, std::vector<vector_d>, vector_v>
      o6(d_vec_vec, d_vec_vec, v_vec2);
  if (false) {
    // the test here is to make things compile as this pattern to
    // if-out things when terms are const is used in our functions
    o6.edge1_.partials_vec_[0] += d_vec1;
  }
  o6.edge3_.partials_vec_[0] += d_vec2;
}
<commit_msg>[Jenkins] auto-formatting by clang-format version 6.0.0 (tags/google/stable/2017-11-14)<commit_after>#include <stan/math/rev/mat.hpp>
#include <stan/math/rev/mat/fun/typedefs.hpp>
#include <gtest/gtest.h>
#include <vector>

#if defined(STAN_OPENCL) && !defined(STAN_OPENCL_NOCACHE)
#include <CL/cl.hpp>
#endif

TEST(AgradPartialsVari, OperandsAndPartialsScal) {
  using stan::math::operands_and_partials;
  using stan::math::var;

  double d1;
  operands_and_partials<double> o3(d1);
  EXPECT_EQ(5, sizeof(o3));

  var v1 = var(0.0);

  std::vector<var> v_stdvec;
  v_stdvec.push_back(v1);

  operands_and_partials<var> o4(v1);
  o4.edge1_.partials_[0] += 10.0;

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_stdvec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(10.0, grad[0]);
}

TEST(AgradPartialsVari, OperandsAndPartialsVec) {
  using stan::math::operands_and_partials;
  using stan::math::var;
  using stan::math::vector_d;
  using stan::math::vector_v;

  vector_d d_vec(4);
  operands_and_partials<vector_d> o3(d_vec);
  EXPECT_EQ(6, sizeof(o3));

  vector_v v_vec(4);
  var v1 = var(0.0);
  var v2 = var(1.0);
  var v3 = var(2.0);
  var v4 = var(3.0);
  v_vec << v1, v2, v3, v4;

  std::vector<var> v_stdvec;
  v_stdvec.push_back(v1);
  v_stdvec.push_back(v2);
  v_stdvec.push_back(v3);
  v_stdvec.push_back(v4);

  operands_and_partials<vector_v> o4(v_vec);
  o4.edge1_.partials_[0] += 10.0;
  o4.edge1_.partials_[1] += 20.0;
  o4.edge1_.partials_[2] += 30.0;
  o4.edge1_.partials_[3] += 40.0;

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_stdvec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(10.0, grad[0]);
  EXPECT_FLOAT_EQ(20.0, grad[1]);
  EXPECT_FLOAT_EQ(30.0, grad[2]);
  EXPECT_FLOAT_EQ(40.0, grad[3]);
}

TEST(AgradPartialsVari, OperandsAndPartialsStdVec) {
  using stan::math::operands_and_partials;
  using stan::math::var;

  std::vector<double> d_vec(4);
  operands_and_partials<std::vector<double> > o3(d_vec);
  EXPECT_EQ(5, sizeof(o3));

  std::vector<var> v_vec;
  var v1 = var(0.0);
  var v2 = var(1.0);
  var v3 = var(2.0);
  var v4 = var(3.0);
  v_vec.push_back(v1);
  v_vec.push_back(v2);
  v_vec.push_back(v3);
  v_vec.push_back(v4);

  operands_and_partials<std::vector<var> > o4(v_vec);
  o4.edge1_.partials_[0] += 10.0;
  o4.edge1_.partials_[1] += 20.0;
  o4.edge1_.partials_[2] += 30.0;
  o4.edge1_.partials_[3] += 40.0;

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_vec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(10.0, grad[0]);
  EXPECT_FLOAT_EQ(20.0, grad[1]);
  EXPECT_FLOAT_EQ(30.0, grad[2]);
  EXPECT_FLOAT_EQ(40.0, grad[3]);
}

TEST(AgradPartialsVari, OperandsAndPartialsMat) {
  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::operands_and_partials;
  using stan::math::var;

  matrix_d d_mat(2, 2);
  d_mat << 10.0, 20.0, 30.0, 40.0;
  operands_and_partials<matrix_d> o3(d_mat);

  EXPECT_EQ(6, sizeof(o3));

  matrix_v v_mat(2, 2);
  var v1 = var(0.0);
  var v2 = var(1.0);
  var v3 = var(2.0);
  var v4 = var(3.0);
  v_mat << v1, v2, v3, v4;

  std::vector<var> v_stdvec;
  v_stdvec.push_back(v1);
  v_stdvec.push_back(v2);
  v_stdvec.push_back(v3);
  v_stdvec.push_back(v4);

  operands_and_partials<matrix_v> o4(v_mat);
  o4.edge1_.partials_ += d_mat;
  o4.edge1_.partials_vec_[1] += d_mat;
  // Should affect the same vars as the call above
  o4.edge1_.partials_vec_[27] += d_mat;

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_stdvec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(30.0, grad[0]);
  EXPECT_FLOAT_EQ(60.0, grad[1]);
  EXPECT_FLOAT_EQ(90.0, grad[2]);
  EXPECT_FLOAT_EQ(120.0, grad[3]);
}

TEST(AgradPartialsVari, OperandsAndPartialsMatMultivar) {
  using stan::math::matrix_d;
  using stan::math::matrix_v;
  using stan::math::operands_and_partials;
  using stan::math::var;

  matrix_d d_mat(2, 2);
  d_mat << 10.0, 20.0, 30.0, 40.0;
  std::vector<matrix_d> d_mat_vec;
  d_mat_vec.push_back(d_mat);
  operands_and_partials<std::vector<matrix_d> > o3(d_mat_vec);

  EXPECT_EQ(5, sizeof(o3));

  matrix_v v_mat1(2, 2);
  var v1 = var(0.0);
  var v2 = var(1.0);
  var v3 = var(2.0);
  var v4 = var(3.0);
  v_mat1 << v1, v2, v3, v4;

  matrix_v v_mat2(2, 2);
  var v5 = var(0.1);
  var v6 = var(1.1);
  var v7 = var(2.1);
  var v8 = var(3.1);
  v_mat2 << v5, v6, v7, v8;

  std::vector<matrix_v> v_mat_vec;
  v_mat_vec.push_back(v_mat1);
  v_mat_vec.push_back(v_mat2);

  std::vector<var> v_stdvec;
  v_stdvec.push_back(v1);
  v_stdvec.push_back(v2);
  v_stdvec.push_back(v3);
  v_stdvec.push_back(v4);
  v_stdvec.push_back(v5);
  v_stdvec.push_back(v6);
  v_stdvec.push_back(v7);
  v_stdvec.push_back(v8);

  operands_and_partials<std::vector<matrix_v> > o4(v_mat_vec);
  o4.edge1_.partials_vec_[0] += d_mat;
  // Should NOT affect the same vars as the call above
  o4.edge1_.partials_vec_[1] += d_mat;
  o4.edge1_.partials_vec_[1] += d_mat;

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_stdvec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(10.0, grad[0]);
  EXPECT_FLOAT_EQ(20.0, grad[1]);
  EXPECT_FLOAT_EQ(30.0, grad[2]);
  EXPECT_FLOAT_EQ(40.0, grad[3]);
  EXPECT_FLOAT_EQ(20.0, grad[4]);
  EXPECT_FLOAT_EQ(40.0, grad[5]);
  EXPECT_FLOAT_EQ(60.0, grad[6]);
  EXPECT_FLOAT_EQ(80.0, grad[7]);
}

TEST(AgradPartialsVari, OperandsAndPartialsMultivar) {
  using stan::math::operands_and_partials;
  using stan::math::var;
  using stan::math::vector_d;
  using stan::math::vector_v;

  std::vector<vector_d> d_vec_vec(2);
  vector_d d_vec1(2);
  d_vec1 << 10.0, 20.0;
  vector_d d_vec2(2);
  d_vec2 << 30.0, 40.0;
  d_vec_vec.push_back(d_vec1);
  d_vec_vec.push_back(d_vec2);
  operands_and_partials<std::vector<vector_d> > o3(d_vec_vec);

  EXPECT_EQ(5, sizeof(o3));

  vector_v v_vec1(2);
  var v1 = var(0.0);
  var v2 = var(1.0);
  v_vec1 << v1, v2;
  vector_v v_vec2(2);
  var v3 = var(2.0);
  var v4 = var(3.0);
  v_vec2 << v3, v4;
  std::vector<vector_v> v_vec;
  v_vec.push_back(v_vec1);
  v_vec.push_back(v_vec2);

  std::vector<var> v_stdvec;
  v_stdvec.push_back(v1);
  v_stdvec.push_back(v2);
  v_stdvec.push_back(v3);
  v_stdvec.push_back(v4);

  operands_and_partials<std::vector<vector_v> > o4(v_vec);
  o4.edge1_.partials_vec_[0] += d_vec1;
  o4.edge1_.partials_vec_[1] += d_vec2;

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_stdvec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(10.0, grad[0]);
  EXPECT_FLOAT_EQ(20.0, grad[1]);
  EXPECT_FLOAT_EQ(30.0, grad[2]);
  EXPECT_FLOAT_EQ(40.0, grad[3]);
}

// XXX Test mixed - operands_and_partials<std::vector<matrix_v>,
//                                        vector_d, vector_v>
TEST(AgradPartialsVari, OperandsAndPartialsMultivarMixed) {
  using stan::math::matrix_v;
  using stan::math::operands_and_partials;
  using stan::math::var;
  using stan::math::vector_d;
  using stan::math::vector_v;

  std::vector<vector_d> d_vec_vec(2);
  vector_d d_vec1(2);
  d_vec1 << 10.0, 20.0;
  vector_d d_vec2(2);
  d_vec2 << 30.0, 40.0;
  d_vec_vec.push_back(d_vec1);
  d_vec_vec.push_back(d_vec2);

  vector_v v_vec1(2);
  var v1 = var(0.0);
  var v2 = var(1.0);
  v_vec1 << v1, v2;
  vector_v v_vec2(2);
  var v3 = var(2.0);
  var v4 = var(3.0);
  v_vec2 << v3, v4;
  std::vector<vector_v> v_vec;
  v_vec.push_back(v_vec1);

  std::vector<var> v_stdvec;
  v_stdvec.push_back(v1);
  v_stdvec.push_back(v2);
  v_stdvec.push_back(v3);
  v_stdvec.push_back(v4);

  operands_and_partials<std::vector<vector_v>, std::vector<vector_d>, vector_v>
      o4(v_vec, d_vec_vec, v_vec2);
  o4.edge1_.partials_vec_[0] += d_vec1;
  o4.edge3_.partials_vec_[0] += d_vec2;

#if defined(STAN_OPENCL) && !defined(STAN_OPENCL_NOCACHE)
  EXPECT_EQ(2 * sizeof(d_vec1) + 6 * sizeof(&v_vec) - sizeof(cl::Buffer),
            sizeof(o4));
#else
  // 2 partials stdvecs, 4 pointers to edges, 2 pointers to operands
  // vecs
  EXPECT_EQ(2 * sizeof(d_vec1) + 6 * sizeof(&v_vec), sizeof(o4));
#endif

  std::vector<double> grad;
  var v = o4.build(10.0);
  v.grad(v_stdvec, grad);
  EXPECT_FLOAT_EQ(10.0, v.val());
  EXPECT_FLOAT_EQ(10.0, grad[0]);
  EXPECT_FLOAT_EQ(20.0, grad[1]);
  EXPECT_FLOAT_EQ(30.0, grad[2]);
  EXPECT_FLOAT_EQ(40.0, grad[3]);

  // when given vector_d in place of vector_v all expressions must
  // still compile
  operands_and_partials<std::vector<vector_v>, std::vector<vector_d>, vector_d>
      o5(v_vec, d_vec_vec, d_vec2);
  o5.edge1_.partials_vec_[0] += d_vec1;
  if (false) {
    // the test here is to make things compile as this pattern to
    // if-out things when terms are const is used in our functions
    o5.edge3_.partials_vec_[0] += vector_d();
    o5.edge3_.partials_vec_[0] -= vector_d();
    o5.edge3_.partials_vec_[0](0) = 0;
  }

  // the same needs to work for the nested case
  operands_and_partials<std::vector<vector_d>, std::vector<vector_d>, vector_v>
      o6(d_vec_vec, d_vec_vec, v_vec2);
  if (false) {
    // the test here is to make things compile as this pattern to
    // if-out things when terms are const is used in our functions
    o6.edge1_.partials_vec_[0] += d_vec1;
  }
  o6.edge3_.partials_vec_[0] += d_vec2;
}
<|endoftext|>


<commit_before>#include <qtest.h>
#include <QtDeclarative/qmlcomponent.h>
#include <QtDeclarative/qmlengine.h>

class MyQmlObject : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool trueProperty READ trueProperty)
    Q_PROPERTY(bool falseProperty READ falseProperty)
    Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged)
public:
    MyQmlObject(): m_methodCalled(false), m_methodIntCalled(false) {}

    bool trueProperty() const { return true; }
    bool falseProperty() const { return false; }

    QString stringProperty() const { return m_string; }
    void setStringProperty(const QString &s)
    {
        if (s == m_string)
            return;
        m_string = s;
        emit stringChanged();
    }

    bool methodCalled() const { return m_methodCalled; }
    bool methodIntCalled() const { return m_methodIntCalled; }

    QString string() const { return m_string; }
signals:
    void basicSignal();
    void argumentSignal(int a, QString b, qreal c);
    void stringChanged();

public slots:
    void method() { m_methodCalled = true; }
    void method(int a) { if(a == 163) m_methodIntCalled = true; }
    void setString(const QString &s) { m_string = s; }

private:
    friend class tst_qmlbindengine;
    bool m_methodCalled;
    bool m_methodIntCalled;

    QString m_string;
};

QML_DECLARE_TYPE(MyQmlObject);
QML_DEFINE_TYPE(MyQmlObject,MyQmlObject);

class MyQmlContainer : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<MyQmlContainer*>* children READ children)
public:
    MyQmlContainer() {}

    QList<MyQmlContainer*> *children() { return &m_children; }

private:
    QList<MyQmlContainer*> m_children;
};

QML_DECLARE_TYPE(MyQmlContainer);
QML_DEFINE_TYPE(MyQmlContainer,MyQmlContainer);

class tst_qmlbindengine : public QObject
{
    Q_OBJECT
public:
    tst_qmlbindengine() {}

private slots:
    void boolPropertiesEvaluateAsBool();
    void methods();
    void signalAssignment();
    void bindingLoop();

private:
    QmlEngine engine;
};

void tst_qmlbindengine::boolPropertiesEvaluateAsBool()
{
    {
        QmlComponent component(&engine, "MyQmlObject { stringProperty: trueProperty?'pass':'fail' }");
        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
        QVERIFY(object != 0);
        QCOMPARE(object->stringProperty(), QLatin1String("pass"));
    }
    {
        QmlComponent component(&engine, "MyQmlObject { stringProperty: falseProperty?'fail':'pass' }");
        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
        QVERIFY(object != 0);
        QCOMPARE(object->stringProperty(), QLatin1String("pass"));
    }
}

void tst_qmlbindengine::signalAssignment()
{
    {
        QmlComponent component(&engine, "MyQmlObject { onBasicSignal: setString('pass') }");
        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
        QVERIFY(object != 0);
        QCOMPARE(object->string(), QString());
        emit object->basicSignal();
        QCOMPARE(object->string(), QString("pass"));
    }

    {
        QmlComponent component(&engine, "MyQmlObject { onArgumentSignal: setString('pass ' + a + ' ' + b + ' ' + c) }");
        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
        QVERIFY(object != 0);
        QCOMPARE(object->string(), QString());
        emit object->argumentSignal(19, "Hello world!", 10.3);
        QCOMPARE(object->string(), QString("pass 19 Hello world! 10.3"));
    }
}

void tst_qmlbindengine::methods()
{
    {
        QmlComponent component(&engine, "MyQmlObject { id: MyObject; onBasicSignal: MyObject.method() }");
        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
        QVERIFY(object != 0);
        QCOMPARE(object->methodCalled(), false);
        QCOMPARE(object->methodIntCalled(), false);
        emit object->basicSignal();
        QCOMPARE(object->methodCalled(), true);
        QCOMPARE(object->methodIntCalled(), false);
    }

    {
        QmlComponent component(&engine, "MyQmlObject { id: MyObject; onBasicSignal: MyObject.method(163) }");
        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
        QVERIFY(object != 0);
        QCOMPARE(object->methodCalled(), false);
        QCOMPARE(object->methodIntCalled(), false);
        emit object->basicSignal();
        QCOMPARE(object->methodCalled(), false);
        QCOMPARE(object->methodIntCalled(), true);
    }
}
#include <QDebug>
void tst_qmlbindengine::bindingLoop()
{
    QmlComponent component(&engine, "MyQmlContainer { children : [ "\
                                    "MyQmlObject { id: Object1; stringProperty: \"hello\" + Object2.stringProperty }, "\
                                    "MyQmlObject { id: Object2; stringProperty: \"hello\" + Object1.stringProperty } ] }");
    //### ignoreMessage doesn't seem to work here
    //QTest::ignoreMessage(QtWarningMsg, "QML MyQmlObject (unknown location): Binding loop detected for property \"stringProperty\"");
    QObject *object = component.create();
    QVERIFY(object != 0);
}

QTEST_MAIN(tst_qmlbindengine)

#include "tst_qmlbindengine.moc"
<commit_msg>Add context property test<commit_after>#include <qtest.h>
#include <QtDeclarative/qmlcomponent.h>
#include <QtDeclarative/qmlengine.h>
#include <QtDeclarative/qmlexpression.h>
#include <QtDeclarative/qmlcontext.h>

class MyQmlObject : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool trueProperty READ trueProperty)
    Q_PROPERTY(bool falseProperty READ falseProperty)
    Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged)
public:
    MyQmlObject(): m_methodCalled(false), m_methodIntCalled(false) {}

    bool trueProperty() const { return true; }
    bool falseProperty() const { return false; }

    QString stringProperty() const { return m_string; }
    void setStringProperty(const QString &s)
    {
        if (s == m_string)
            return;
        m_string = s;
        emit stringChanged();
    }

    bool methodCalled() const { return m_methodCalled; }
    bool methodIntCalled() const { return m_methodIntCalled; }

    QString string() const { return m_string; }
signals:
    void basicSignal();
    void argumentSignal(int a, QString b, qreal c);
    void stringChanged();

public slots:
    void method() { m_methodCalled = true; }
    void method(int a) { if(a == 163) m_methodIntCalled = true; }
    void setString(const QString &s) { m_string = s; }

private:
    friend class tst_qmlbindengine;
    bool m_methodCalled;
    bool m_methodIntCalled;

    QString m_string;
};

QML_DECLARE_TYPE(MyQmlObject);
QML_DEFINE_TYPE(MyQmlObject,MyQmlObject);

class MyQmlContainer : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<MyQmlContainer*>* children READ children)
public:
    MyQmlContainer() {}

    QList<MyQmlContainer*> *children() { return &m_children; }

private:
    QList<MyQmlContainer*> m_children;
};

QML_DECLARE_TYPE(MyQmlContainer);
QML_DEFINE_TYPE(MyQmlContainer,MyQmlContainer);

class tst_qmlbindengine : public QObject
{
    Q_OBJECT
public:
    tst_qmlbindengine() {}

private slots:
    void boolPropertiesEvaluateAsBool();
    void methods();
    void signalAssignment();
    void bindingLoop();
    void contextPropertiesTriggerReeval();

private:
    QmlEngine engine;
};

void tst_qmlbindengine::boolPropertiesEvaluateAsBool()
{
    {
        QmlComponent component(&engine, "MyQmlObject { stringProperty: trueProperty?'pass':'fail' }");
        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
        QVERIFY(object != 0);
        QCOMPARE(object->stringProperty(), QLatin1String("pass"));
    }
    {
        QmlComponent component(&engine, "MyQmlObject { stringProperty: falseProperty?'fail':'pass' }");
        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
        QVERIFY(object != 0);
        QCOMPARE(object->stringProperty(), QLatin1String("pass"));
    }
}

void tst_qmlbindengine::signalAssignment()
{
    {
        QmlComponent component(&engine, "MyQmlObject { onBasicSignal: setString('pass') }");
        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
        QVERIFY(object != 0);
        QCOMPARE(object->string(), QString());
        emit object->basicSignal();
        QCOMPARE(object->string(), QString("pass"));
    }

    {
        QmlComponent component(&engine, "MyQmlObject { onArgumentSignal: setString('pass ' + a + ' ' + b + ' ' + c) }");
        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
        QVERIFY(object != 0);
        QCOMPARE(object->string(), QString());
        emit object->argumentSignal(19, "Hello world!", 10.3);
        QCOMPARE(object->string(), QString("pass 19 Hello world! 10.3"));
    }
}

void tst_qmlbindengine::methods()
{
    {
        QmlComponent component(&engine, "MyQmlObject { id: MyObject; onBasicSignal: MyObject.method() }");
        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
        QVERIFY(object != 0);
        QCOMPARE(object->methodCalled(), false);
        QCOMPARE(object->methodIntCalled(), false);
        emit object->basicSignal();
        QCOMPARE(object->methodCalled(), true);
        QCOMPARE(object->methodIntCalled(), false);
    }

    {
        QmlComponent component(&engine, "MyQmlObject { id: MyObject; onBasicSignal: MyObject.method(163) }");
        MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
        QVERIFY(object != 0);
        QCOMPARE(object->methodCalled(), false);
        QCOMPARE(object->methodIntCalled(), false);
        emit object->basicSignal();
        QCOMPARE(object->methodCalled(), false);
        QCOMPARE(object->methodIntCalled(), true);
    }
}

void tst_qmlbindengine::bindingLoop()
{
    QmlComponent component(&engine, "MyQmlContainer { children : [ "\
                                    "MyQmlObject { id: Object1; stringProperty: \"hello\" + Object2.stringProperty }, "\
                                    "MyQmlObject { id: Object2; stringProperty: \"hello\" + Object1.stringProperty } ] }");
    //### ignoreMessage doesn't seem to work here
    //QTest::ignoreMessage(QtWarningMsg, "QML MyQmlObject (unknown location): Binding loop detected for property \"stringProperty\"");
    QObject *object = component.create();
    QVERIFY(object != 0);
}

class MyExpression : public QmlExpression
{
public:
    MyExpression(QmlContext *ctxt, const QString &expr)
        : QmlExpression(ctxt, expr, 0), changed(false)
    {
    }

    bool changed;
};

void tst_qmlbindengine::contextPropertiesTriggerReeval()
{
    QmlContext context(engine.rootContext());
    context.setContextProperty("testProp", QVariant(1));

    MyExpression expr(&context, "testProp + 1");
    QCOMPARE(expr.changed, false);
    QCOMPARE(expr.value(), QVariant(2));

    context.setContextProperty("testProp", QVariant(2));
    QCOMPARE(expr.changed, true);
    QCOMPARE(expr.value(), QVariant(3));
}

QTEST_MAIN(tst_qmlbindengine)

#include "tst_qmlbindengine.moc"
<|endoftext|>


<commit_before>/**
   \file undistort.cc

   Apply Lensfun corrections to a PNM file in place.  This means, the original
   file is overwritten.  The command line parameters are:
   - path to the PNM file
   - x coordinate of top left corner
   - y coordinate of top left corner
   - x coordinate of top right corner
   - y coordinate of top right corner
   - x coordinate of bottom left corner
   - y coordinate of bottom left corner
   - x coordinate of bottom right corner
   - y coordinate of bottom right corner

   All coordinates are pixel coordinates, with the top left of the image the
   origin.  The corners must be the corners of a perfect rectangle which was
   taken a picture of, e.g. a sheet of paper.  These are used for the
   perspective correction as well as the rotation, so that the edges of the
   rectangle are parellel to the image borders.

   The program returns the position and the dimensions of the rectangle in
   the output image to stdout in JSON format:

   \code{.json}
   [x₀, y₀, width, height]
   \endcode

   Here, x₀ and y₀ are the coordinates of the top left corner, and width and
   height are the dimensions of the rectangle.

   This program does not apply colour corrections such as vignetting
   correction, as those are handled by kamscan.py using flat field images.
*/
#include <fstream>
#include <vector>
#include <iterator>
#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include "lensfun.h"

/** Class for bitmap data.

  In case of 2 bytes per channel, network byte order is assumed. */
class Image {
public:
    Image(int width, int height, int channel_size, int channels);
    Image() {};
    Image(const Image &image);
    /** Get the channel intensity at a certian coordinate.
      \param x x coordinate
      \param y y coordinate
      \param channel index of the channel (for greyscale, it is always zero;
        for RGB, it is 0, 1, or 2)
      \return raw integer value of the intensity of this channel at this
        position
    */
    int get(int x, int y, int channel);
    /** Get the channel intensity at a certian coordinate.  The coordinates are
      floats and may contain fractions.  In this case, the intensity is
      calculated using bilinear interpolation between the four pixels around
      this coordinate.
      \param x x coordinate
      \param y y coordinate
      \param channel index of the channel (for greyscale, it is always zero;
        for RGB, it is 0, 1, or 2)
      \return raw integer value of the intensity of this channel at this
        position
    */
    int get(float x, float y, int channel);
    /** Set the channel intensity at a certian coordinate.
      \param x x coordinate
      \param y y coordinate
      \param channel index of the channel (for greyscale, it is always zero;
        for RGB, it is 0, 1, or 2)
      \param value raw integer value of the intensity of this channel at this
        position
    */
    void set(int x, int y, int channel, int value);
    /** Determine the channel descriptions.  This is used by Lensfun internally
      and necessary if you want to apply colour corrections, e.g. vignetting
      correction.
      \return the components of each pixel
    */
    int components();
    /** Determine the pixel format à la Lensfun.  It is derived from
      channel_size.
      \return the pixel format as it is needed by Lensfun
     */
    lfPixelFormat pixel_format();
    int width, height; ///< width and height of the image in pixels
    int channels; ///< number of channels; may be 1 (greyscale) or 3 (RGB)
    /** the raw data (1:1 dump of the PNM content, without header)
     */
    std::vector<unsigned char> data;

private:
    friend std::istream& operator>>(std::istream &inputStream, Image &other);
    friend std::ostream& operator<<(std::ostream &outputStream, const Image &other);
    int channel_size; ///< width of one channel in bytes; may be 1 or 2
};

Image::Image(int width, int height, int channel_size, int channels) :
    width(width), height(height), channel_size(channel_size), channels(channels)
{
    data.resize(width * height * channel_size * channels);
}

Image::Image(const Image &image) :
    width(image.width), height(image.height), channel_size(image.channel_size), channels(image.channels) {
}

int Image::get(int x, int y, int channel) {
    if (x < 0 || x >= width || y < 0 || y >= height)
        return 0;
    int position = channel_size * (channels * (y * width + x) + channel);
    int result = static_cast<int>(data[position]);
    if (channel_size == 2)
        result = (result << 8) + static_cast<int>(data[position + 1]);
    return result;
}

int Image::get(float x, float y, int channel) {
    float dummy;
    int x0 = static_cast<int>(x);
    int y0 = static_cast<int>(y);
    float i0 = static_cast<float>(get(x0, y0, channel));
    float i1 = static_cast<float>(get(x0 + 1, y0, channel));
    float i2 = static_cast<float>(get(x0, y0 + 1, channel));
    float i3 = static_cast<float>(get(x0 + 1, y0 + 1, channel));
    float fraction_x = std::modf(x, &dummy);
    float i01 = (1 - fraction_x) * i0 + fraction_x * i1;
    float i23 = (1 - fraction_x) * i2 + fraction_x * i3;
    float fraction_y = std::modf(y, &dummy);
    return static_cast<int>(std::round((1 - fraction_y) * i01 + fraction_y * i23));
}

void Image::set(int x, int y, int channel, int value) {
    if (x >= 0 && x < width && y >= 0 && y < height) {
        int position = channel_size * (channels * (y * width + x) + channel);
        if (channel_size == 1)
            data[position] = static_cast<unsigned char>(value);
        else if (channel_size == 2) {
            data[position] = static_cast<unsigned char>(value >> 8);
            data[position + 1] = static_cast<unsigned char>(value & 256);
        }
    }
}

int Image::components() {
    switch (channels) {
    case 1:
        return LF_CR_1(INTENSITY);
    case 3:
        return LF_CR_3(RED, GREEN, BLUE);
    default:
        throw std::runtime_error("Invalid value of 'channels'.");
    }
}

lfPixelFormat Image::pixel_format() {
    switch (channel_size) {
    case 1:
        return LF_PF_U8;
    case 2:
        return LF_PF_U16;
    default:
        throw std::runtime_error("Invalid value of 'channel_size'.");
    }
}

std::istream& operator>>(std::istream &inputStream, Image &other)
{
    std::string magic_number;
    int maximum_color_value;
    inputStream >> magic_number;
    if (magic_number == "P5")
        other.channels = 1;
    else if (magic_number == "P6")
        other.channels = 3;
    else
        throw std::runtime_error("Invalid input file.  Must start with 'P5' or 'P6'.");
    inputStream >> other.width >> other.height >> maximum_color_value;
    inputStream.get(); // skip the trailing white space
    switch (maximum_color_value) {
    case 255:
        other.channel_size = 1;
        break;
    case 65535:
        other.channel_size = 2;
        break;
    default:
        throw std::runtime_error("Invalid PPM file: Maximum color value must be 255 or 65535.");
    }
    size_t size = other.width * other.height * other.channel_size * other.channels;
    other.data.resize(size);
    inputStream.read(reinterpret_cast<char*>(other.data.data()), size);
    return inputStream;
}

std::ostream& operator<<(std::ostream &outputStream, const Image &other)
{
    outputStream << (other.channels == 3 ? "P6" : "P5") << "\n"
                 << other.width << " "
                 << other.height << "\n"
                 << (other.channel_size == 1 ? "255" : "65535") << "\n";
    outputStream.write(reinterpret_cast<const char*>(other.data.data()), other.data.size());
    return outputStream;
}

int main(int argc, char* argv[]) {
    if (argc != 10) {
        std::cerr << "You must give path to input file as well as all four corner coordinates.\n";
        return -1;
    }

    lfDatabase ldb;

    if (ldb.Load() != LF_NO_ERROR) {
        std::cerr << "Database could not be loaded\n";
        return -1;
    }

    const lfCamera *camera;
    const lfCamera **cameras = ldb.FindCamerasExt(NULL, "NEX-7");
    if (cameras && !cameras[1])
        camera = cameras[0];
    else {
        std::cerr << "Cannot find unique camera in database.  " << sizeof(cameras) << " cameras found.\n";
        lf_free(cameras);
        return -1;
    }
    lf_free(cameras);

    const lfLens *lens;
    const lfLens **lenses = ldb.FindLenses(camera, NULL, "E 50mm f/1.8 OSS (kamscan)");
    if (lenses && !lenses[1]) {
        lens = lenses[0];
    } else if (!lenses) {
        std::cerr << "Cannot find lens in database\n";
        lf_free(lenses);
        return -1;
    } else {
        std::cerr << "Lens name ambiguous\n";
    }
    lf_free(lenses);

    Image image;
    {
        std::ifstream file(argv[1], std::ios::binary);
        file >> image;
    }

    lfModifier modifier(camera->CropFactor, image.width, image.height, image.pixel_format());
    lfModifier pc_coord_modifier(camera->CropFactor, image.width, image.height, image.pixel_format(), true);
    lfModifier back_modifier(camera->CropFactor, image.width, image.height, image.pixel_format(), true);
    if (!modifier.EnableDistortionCorrection(lens, 50) || !back_modifier.EnableDistortionCorrection(lens, 50) ||
        !pc_coord_modifier.EnableDistortionCorrection(lens, 50)) {
        std::cerr << "Failed to activate undistortion\n";
        return -1;
    }
    if (image.channels == 3)
        if (!modifier.EnableTCACorrection(lens, 50)) {
            std::cerr << "Failed to activate un-TCA\n";
            return -1;
        }
    std::vector<float> x, y;
    x.push_back(std::stof(argv[2]));
    y.push_back(std::stof(argv[3]));

    x.push_back(std::stof(argv[6]));
    y.push_back(std::stof(argv[7]));

    x.push_back(std::stof(argv[4]));
    y.push_back(std::stof(argv[5]));

    x.push_back(std::stof(argv[8]));
    y.push_back(std::stof(argv[9]));

    x.push_back(std::stof(argv[2]));
    y.push_back(std::stof(argv[3]));

    x.push_back(std::stof(argv[4]));
    y.push_back(std::stof(argv[5]));
    std::vector<float> x_undist, y_undist;
    for (int i = 0; i < x.size(); i++) {
        float result[2];
        pc_coord_modifier.ApplyGeometryDistortion(x[i], y[i], 1, 1, result);
        x_undist.push_back(result[0]);
        y_undist.push_back(result[1]);
    }
    if (!modifier.EnablePerspectiveCorrection(lens, 50, x_undist.data(), y_undist.data(), 6, 0) ||
        !back_modifier.EnablePerspectiveCorrection(lens, 50, x_undist.data(), y_undist.data(), 6, 0)) {
        std::cerr << "Failed to activate perspective correction\n";
        return -1;
    }

    std::vector<float> res(image.width * image.height * 2 * image.channels);
    if (image.channels == 3)
        modifier.ApplySubpixelGeometryDistortion(0, 0, image.width, image.height, res.data());
    else
        modifier.ApplyGeometryDistortion(0, 0, image.width, image.height, res.data());
    Image new_image = image;
    for (int x = 0; x < image.width; x++)
        for (int y = 0; y < image.height; y++) {
            int position = 2 * image.channels * (y * image.width + x);
            float source_x_R = res[position];
            float source_y_R = res[position + 1];
            new_image.set(x, y, 0, image.get(source_x_R, source_y_R, 0));
            if (image.channels == 3) {
                float source_x_G = res[position + 2];
                float source_y_G = res[position + 3];
                float source_x_B = res[position + 4];
                float source_y_B = res[position + 5];
                new_image.set(x, y, 1, image.get(source_x_G, source_y_G, 1));
                new_image.set(x, y, 2, image.get(source_x_B, source_y_B, 2));
            }
        }
    std::ofstream file(argv[1], std::ios::binary);
    file << new_image;

    for (int i = 0; i < 4; i++) {
        float result[2];
        back_modifier.ApplyGeometryDistortion(x[i], y[i], 1, 1, result);
        x[i] = result[0];
        y[i] = result[1];
    }
    std::cout << "[" << std::min(x[0], x[2]) << ", " << std::min(y[0], y[1]) <<
        ", " << std::max(x[1], x[3]) - std::min(x[0], x[2]) << ", " << std::max(y[2], y[3]) - std::min(y[0], y[1]) << "]\n";

    return 0;
}
<commit_msg>Added notice that undistort only works for the Sony E 50mm f/1.8 OSS.<commit_after>/**
   \file undistort.cc

   Apply Lensfun corrections to a PNM file in place.  This means, the original
   file is overwritten.  The command line parameters are:
   - path to the PNM file
   - x coordinate of top left corner
   - y coordinate of top left corner
   - x coordinate of top right corner
   - y coordinate of top right corner
   - x coordinate of bottom left corner
   - y coordinate of bottom left corner
   - x coordinate of bottom right corner
   - y coordinate of bottom right corner

   All coordinates are pixel coordinates, with the top left of the image the
   origin.  The corners must be the corners of a perfect rectangle which was
   taken a picture of, e.g. a sheet of paper.  These are used for the
   perspective correction as well as the rotation, so that the edges of the
   rectangle are parellel to the image borders.

   The program returns the position and the dimensions of the rectangle in
   the output image to stdout in JSON format:

   \code{.json}
   [x₀, y₀, width, height]
   \endcode

   Here, x₀ and y₀ are the coordinates of the top left corner, and width and
   height are the dimensions of the rectangle.

   This program does not apply colour corrections such as vignetting
   correction, as those are handled by kamscan.py using flat field images.

   \b Important: This program has my lens hardcoded into it, the 50mm f/1.8 OSS
   for the Sony E mount.  It was necessary to make a special calibration for
   the finite distance to the subject.  Lensfun contains corrections for focus
   at infinity.
*/
#include <fstream>
#include <vector>
#include <iterator>
#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include "lensfun.h"

/** Class for bitmap data.

  In case of 2 bytes per channel, network byte order is assumed. */
class Image {
public:
    Image(int width, int height, int channel_size, int channels);
    Image() {};
    Image(const Image &image);
    /** Get the channel intensity at a certian coordinate.
      \param x x coordinate
      \param y y coordinate
      \param channel index of the channel (for greyscale, it is always zero;
        for RGB, it is 0, 1, or 2)
      \return raw integer value of the intensity of this channel at this
        position
    */
    int get(int x, int y, int channel);
    /** Get the channel intensity at a certian coordinate.  The coordinates are
      floats and may contain fractions.  In this case, the intensity is
      calculated using bilinear interpolation between the four pixels around
      this coordinate.
      \param x x coordinate
      \param y y coordinate
      \param channel index of the channel (for greyscale, it is always zero;
        for RGB, it is 0, 1, or 2)
      \return raw integer value of the intensity of this channel at this
        position
    */
    int get(float x, float y, int channel);
    /** Set the channel intensity at a certian coordinate.
      \param x x coordinate
      \param y y coordinate
      \param channel index of the channel (for greyscale, it is always zero;
        for RGB, it is 0, 1, or 2)
      \param value raw integer value of the intensity of this channel at this
        position
    */
    void set(int x, int y, int channel, int value);
    /** Determine the channel descriptions.  This is used by Lensfun internally
      and necessary if you want to apply colour corrections, e.g. vignetting
      correction.
      \return the components of each pixel
    */
    int components();
    /** Determine the pixel format à la Lensfun.  It is derived from
      channel_size.
      \return the pixel format as it is needed by Lensfun
     */
    lfPixelFormat pixel_format();
    int width, height; ///< width and height of the image in pixels
    int channels; ///< number of channels; may be 1 (greyscale) or 3 (RGB)
    /** the raw data (1:1 dump of the PNM content, without header)
     */
    std::vector<unsigned char> data;

private:
    friend std::istream& operator>>(std::istream &inputStream, Image &other);
    friend std::ostream& operator<<(std::ostream &outputStream, const Image &other);
    int channel_size; ///< width of one channel in bytes; may be 1 or 2
};

Image::Image(int width, int height, int channel_size, int channels) :
    width(width), height(height), channel_size(channel_size), channels(channels)
{
    data.resize(width * height * channel_size * channels);
}

Image::Image(const Image &image) :
    width(image.width), height(image.height), channel_size(image.channel_size), channels(image.channels) {
}

int Image::get(int x, int y, int channel) {
    if (x < 0 || x >= width || y < 0 || y >= height)
        return 0;
    int position = channel_size * (channels * (y * width + x) + channel);
    int result = static_cast<int>(data[position]);
    if (channel_size == 2)
        result = (result << 8) + static_cast<int>(data[position + 1]);
    return result;
}

int Image::get(float x, float y, int channel) {
    float dummy;
    int x0 = static_cast<int>(x);
    int y0 = static_cast<int>(y);
    float i0 = static_cast<float>(get(x0, y0, channel));
    float i1 = static_cast<float>(get(x0 + 1, y0, channel));
    float i2 = static_cast<float>(get(x0, y0 + 1, channel));
    float i3 = static_cast<float>(get(x0 + 1, y0 + 1, channel));
    float fraction_x = std::modf(x, &dummy);
    float i01 = (1 - fraction_x) * i0 + fraction_x * i1;
    float i23 = (1 - fraction_x) * i2 + fraction_x * i3;
    float fraction_y = std::modf(y, &dummy);
    return static_cast<int>(std::round((1 - fraction_y) * i01 + fraction_y * i23));
}

void Image::set(int x, int y, int channel, int value) {
    if (x >= 0 && x < width && y >= 0 && y < height) {
        int position = channel_size * (channels * (y * width + x) + channel);
        if (channel_size == 1)
            data[position] = static_cast<unsigned char>(value);
        else if (channel_size == 2) {
            data[position] = static_cast<unsigned char>(value >> 8);
            data[position + 1] = static_cast<unsigned char>(value & 256);
        }
    }
}

int Image::components() {
    switch (channels) {
    case 1:
        return LF_CR_1(INTENSITY);
    case 3:
        return LF_CR_3(RED, GREEN, BLUE);
    default:
        throw std::runtime_error("Invalid value of 'channels'.");
    }
}

lfPixelFormat Image::pixel_format() {
    switch (channel_size) {
    case 1:
        return LF_PF_U8;
    case 2:
        return LF_PF_U16;
    default:
        throw std::runtime_error("Invalid value of 'channel_size'.");
    }
}

std::istream& operator>>(std::istream &inputStream, Image &other)
{
    std::string magic_number;
    int maximum_color_value;
    inputStream >> magic_number;
    if (magic_number == "P5")
        other.channels = 1;
    else if (magic_number == "P6")
        other.channels = 3;
    else
        throw std::runtime_error("Invalid input file.  Must start with 'P5' or 'P6'.");
    inputStream >> other.width >> other.height >> maximum_color_value;
    inputStream.get(); // skip the trailing white space
    switch (maximum_color_value) {
    case 255:
        other.channel_size = 1;
        break;
    case 65535:
        other.channel_size = 2;
        break;
    default:
        throw std::runtime_error("Invalid PPM file: Maximum color value must be 255 or 65535.");
    }
    size_t size = other.width * other.height * other.channel_size * other.channels;
    other.data.resize(size);
    inputStream.read(reinterpret_cast<char*>(other.data.data()), size);
    return inputStream;
}

std::ostream& operator<<(std::ostream &outputStream, const Image &other)
{
    outputStream << (other.channels == 3 ? "P6" : "P5") << "\n"
                 << other.width << " "
                 << other.height << "\n"
                 << (other.channel_size == 1 ? "255" : "65535") << "\n";
    outputStream.write(reinterpret_cast<const char*>(other.data.data()), other.data.size());
    return outputStream;
}

int main(int argc, char* argv[]) {
    if (argc != 10) {
        std::cerr << "You must give path to input file as well as all four corner coordinates.\n";
        return -1;
    }

    lfDatabase ldb;

    if (ldb.Load() != LF_NO_ERROR) {
        std::cerr << "Database could not be loaded\n";
        return -1;
    }

    const lfCamera *camera;
    const lfCamera **cameras = ldb.FindCamerasExt(NULL, "NEX-7");
    if (cameras && !cameras[1])
        camera = cameras[0];
    else {
        std::cerr << "Cannot find unique camera in database.  " << sizeof(cameras) << " cameras found.\n";
        lf_free(cameras);
        return -1;
    }
    lf_free(cameras);

    const lfLens *lens;
    const lfLens **lenses = ldb.FindLenses(camera, NULL, "E 50mm f/1.8 OSS (kamscan)");
    if (lenses && !lenses[1]) {
        lens = lenses[0];
    } else if (!lenses) {
        std::cerr << "Cannot find lens in database\n";
        lf_free(lenses);
        return -1;
    } else {
        std::cerr << "Lens name ambiguous\n";
    }
    lf_free(lenses);

    Image image;
    {
        std::ifstream file(argv[1], std::ios::binary);
        file >> image;
    }

    lfModifier modifier(camera->CropFactor, image.width, image.height, image.pixel_format());
    lfModifier pc_coord_modifier(camera->CropFactor, image.width, image.height, image.pixel_format(), true);
    lfModifier back_modifier(camera->CropFactor, image.width, image.height, image.pixel_format(), true);
    if (!modifier.EnableDistortionCorrection(lens, 50) || !back_modifier.EnableDistortionCorrection(lens, 50) ||
        !pc_coord_modifier.EnableDistortionCorrection(lens, 50)) {
        std::cerr << "Failed to activate undistortion\n";
        return -1;
    }
    if (image.channels == 3)
        if (!modifier.EnableTCACorrection(lens, 50)) {
            std::cerr << "Failed to activate un-TCA\n";
            return -1;
        }
    std::vector<float> x, y;
    x.push_back(std::stof(argv[2]));
    y.push_back(std::stof(argv[3]));

    x.push_back(std::stof(argv[6]));
    y.push_back(std::stof(argv[7]));

    x.push_back(std::stof(argv[4]));
    y.push_back(std::stof(argv[5]));

    x.push_back(std::stof(argv[8]));
    y.push_back(std::stof(argv[9]));

    x.push_back(std::stof(argv[2]));
    y.push_back(std::stof(argv[3]));

    x.push_back(std::stof(argv[4]));
    y.push_back(std::stof(argv[5]));
    std::vector<float> x_undist, y_undist;
    for (int i = 0; i < x.size(); i++) {
        float result[2];
        pc_coord_modifier.ApplyGeometryDistortion(x[i], y[i], 1, 1, result);
        x_undist.push_back(result[0]);
        y_undist.push_back(result[1]);
    }
    if (!modifier.EnablePerspectiveCorrection(lens, 50, x_undist.data(), y_undist.data(), 6, 0) ||
        !back_modifier.EnablePerspectiveCorrection(lens, 50, x_undist.data(), y_undist.data(), 6, 0)) {
        std::cerr << "Failed to activate perspective correction\n";
        return -1;
    }

    std::vector<float> res(image.width * image.height * 2 * image.channels);
    if (image.channels == 3)
        modifier.ApplySubpixelGeometryDistortion(0, 0, image.width, image.height, res.data());
    else
        modifier.ApplyGeometryDistortion(0, 0, image.width, image.height, res.data());
    Image new_image = image;
    for (int x = 0; x < image.width; x++)
        for (int y = 0; y < image.height; y++) {
            int position = 2 * image.channels * (y * image.width + x);
            float source_x_R = res[position];
            float source_y_R = res[position + 1];
            new_image.set(x, y, 0, image.get(source_x_R, source_y_R, 0));
            if (image.channels == 3) {
                float source_x_G = res[position + 2];
                float source_y_G = res[position + 3];
                float source_x_B = res[position + 4];
                float source_y_B = res[position + 5];
                new_image.set(x, y, 1, image.get(source_x_G, source_y_G, 1));
                new_image.set(x, y, 2, image.get(source_x_B, source_y_B, 2));
            }
        }
    std::ofstream file(argv[1], std::ios::binary);
    file << new_image;

    for (int i = 0; i < 4; i++) {
        float result[2];
        back_modifier.ApplyGeometryDistortion(x[i], y[i], 1, 1, result);
        x[i] = result[0];
        y[i] = result[1];
    }
    std::cout << "[" << std::min(x[0], x[2]) << ", " << std::min(y[0], y[1]) <<
        ", " << std::max(x[1], x[3]) - std::min(x[0], x[2]) << ", " << std::max(y[2], y[3]) - std::min(y[0], y[1]) << "]\n";

    return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>

#include <kcpolydb.h>

long estimate_a(long *pack) {
  return (
    4 + pack[0] * 8 +
    4 + 1 + pack[1] * 8 * 5 +
    4 + 1 + pack[2] * 8 * 5 + 3 * 11 * 1 +
    4 + 1 + pack[3] * 8 * 5 + 3 * 11 * 2 +
    4 + 1 + pack[4] * 8 * 5 + 3 * 11 * 4 +
    4 + 1 + pack[5] * 8 * 5 + 3 * 11 * 6
  );
}

long estimate_b(long *pack) {
  return (
    4 + pack[0] * 9 +
    4 + 1 + pack[1] * 9 * 5 +
    4 + 1 + pack[2] * 9 * 5 + 4 * 2 * 3 * 8 * 1 +
    4 + 1 + pack[3] * 9 * 5 + 4 * 2 * 3 * 8 * 2 +
    4 + 1 + pack[4] * 9 * 5 + 4 * 2 * 3 * 8 * 4 +
    4 + 1 + pack[5] * 9 * 5 + 4 * 2 * 3 * 8 * 6
  );
}

int main(int argc, char **argv) {
    if (argc <= 1) {
      std::cout << "Usage: stat <dbfile.kct>" << std::endl;
      return 1;
    }

    kyotocabinet::TreeDB db;

    if (!db.open(argv[1], kyotocabinet::TreeDB::OREADER)) {
      std::cout << "Could not open database." << std::endl;
      return 2;
    }

    std::auto_ptr<kyotocabinet::TreeDB::Cursor> cur(db.cursor());
    cur->jump();

    std::string key, value;

    long pack[] = {0, 0, 0, 0, 0, 0};

    while (cur->get(&key, &value, true)) {
        if (value.size() == 8) {
            pack[0]++;
        } else {
            pack[value.at(0)]++;
        }
    }

    for (int i = 0; i < 5; i++) {
        std::cout << "Pack format " << i << ": " << pack[i] << " nodes " << std::endl;
    }

    std::cout << "Unique positions: " << (pack[0] + pack[1] + pack[2] + pack[3] + pack[4] + pack[5]) << std::endl;

    std::cout << std::endl;

    std::cout << "Scheme A: " << estimate_a(pack) << " bytes" << std::endl;
    std::cout << "Scheme B: " << estimate_b(pack) << " bytes" << std::endl;
    std::cout << "B/A: " << ((double)estimate_b(pack)/estimate_a(pack)) << std::endl;

    return 0;
}
<commit_msg>Show progress<commit_after>#include <iostream>
#include <string>

#include <kcpolydb.h>

long estimate_a(long *pack) {
  return (
    4 + pack[0] * 8 +
    4 + 1 + pack[1] * 8 * 5 +
    4 + 1 + pack[2] * 8 * 5 + 3 * 11 * 1 +
    4 + 1 + pack[3] * 8 * 5 + 3 * 11 * 2 +
    4 + 1 + pack[4] * 8 * 5 + 3 * 11 * 4 +
    4 + 1 + pack[5] * 8 * 5 + 3 * 11 * 6
  );
}

long estimate_b(long *pack) {
  return (
    4 + pack[0] * 9 +
    4 + 1 + pack[1] * 9 * 5 +
    4 + 1 + pack[2] * 9 * 5 + 4 * 2 * 3 * 8 * 1 +
    4 + 1 + pack[3] * 9 * 5 + 4 * 2 * 3 * 8 * 2 +
    4 + 1 + pack[4] * 9 * 5 + 4 * 2 * 3 * 8 * 4 +
    4 + 1 + pack[5] * 9 * 5 + 4 * 2 * 3 * 8 * 6
  );
}

int main(int argc, char **argv) {
    if (argc <= 1) {
      std::cout << "Usage: stat <dbfile.kct>" << std::endl;
      return 1;
    }

    kyotocabinet::TreeDB db;

    if (!db.open(argv[1], kyotocabinet::TreeDB::OREADER)) {
      std::cout << "Could not open database." << std::endl;
      return 2;
    }

    std::auto_ptr<kyotocabinet::TreeDB::Cursor> cur(db.cursor());
    cur->jump();

    std::string key, value;

    long pack[] = {0, 0, 0, 0, 0, 0};
    long total = 0;

    std::cout << "Scanning ..." << std::endl;

    while (cur->get(&key, &value, true)) {
        total++;
        if (value.size() == 8) {
            pack[0]++;
        } else {
            pack[value.at(0)]++;
        }

        if (total % 50000 == 0) {
            std::cerr << ".";
        }
    }

    std::cerr << std::endl;

    for (int i = 0; i < 5; i++) {
        std::cout << "Pack format " << i << ": " << pack[i] << " nodes " << std::endl;
    }

    std::cout << "Unique positions: " << total << std::endl;

    std::cout << std::endl;

    std::cout << "Scheme A: " << estimate_a(pack) << " bytes" << std::endl;
    std::cout << "Scheme B: " << estimate_b(pack) << " bytes" << std::endl;
    std::cout << "B/A: " << ((double)estimate_b(pack)/estimate_a(pack)) << std::endl;

    return 0;
}
<|endoftext|>