<commit_before>//===- AliasAnalysis.cpp - Generic Alias Analysis Interface Implementation -==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the generic AliasAnalysis interface which is used as the
// common interface used by all clients and implementations of alias analysis.
//
// This file also implements the default version of the AliasAnalysis interface
// that is to be used when no other implementation is specified.  This does some
// simple tests that detect obvious cases: two different global pointers cannot
// alias, a global cannot alias a malloc, two different mallocs cannot alias,
// etc.
//
// This alias analysis implementation really isn't very good for anything, but
// it is very fast, and makes a nice clean default implementation.  Because it
// handles lots of little corner cases, other, more complex, alias analysis
// implementations may choose to rely on this pass to resolve these simple and
// easy cases.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Pass.h"
#include "llvm/BasicBlock.h"
#include "llvm/Function.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Instructions.h"
#include "llvm/LLVMContext.h"
#include "llvm/Type.h"
#include "llvm/Target/TargetData.h"
using namespace llvm;

// Register the AliasAnalysis interface, providing a nice name to refer to.
INITIALIZE_ANALYSIS_GROUP(AliasAnalysis, "Alias Analysis", NoAA)
char AliasAnalysis::ID = 0;

//===----------------------------------------------------------------------===//
// Default chaining methods
//===----------------------------------------------------------------------===//

AliasAnalysis::AliasResult
AliasAnalysis::alias(const Location &LocA, const Location &LocB) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");
  return AA->alias(LocA, LocB);
}

bool AliasAnalysis::pointsToConstantMemory(const Location &Loc) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");
  return AA->pointsToConstantMemory(Loc);
}

void AliasAnalysis::deleteValue(Value *V) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");
  AA->deleteValue(V);
}

void AliasAnalysis::copyValue(Value *From, Value *To) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");
  AA->copyValue(From, To);
}

AliasAnalysis::ModRefResult
AliasAnalysis::getModRefInfo(ImmutableCallSite CS,
                             const Location &Loc) {
  // Don't assert AA because BasicAA calls us in order to make use of the
  // logic here.

  ModRefBehavior MRB = getModRefBehavior(CS);
  if (MRB == DoesNotAccessMemory)
    return NoModRef;

  ModRefResult Mask = ModRef;
  if (MRB == OnlyReadsMemory)
    Mask = Ref;
  else if (MRB == AliasAnalysis::AccessesArguments) {
    bool doesAlias = false;
    for (ImmutableCallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end();
         AI != AE; ++AI)
      if (!isNoAlias(Location(*AI), Loc)) {
        doesAlias = true;
        break;
      }

    if (!doesAlias)
      return NoModRef;
  }

  // If Loc is a constant memory location, the call definitely could not
  // modify the memory location.
  if ((Mask & Mod) && pointsToConstantMemory(Loc))
    Mask = ModRefResult(Mask & ~Mod);

  // If this is BasicAA, don't forward.
  if (!AA) return Mask;

  // Otherwise, fall back to the next AA in the chain. But we can merge
  // in any mask we've managed to compute.
  return ModRefResult(AA->getModRefInfo(CS, Loc) & Mask);
}

AliasAnalysis::ModRefResult
AliasAnalysis::getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) {
  // Don't assert AA because BasicAA calls us in order to make use of the
  // logic here.

  // If CS1 or CS2 are readnone, they don't interact.
  ModRefBehavior CS1B = getModRefBehavior(CS1);
  if (CS1B == DoesNotAccessMemory) return NoModRef;

  ModRefBehavior CS2B = getModRefBehavior(CS2);
  if (CS2B == DoesNotAccessMemory) return NoModRef;

  // If they both only read from memory, there is no dependence.
  if (CS1B == OnlyReadsMemory && CS2B == OnlyReadsMemory)
    return NoModRef;

  AliasAnalysis::ModRefResult Mask = ModRef;

  // If CS1 only reads memory, the only dependence on CS2 can be
  // from CS1 reading memory written by CS2.
  if (CS1B == OnlyReadsMemory)
    Mask = ModRefResult(Mask & Ref);

  // If CS2 only access memory through arguments, accumulate the mod/ref
  // information from CS1's references to the memory referenced by
  // CS2's arguments.
  if (CS2B == AccessesArguments) {
    AliasAnalysis::ModRefResult R = NoModRef;
    for (ImmutableCallSite::arg_iterator
         I = CS2.arg_begin(), E = CS2.arg_end(); I != E; ++I) {
      R = ModRefResult((R | getModRefInfo(CS1, *I, UnknownSize)) & Mask);
      if (R == Mask)
        break;
    }
    return R;
  }

  // If CS1 only accesses memory through arguments, check if CS2 references
  // any of the memory referenced by CS1's arguments. If not, return NoModRef.
  if (CS1B == AccessesArguments) {
    AliasAnalysis::ModRefResult R = NoModRef;
    for (ImmutableCallSite::arg_iterator
         I = CS1.arg_begin(), E = CS1.arg_end(); I != E; ++I)
      if (getModRefInfo(CS2, *I, UnknownSize) != NoModRef) {
        R = Mask;
        break;
      }
    if (R == NoModRef)
      return R;
  }

  // If this is BasicAA, don't forward.
  if (!AA) return Mask;

  // Otherwise, fall back to the next AA in the chain. But we can merge
  // in any mask we've managed to compute.
  return ModRefResult(AA->getModRefInfo(CS1, CS2) & Mask);
}

AliasAnalysis::ModRefBehavior
AliasAnalysis::getModRefBehavior(ImmutableCallSite CS) {
  // Don't assert AA because BasicAA calls us in order to make use of the
  // logic here.

  ModRefBehavior Min = UnknownModRefBehavior;

  // Call back into the alias analysis with the other form of getModRefBehavior
  // to see if it can give a better response.
  if (const Function *F = CS.getCalledFunction())
    Min = getModRefBehavior(F);

  // If this is BasicAA, don't forward.
  if (!AA) return Min;

  // Otherwise, fall back to the next AA in the chain. But we can merge
  // in any result we've managed to compute.
  return std::min(AA->getModRefBehavior(CS), Min);
}

AliasAnalysis::ModRefBehavior
AliasAnalysis::getModRefBehavior(const Function *F) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");
  return AA->getModRefBehavior(F);
}

//===----------------------------------------------------------------------===//
// AliasAnalysis non-virtual helper method implementation
//===----------------------------------------------------------------------===//

AliasAnalysis::ModRefResult
AliasAnalysis::getModRefInfo(const LoadInst *L, const Location &Loc) {
  // Be conservative in the face of volatile.
  if (L->isVolatile())
    return ModRef;

  // If the load address doesn't alias the given address, it doesn't read
  // or write the specified memory.
  if (!alias(Location(L->getOperand(0),
                      getTypeStoreSize(L->getType()),
                      L->getMetadata(LLVMContext::MD_tbaa)),
             Loc))
    return NoModRef;

  // Otherwise, a load just reads.
  return Ref;
}

AliasAnalysis::ModRefResult
AliasAnalysis::getModRefInfo(const StoreInst *S, const Location &Loc) {
  // Be conservative in the face of volatile.
  if (S->isVolatile())
    return ModRef;

  // If the store address cannot alias the pointer in question, then the
  // specified memory cannot be modified by the store.
  if (!alias(Location(S->getOperand(1),
                      getTypeStoreSize(S->getOperand(0)->getType()),
                      S->getMetadata(LLVMContext::MD_tbaa)),
             Loc))
    return NoModRef;

  // If the pointer is a pointer to constant memory, then it could not have been
  // modified by this store.
  if (pointsToConstantMemory(Loc))
    return NoModRef;

  // Otherwise, a store just writes.
  return Mod;
}

AliasAnalysis::ModRefResult
AliasAnalysis::getModRefInfo(const VAArgInst *V, const Location &Loc) {
  // If the va_arg address cannot alias the pointer in question, then the
  // specified memory cannot be accessed by the va_arg.
  if (!alias(Location(V->getOperand(0),
                      UnknownSize,
                      V->getMetadata(LLVMContext::MD_tbaa)),
             Loc))
    return NoModRef;

  // If the pointer is a pointer to constant memory, then it could not have been
  // modified by this va_arg.
  if (pointsToConstantMemory(Loc))
    return NoModRef;

  // Otherwise, a va_arg reads and writes.
  return ModRef;
}

AliasAnalysis::ModRefBehavior
AliasAnalysis::getIntrinsicModRefBehavior(unsigned iid) {
#define GET_INTRINSIC_MODREF_BEHAVIOR
#include "llvm/Intrinsics.gen"
#undef GET_INTRINSIC_MODREF_BEHAVIOR
}

// AliasAnalysis destructor: DO NOT move this to the header file for
// AliasAnalysis or else clients of the AliasAnalysis class may not depend on
// the AliasAnalysis.o file in the current .a file, causing alias analysis
// support to not be included in the tool correctly!
//
AliasAnalysis::~AliasAnalysis() {}

/// InitializeAliasAnalysis - Subclasses must call this method to initialize the
/// AliasAnalysis interface before any other methods are called.
///
void AliasAnalysis::InitializeAliasAnalysis(Pass *P) {
  TD = P->getAnalysisIfAvailable<TargetData>();
  AA = &P->getAnalysis<AliasAnalysis>();
}

// getAnalysisUsage - All alias analysis implementations should invoke this
// directly (using AliasAnalysis::getAnalysisUsage(AU)).
void AliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<AliasAnalysis>();         // All AA's chain
}

/// getTypeStoreSize - Return the TargetData store size for the given type,
/// if known, or a conservative value otherwise.
///
uint64_t AliasAnalysis::getTypeStoreSize(const Type *Ty) {
  return TD ? TD->getTypeStoreSize(Ty) : UnknownSize;
}

/// canBasicBlockModify - Return true if it is possible for execution of the
/// specified basic block to modify the value pointed to by Ptr.
///
bool AliasAnalysis::canBasicBlockModify(const BasicBlock &BB,
                                        const Location &Loc) {
  return canInstructionRangeModify(BB.front(), BB.back(), Loc);
}

/// canInstructionRangeModify - Return true if it is possible for the execution
/// of the specified instructions to modify the value pointed to by Ptr.  The
/// instructions to consider are all of the instructions in the range of [I1,I2]
/// INCLUSIVE.  I1 and I2 must be in the same basic block.
///
bool AliasAnalysis::canInstructionRangeModify(const Instruction &I1,
                                              const Instruction &I2,
                                              const Location &Loc) {
  assert(I1.getParent() == I2.getParent() &&
         "Instructions not in same basic block!");
  BasicBlock::const_iterator I = &I1;
  BasicBlock::const_iterator E = &I2;
  ++E;  // Convert from inclusive to exclusive range.

  for (; I != E; ++I) // Check every instruction in range
    if (getModRefInfo(I, Loc) & Mod)
      return true;
  return false;
}

/// isNoAliasCall - Return true if this pointer is returned by a noalias
/// function.
bool llvm::isNoAliasCall(const Value *V) {
  if (isa<CallInst>(V) || isa<InvokeInst>(V))
    return ImmutableCallSite(cast<Instruction>(V))
      .paramHasAttr(0, Attribute::NoAlias);
  return false;
}

/// isIdentifiedObject - Return true if this pointer refers to a distinct and
/// identifiable object.  This returns true for:
///    Global Variables and Functions (but not Global Aliases)
///    Allocas and Mallocs
///    ByVal and NoAlias Arguments
///    NoAlias returns
///
bool llvm::isIdentifiedObject(const Value *V) {
  if (isa<AllocaInst>(V))
    return true;
  if (isa<GlobalValue>(V) && !isa<GlobalAlias>(V))
    return true;
  if (isNoAliasCall(V))
    return true;
  if (const Argument *A = dyn_cast<Argument>(V))
    return A->hasNoAliasAttr() || A->hasByValAttr();
  return false;
}
<commit_msg>Reintroduce these asserts, now that BasicAA is a normal AliasAnalysis pass.<commit_after>//===- AliasAnalysis.cpp - Generic Alias Analysis Interface Implementation -==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the generic AliasAnalysis interface which is used as the
// common interface used by all clients and implementations of alias analysis.
//
// This file also implements the default version of the AliasAnalysis interface
// that is to be used when no other implementation is specified.  This does some
// simple tests that detect obvious cases: two different global pointers cannot
// alias, a global cannot alias a malloc, two different mallocs cannot alias,
// etc.
//
// This alias analysis implementation really isn't very good for anything, but
// it is very fast, and makes a nice clean default implementation.  Because it
// handles lots of little corner cases, other, more complex, alias analysis
// implementations may choose to rely on this pass to resolve these simple and
// easy cases.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Pass.h"
#include "llvm/BasicBlock.h"
#include "llvm/Function.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Instructions.h"
#include "llvm/LLVMContext.h"
#include "llvm/Type.h"
#include "llvm/Target/TargetData.h"
using namespace llvm;

// Register the AliasAnalysis interface, providing a nice name to refer to.
INITIALIZE_ANALYSIS_GROUP(AliasAnalysis, "Alias Analysis", NoAA)
char AliasAnalysis::ID = 0;

//===----------------------------------------------------------------------===//
// Default chaining methods
//===----------------------------------------------------------------------===//

AliasAnalysis::AliasResult
AliasAnalysis::alias(const Location &LocA, const Location &LocB) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");
  return AA->alias(LocA, LocB);
}

bool AliasAnalysis::pointsToConstantMemory(const Location &Loc) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");
  return AA->pointsToConstantMemory(Loc);
}

void AliasAnalysis::deleteValue(Value *V) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");
  AA->deleteValue(V);
}

void AliasAnalysis::copyValue(Value *From, Value *To) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");
  AA->copyValue(From, To);
}

AliasAnalysis::ModRefResult
AliasAnalysis::getModRefInfo(ImmutableCallSite CS,
                             const Location &Loc) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");

  ModRefBehavior MRB = getModRefBehavior(CS);
  if (MRB == DoesNotAccessMemory)
    return NoModRef;

  ModRefResult Mask = ModRef;
  if (MRB == OnlyReadsMemory)
    Mask = Ref;
  else if (MRB == AliasAnalysis::AccessesArguments) {
    bool doesAlias = false;
    for (ImmutableCallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end();
         AI != AE; ++AI)
      if (!isNoAlias(Location(*AI), Loc)) {
        doesAlias = true;
        break;
      }

    if (!doesAlias)
      return NoModRef;
  }

  // If Loc is a constant memory location, the call definitely could not
  // modify the memory location.
  if ((Mask & Mod) && pointsToConstantMemory(Loc))
    Mask = ModRefResult(Mask & ~Mod);

  // If this is BasicAA, don't forward.
  if (!AA) return Mask;

  // Otherwise, fall back to the next AA in the chain. But we can merge
  // in any mask we've managed to compute.
  return ModRefResult(AA->getModRefInfo(CS, Loc) & Mask);
}

AliasAnalysis::ModRefResult
AliasAnalysis::getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");

  // If CS1 or CS2 are readnone, they don't interact.
  ModRefBehavior CS1B = getModRefBehavior(CS1);
  if (CS1B == DoesNotAccessMemory) return NoModRef;

  ModRefBehavior CS2B = getModRefBehavior(CS2);
  if (CS2B == DoesNotAccessMemory) return NoModRef;

  // If they both only read from memory, there is no dependence.
  if (CS1B == OnlyReadsMemory && CS2B == OnlyReadsMemory)
    return NoModRef;

  AliasAnalysis::ModRefResult Mask = ModRef;

  // If CS1 only reads memory, the only dependence on CS2 can be
  // from CS1 reading memory written by CS2.
  if (CS1B == OnlyReadsMemory)
    Mask = ModRefResult(Mask & Ref);

  // If CS2 only access memory through arguments, accumulate the mod/ref
  // information from CS1's references to the memory referenced by
  // CS2's arguments.
  if (CS2B == AccessesArguments) {
    AliasAnalysis::ModRefResult R = NoModRef;
    for (ImmutableCallSite::arg_iterator
         I = CS2.arg_begin(), E = CS2.arg_end(); I != E; ++I) {
      R = ModRefResult((R | getModRefInfo(CS1, *I, UnknownSize)) & Mask);
      if (R == Mask)
        break;
    }
    return R;
  }

  // If CS1 only accesses memory through arguments, check if CS2 references
  // any of the memory referenced by CS1's arguments. If not, return NoModRef.
  if (CS1B == AccessesArguments) {
    AliasAnalysis::ModRefResult R = NoModRef;
    for (ImmutableCallSite::arg_iterator
         I = CS1.arg_begin(), E = CS1.arg_end(); I != E; ++I)
      if (getModRefInfo(CS2, *I, UnknownSize) != NoModRef) {
        R = Mask;
        break;
      }
    if (R == NoModRef)
      return R;
  }

  // If this is BasicAA, don't forward.
  if (!AA) return Mask;

  // Otherwise, fall back to the next AA in the chain. But we can merge
  // in any mask we've managed to compute.
  return ModRefResult(AA->getModRefInfo(CS1, CS2) & Mask);
}

AliasAnalysis::ModRefBehavior
AliasAnalysis::getModRefBehavior(ImmutableCallSite CS) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");

  ModRefBehavior Min = UnknownModRefBehavior;

  // Call back into the alias analysis with the other form of getModRefBehavior
  // to see if it can give a better response.
  if (const Function *F = CS.getCalledFunction())
    Min = getModRefBehavior(F);

  // If this is BasicAA, don't forward.
  if (!AA) return Min;

  // Otherwise, fall back to the next AA in the chain. But we can merge
  // in any result we've managed to compute.
  return std::min(AA->getModRefBehavior(CS), Min);
}

AliasAnalysis::ModRefBehavior
AliasAnalysis::getModRefBehavior(const Function *F) {
  assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!");
  return AA->getModRefBehavior(F);
}

//===----------------------------------------------------------------------===//
// AliasAnalysis non-virtual helper method implementation
//===----------------------------------------------------------------------===//

AliasAnalysis::ModRefResult
AliasAnalysis::getModRefInfo(const LoadInst *L, const Location &Loc) {
  // Be conservative in the face of volatile.
  if (L->isVolatile())
    return ModRef;

  // If the load address doesn't alias the given address, it doesn't read
  // or write the specified memory.
  if (!alias(Location(L->getOperand(0),
                      getTypeStoreSize(L->getType()),
                      L->getMetadata(LLVMContext::MD_tbaa)),
             Loc))
    return NoModRef;

  // Otherwise, a load just reads.
  return Ref;
}

AliasAnalysis::ModRefResult
AliasAnalysis::getModRefInfo(const StoreInst *S, const Location &Loc) {
  // Be conservative in the face of volatile.
  if (S->isVolatile())
    return ModRef;

  // If the store address cannot alias the pointer in question, then the
  // specified memory cannot be modified by the store.
  if (!alias(Location(S->getOperand(1),
                      getTypeStoreSize(S->getOperand(0)->getType()),
                      S->getMetadata(LLVMContext::MD_tbaa)),
             Loc))
    return NoModRef;

  // If the pointer is a pointer to constant memory, then it could not have been
  // modified by this store.
  if (pointsToConstantMemory(Loc))
    return NoModRef;

  // Otherwise, a store just writes.
  return Mod;
}

AliasAnalysis::ModRefResult
AliasAnalysis::getModRefInfo(const VAArgInst *V, const Location &Loc) {
  // If the va_arg address cannot alias the pointer in question, then the
  // specified memory cannot be accessed by the va_arg.
  if (!alias(Location(V->getOperand(0),
                      UnknownSize,
                      V->getMetadata(LLVMContext::MD_tbaa)),
             Loc))
    return NoModRef;

  // If the pointer is a pointer to constant memory, then it could not have been
  // modified by this va_arg.
  if (pointsToConstantMemory(Loc))
    return NoModRef;

  // Otherwise, a va_arg reads and writes.
  return ModRef;
}

AliasAnalysis::ModRefBehavior
AliasAnalysis::getIntrinsicModRefBehavior(unsigned iid) {
#define GET_INTRINSIC_MODREF_BEHAVIOR
#include "llvm/Intrinsics.gen"
#undef GET_INTRINSIC_MODREF_BEHAVIOR
}

// AliasAnalysis destructor: DO NOT move this to the header file for
// AliasAnalysis or else clients of the AliasAnalysis class may not depend on
// the AliasAnalysis.o file in the current .a file, causing alias analysis
// support to not be included in the tool correctly!
//
AliasAnalysis::~AliasAnalysis() {}

/// InitializeAliasAnalysis - Subclasses must call this method to initialize the
/// AliasAnalysis interface before any other methods are called.
///
void AliasAnalysis::InitializeAliasAnalysis(Pass *P) {
  TD = P->getAnalysisIfAvailable<TargetData>();
  AA = &P->getAnalysis<AliasAnalysis>();
}

// getAnalysisUsage - All alias analysis implementations should invoke this
// directly (using AliasAnalysis::getAnalysisUsage(AU)).
void AliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<AliasAnalysis>();         // All AA's chain
}

/// getTypeStoreSize - Return the TargetData store size for the given type,
/// if known, or a conservative value otherwise.
///
uint64_t AliasAnalysis::getTypeStoreSize(const Type *Ty) {
  return TD ? TD->getTypeStoreSize(Ty) : UnknownSize;
}

/// canBasicBlockModify - Return true if it is possible for execution of the
/// specified basic block to modify the value pointed to by Ptr.
///
bool AliasAnalysis::canBasicBlockModify(const BasicBlock &BB,
                                        const Location &Loc) {
  return canInstructionRangeModify(BB.front(), BB.back(), Loc);
}

/// canInstructionRangeModify - Return true if it is possible for the execution
/// of the specified instructions to modify the value pointed to by Ptr.  The
/// instructions to consider are all of the instructions in the range of [I1,I2]
/// INCLUSIVE.  I1 and I2 must be in the same basic block.
///
bool AliasAnalysis::canInstructionRangeModify(const Instruction &I1,
                                              const Instruction &I2,
                                              const Location &Loc) {
  assert(I1.getParent() == I2.getParent() &&
         "Instructions not in same basic block!");
  BasicBlock::const_iterator I = &I1;
  BasicBlock::const_iterator E = &I2;
  ++E;  // Convert from inclusive to exclusive range.

  for (; I != E; ++I) // Check every instruction in range
    if (getModRefInfo(I, Loc) & Mod)
      return true;
  return false;
}

/// isNoAliasCall - Return true if this pointer is returned by a noalias
/// function.
bool llvm::isNoAliasCall(const Value *V) {
  if (isa<CallInst>(V) || isa<InvokeInst>(V))
    return ImmutableCallSite(cast<Instruction>(V))
      .paramHasAttr(0, Attribute::NoAlias);
  return false;
}

/// isIdentifiedObject - Return true if this pointer refers to a distinct and
/// identifiable object.  This returns true for:
///    Global Variables and Functions (but not Global Aliases)
///    Allocas and Mallocs
///    ByVal and NoAlias Arguments
///    NoAlias returns
///
bool llvm::isIdentifiedObject(const Value *V) {
  if (isa<AllocaInst>(V))
    return true;
  if (isa<GlobalValue>(V) && !isa<GlobalAlias>(V))
    return true;
  if (isNoAliasCall(V))
    return true;
  if (const Argument *A = dyn_cast<Argument>(V))
    return A->hasNoAliasAttr() || A->hasByValAttr();
  return false;
}
<|endoftext|>


<commit_before>#ifndef ITER_ACCUMULATE_H_
#define ITER_ACCUMULATE_H_

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>
#include <functional>
#include <type_traits>

namespace iter {

    //Forward declarations of Accumulator and accumulate
    template <typename Container, typename AccumulateFunc>
    class Accumulator;

    template <typename Container, typename AccumulateFunc>
    Accumulator<Container, AccumulateFunc> accumulate(
            Container&&, AccumulateFunc);

    template <typename T, typename AccumulateFunc>
    Accumulator<std::initializer_list<T>, AccumulateFunc> accumulate(
            std::initializer_list<T>, AccumulateFunc);

    template <typename Container, typename AccumulateFunc>
    class Accumulator {
        private:
            Container container;
            AccumulateFunc accumulate_func;

            friend Accumulator accumulate<Container, AccumulateFunc>(
                    Container&&, AccumulateFunc);

            template <typename T, typename AF>
            friend Accumulator<std::initializer_list<T>, AF> accumulate(
                    std::initializer_list<T>, AF);

            // AccumVal must be default constructible
            using AccumVal =
                typename std::remove_reference<
                    typename std::result_of<AccumulateFunc(
                            iterator_deref<Container>,
                            iterator_deref<Container>)>::type>::type;
            static_assert(
                    std::is_default_constructible<AccumVal>::value,
                    "Cannot accumulate a non-default constructible type");

            Accumulator(Container container, AccumulateFunc accumulate_func)
                : container(std::forward<Container>(container)),
                accumulate_func(accumulate_func)
            { }
        public:

            class Iterator
                : public std::iterator<std::forward_iterator_tag, AccumVal>
            {
                private:
                    iterator_type<Container> sub_iter;
                    const iterator_type<Container> sub_end;
                    AccumulateFunc accumulate_func;
                    AccumVal acc_val;
                public:
                    Iterator (iterator_type<Container> iter,
                            iterator_type<Container> end,
                            AccumulateFunc accumulate_func)
                        : sub_iter{iter},
                        sub_end{end},
                        accumulate_func(accumulate_func),
                        // only get first value if not an end iterator
                        acc_val(!(iter != end) ? AccumVal{} : *iter)
                    { }

                    AccumVal operator*() const {
                        return this->acc_val;
                    }

                    Iterator& operator++() {
                        ++this->sub_iter;
                        if (this->sub_iter != this->sub_end) {
                            this->acc_val = accumulate_func(
                                    this->acc_val, *this->sub_iter);
                        }
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() {
                return {std::begin(this->container),
                        std::end(this->container),
                        this->accumulate_func};
            }

            Iterator end() {
                return {std::end(this->container),
                        std::end(this->container),
                        this->accumulate_func};
            }

    };

    // Helper function to instantiate an Accumulator
    template <typename Container, typename AccumulateFunc>
    Accumulator<Container, AccumulateFunc> accumulate(
            Container&& container,
            AccumulateFunc accumulate_func)
    {
        return {std::forward<Container>(container), accumulate_func};
    }

    template <typename Container>
    auto accumulate(Container&& container) ->
        decltype(accumulate(std::forward<Container>(container),
                    std::plus<typename std::remove_reference<
                        iterator_deref<Container>>::type>{}))
    {
        return accumulate(std::forward<Container>(container),
                    std::plus<typename std::remove_reference<
                        iterator_deref<Container>>::type>{});
    }

    template <typename T, typename AccumulateFunc>
    Accumulator<std::initializer_list<T>, AccumulateFunc> accumulate(
            std::initializer_list<T> il,
            AccumulateFunc accumulate_func)
    {
        return {std::move(il), accumulate_func};
    }

    template <typename T>
    auto accumulate(std::initializer_list<T> il) ->
        decltype(accumulate(std::move(il), std::plus<T>{}))
    {
        return accumulate(std::move(il), std::plus<T>{});
    }

}

#endif //ifndef ITER_ACCUMULATE_H_
<commit_msg>iterator dereferences to const ref to avoid copy<commit_after>#ifndef ITER_ACCUMULATE_H_
#define ITER_ACCUMULATE_H_

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>
#include <functional>
#include <type_traits>

namespace iter {

    //Forward declarations of Accumulator and accumulate
    template <typename Container, typename AccumulateFunc>
    class Accumulator;

    template <typename Container, typename AccumulateFunc>
    Accumulator<Container, AccumulateFunc> accumulate(
            Container&&, AccumulateFunc);

    template <typename T, typename AccumulateFunc>
    Accumulator<std::initializer_list<T>, AccumulateFunc> accumulate(
            std::initializer_list<T>, AccumulateFunc);

    template <typename Container, typename AccumulateFunc>
    class Accumulator {
        private:
            Container container;
            AccumulateFunc accumulate_func;

            friend Accumulator accumulate<Container, AccumulateFunc>(
                    Container&&, AccumulateFunc);

            template <typename T, typename AF>
            friend Accumulator<std::initializer_list<T>, AF> accumulate(
                    std::initializer_list<T>, AF);

            // AccumVal must be default constructible
            using AccumVal =
                typename std::remove_reference<
                    typename std::result_of<AccumulateFunc(
                            iterator_deref<Container>,
                            iterator_deref<Container>)>::type>::type;
            static_assert(
                    std::is_default_constructible<AccumVal>::value,
                    "Cannot accumulate a non-default constructible type");

            Accumulator(Container container, AccumulateFunc accumulate_func)
                : container(std::forward<Container>(container)),
                accumulate_func(accumulate_func)
            { }
        public:

            class Iterator
                : public std::iterator<std::forward_iterator_tag, AccumVal>
            {
                private:
                    iterator_type<Container> sub_iter;
                    const iterator_type<Container> sub_end;
                    AccumulateFunc accumulate_func;
                    AccumVal acc_val;
                public:
                    Iterator (iterator_type<Container> iter,
                            iterator_type<Container> end,
                            AccumulateFunc accumulate_func)
                        : sub_iter{iter},
                        sub_end{end},
                        accumulate_func(accumulate_func),
                        // only get first value if not an end iterator
                        acc_val(!(iter != end) ? AccumVal{} : *iter)
                    { }

                    const AccumVal& operator*() const {
                        return this->acc_val;
                    }

                    Iterator& operator++() {
                        ++this->sub_iter;
                        if (this->sub_iter != this->sub_end) {
                            this->acc_val = accumulate_func(
                                    this->acc_val, *this->sub_iter);
                        }
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() {
                return {std::begin(this->container),
                        std::end(this->container),
                        this->accumulate_func};
            }

            Iterator end() {
                return {std::end(this->container),
                        std::end(this->container),
                        this->accumulate_func};
            }

    };

    // Helper function to instantiate an Accumulator
    template <typename Container, typename AccumulateFunc>
    Accumulator<Container, AccumulateFunc> accumulate(
            Container&& container,
            AccumulateFunc accumulate_func)
    {
        return {std::forward<Container>(container), accumulate_func};
    }

    template <typename Container>
    auto accumulate(Container&& container) ->
        decltype(accumulate(std::forward<Container>(container),
                    std::plus<typename std::remove_reference<
                        iterator_deref<Container>>::type>{}))
    {
        return accumulate(std::forward<Container>(container),
                    std::plus<typename std::remove_reference<
                        iterator_deref<Container>>::type>{});
    }

    template <typename T, typename AccumulateFunc>
    Accumulator<std::initializer_list<T>, AccumulateFunc> accumulate(
            std::initializer_list<T> il,
            AccumulateFunc accumulate_func)
    {
        return {std::move(il), accumulate_func};
    }

    template <typename T>
    auto accumulate(std::initializer_list<T> il) ->
        decltype(accumulate(std::move(il), std::plus<T>{}))
    {
        return accumulate(std::move(il), std::plus<T>{});
    }

}

#endif //ifndef ITER_ACCUMULATE_H_
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Open Connectome Project (http://openconnecto.me)
 * Written by Da Zheng (zhengda1936@gmail.com)
 *
 * This file is part of FlashMatrix.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifdef PROFILER
#include <gperftools/profiler.h>
#endif

#include "sparse_matrix.h"
#include "matrix_worker_thread.h"
#include "matrix_io.h"
#include "matrix_config.h"

namespace fm
{

matrix_config matrix_conf;

void row_compute_task::run(char *buf, size_t size)
{
	assert(this->buf == buf);
	assert(this->buf_size == size);

	char *buf_p = buf + (io.get_loc().get_offset() - off);
	fg::ext_mem_undirected_vertex *v = (fg::ext_mem_undirected_vertex *) buf_p;
	for (size_t i = 0; i < io.get_num_rows(); i++) {
		size_t vsize = v->get_size();
		assert(buf_size >= vsize);
		buf_size -= vsize;
		buf_p += vsize;
		run_on_row(*v);
		v = (fg::ext_mem_undirected_vertex *) buf_p;
	}
}

/*
 * Sparse square symmetric matrix. It is partitioned in rows.
 */
class sparse_sym_matrix: public sparse_matrix
{
	// This works like the index of the sparse matrix.
	std::vector<row_block> blocks;

	sparse_sym_matrix(safs::file_io_factory::shared_ptr factory,
			size_t nrows): sparse_matrix(factory, nrows, nrows, true,
				part_dim_t::ROW) {
	}
public:
	static ptr create(fg::FG_graph::ptr);

	// Nothing should happen for a symmetric matrix.
	virtual void transpose() {
	}

	virtual void compute(task_creator::ptr creator) const;
};

sparse_matrix::ptr sparse_sym_matrix::create(fg::FG_graph::ptr fg)
{
	// Initialize vertex index.
	fg::vertex_index::ptr index = fg->get_index_data();
	assert(index != NULL);
	assert(!index->get_graph_header().is_directed_graph()
			&& !index->is_compressed());
	fg::undirected_vertex_index::ptr uindex
		= fg::undirected_vertex_index::cast(index);

	fg::vsize_t num_vertices = uindex->get_num_vertices();
	sparse_sym_matrix *m = new sparse_sym_matrix(fg->get_graph_io_factory(
				safs::REMOTE_ACCESS), num_vertices);

	// Generate the matrix index from the vertex index.
	for (size_t i = 0; i < num_vertices; i += matrix_conf.get_row_block_size()) {
		fg::ext_mem_vertex_info info = uindex->get_vertex_info(i);
		m->blocks.emplace_back(info.get_off());
	}
	m->blocks.emplace_back(uindex->get_graph_size());

	return sparse_matrix::ptr(m);
}

void sparse_sym_matrix::compute(task_creator::ptr creator) const
{
	int num_workers = matrix_conf.get_num_threads();
	int num_nodes = safs::params.get_num_nodes();
	std::vector<matrix_worker_thread::ptr> workers(num_workers);
	std::vector<matrix_io_generator::ptr> io_gens(num_workers);
	for (int i = 0; i < num_workers; i++) {
		io_gens[i] = matrix_io_generator::create(blocks, get_num_rows(),
				get_num_cols(), get_file_id(), i, num_workers);
	}

#ifdef PROFILER
	if (!fg::graph_conf.get_prof_file().empty())
		ProfilerStart(fg::graph_conf.get_prof_file().c_str());
#endif
	for (int i = 0; i < num_workers; i++) {
		int node_id = i % num_nodes;
		matrix_worker_thread::ptr t = matrix_worker_thread::create(i, node_id,
				get_io_factory(), io_gens, creator);
		t->start();
		workers[i] = t;
	}
	for (int i = 0; i < num_workers; i++)
		workers[i]->join();
#ifdef PROFILER
	if (!fg::graph_conf.get_prof_file().empty())
		ProfilerStop();
#endif
}

/*
 * Sparse asymmetric square matrix. It is partitioned in rows.
 */
class sparse_asym_matrix: public sparse_matrix
{
	// These work like the index of the sparse matrix.
	// out_blocks index the original matrix.
	std::vector<row_block> out_blocks;
	// in_blocks index the transpose of the matrix.
	std::vector<row_block> in_blocks;
	bool transposed;

	sparse_asym_matrix(safs::file_io_factory::shared_ptr factory,
			size_t nrows): sparse_matrix(factory, nrows, nrows, false,
				part_dim_t::ROW) {
		transposed = false;
	}
public:
	static ptr create(fg::FG_graph::ptr);

	virtual void transpose() {
		transposed = !transposed;
	}

	virtual void compute(task_creator::ptr creator) const;
};

sparse_matrix::ptr sparse_asym_matrix::create(fg::FG_graph::ptr fg)
{
	// Initialize vertex index.
	fg::vertex_index::ptr index = fg->get_index_data();
	assert(index != NULL);
	assert(index->get_graph_header().is_directed_graph()
			&& !index->is_compressed());
	fg::directed_vertex_index::ptr dindex = fg::directed_vertex_index::cast(index);

	fg::vsize_t num_vertices = dindex->get_num_vertices();
	sparse_asym_matrix *m = new sparse_asym_matrix(fg->get_graph_io_factory(
				safs::REMOTE_ACCESS), num_vertices);

	// Generate the matrix index from the vertex index.
	for (size_t i = 0; i < num_vertices; i += matrix_conf.get_row_block_size()) {
		fg::ext_mem_vertex_info info = dindex->get_vertex_info_out(i);
		m->out_blocks.emplace_back(info.get_off());

		info = dindex->get_vertex_info_in(i);
		m->in_blocks.emplace_back(info.get_off());
	}
	fg::ext_mem_vertex_info info = dindex->get_vertex_info_out(num_vertices - 1);
	m->out_blocks.emplace_back(info.get_off() + info.get_size());
	info = dindex->get_vertex_info_in(num_vertices - 1);
	m->in_blocks.emplace_back(info.get_off() + info.get_size());

	return sparse_matrix::ptr(m);
}

void sparse_asym_matrix::compute(task_creator::ptr creator) const
{
	int num_workers = matrix_conf.get_num_threads();
	int num_nodes = safs::params.get_num_nodes();
	std::vector<matrix_worker_thread::ptr> workers(num_workers);
	std::vector<matrix_io_generator::ptr> io_gens(num_workers);
	for (int i = 0; i < num_workers; i++) {
		io_gens[i] = matrix_io_generator::create(
				transposed ? in_blocks : out_blocks, get_num_rows(),
				get_num_cols(), get_file_id(), i, num_workers);
	}
#ifdef PROFILER
	if (!fg::graph_conf.get_prof_file().empty())
		ProfilerStart(fg::graph_conf.get_prof_file().c_str());
#endif
	for (int i = 0; i < num_workers; i++) {
		int node_id = i % num_nodes;
		matrix_worker_thread::ptr t = matrix_worker_thread::create(i, node_id,
				get_io_factory(), io_gens, creator);
		t->start();
		workers[i] = t;
	}
	for (int i = 0; i < num_workers; i++)
		workers[i]->join();
#ifdef PROFILER
	if (!fg::graph_conf.get_prof_file().empty())
		ProfilerStop();
#endif
}

sparse_matrix::ptr sparse_matrix::create(fg::FG_graph::ptr fg)
{
	const fg::graph_header &header = fg->get_graph_header();
	if (header.is_directed_graph())
		return sparse_asym_matrix::create(fg);
	else
		return sparse_sym_matrix::create(fg);
}

static std::atomic<size_t> init_count;

void init_flash_matrix(config_map::ptr configs)
{
	size_t count = init_count.fetch_add(1);
	if (count == 0) {
		matrix_conf.init(configs);
		try {
			safs::init_io_system(configs, false);
		} catch (std::exception &e) {
			// If SAFS fails to initialize, we should remove the count
			// increase at the beginning of the function.
			init_count--;
			throw e;
		}
	}
}

void destroy_flash_matrix()
{
	if (init_count.fetch_sub(1) == 1)
		safs::destroy_io_system();
}

}
<commit_msg>[Matrix]: disable page cache by default.<commit_after>/*
 * Copyright 2014 Open Connectome Project (http://openconnecto.me)
 * Written by Da Zheng (zhengda1936@gmail.com)
 *
 * This file is part of FlashMatrix.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifdef PROFILER
#include <gperftools/profiler.h>
#endif

#include "sparse_matrix.h"
#include "matrix_worker_thread.h"
#include "matrix_io.h"
#include "matrix_config.h"

namespace fm
{

matrix_config matrix_conf;

void row_compute_task::run(char *buf, size_t size)
{
	assert(this->buf == buf);
	assert(this->buf_size == size);

	char *buf_p = buf + (io.get_loc().get_offset() - off);
	fg::ext_mem_undirected_vertex *v = (fg::ext_mem_undirected_vertex *) buf_p;
	for (size_t i = 0; i < io.get_num_rows(); i++) {
		size_t vsize = v->get_size();
		assert(buf_size >= vsize);
		buf_size -= vsize;
		buf_p += vsize;
		run_on_row(*v);
		v = (fg::ext_mem_undirected_vertex *) buf_p;
	}
}

/*
 * Sparse square symmetric matrix. It is partitioned in rows.
 */
class sparse_sym_matrix: public sparse_matrix
{
	// This works like the index of the sparse matrix.
	std::vector<row_block> blocks;

	sparse_sym_matrix(safs::file_io_factory::shared_ptr factory,
			size_t nrows): sparse_matrix(factory, nrows, nrows, true,
				part_dim_t::ROW) {
	}
public:
	static ptr create(fg::FG_graph::ptr);

	// Nothing should happen for a symmetric matrix.
	virtual void transpose() {
	}

	virtual void compute(task_creator::ptr creator) const;
};

sparse_matrix::ptr sparse_sym_matrix::create(fg::FG_graph::ptr fg)
{
	// Initialize vertex index.
	fg::vertex_index::ptr index = fg->get_index_data();
	assert(index != NULL);
	assert(!index->get_graph_header().is_directed_graph()
			&& !index->is_compressed());
	fg::undirected_vertex_index::ptr uindex
		= fg::undirected_vertex_index::cast(index);

	fg::vsize_t num_vertices = uindex->get_num_vertices();
	sparse_sym_matrix *m = new sparse_sym_matrix(fg->get_graph_io_factory(
				safs::REMOTE_ACCESS), num_vertices);

	// Generate the matrix index from the vertex index.
	for (size_t i = 0; i < num_vertices; i += matrix_conf.get_row_block_size()) {
		fg::ext_mem_vertex_info info = uindex->get_vertex_info(i);
		m->blocks.emplace_back(info.get_off());
	}
	m->blocks.emplace_back(uindex->get_graph_size());

	return sparse_matrix::ptr(m);
}

void sparse_sym_matrix::compute(task_creator::ptr creator) const
{
	int num_workers = matrix_conf.get_num_threads();
	int num_nodes = safs::params.get_num_nodes();
	std::vector<matrix_worker_thread::ptr> workers(num_workers);
	std::vector<matrix_io_generator::ptr> io_gens(num_workers);
	for (int i = 0; i < num_workers; i++) {
		io_gens[i] = matrix_io_generator::create(blocks, get_num_rows(),
				get_num_cols(), get_file_id(), i, num_workers);
	}

#ifdef PROFILER
	if (!fg::graph_conf.get_prof_file().empty())
		ProfilerStart(fg::graph_conf.get_prof_file().c_str());
#endif
	for (int i = 0; i < num_workers; i++) {
		int node_id = i % num_nodes;
		matrix_worker_thread::ptr t = matrix_worker_thread::create(i, node_id,
				get_io_factory(), io_gens, creator);
		t->start();
		workers[i] = t;
	}
	for (int i = 0; i < num_workers; i++)
		workers[i]->join();
#ifdef PROFILER
	if (!fg::graph_conf.get_prof_file().empty())
		ProfilerStop();
#endif
}

/*
 * Sparse asymmetric square matrix. It is partitioned in rows.
 */
class sparse_asym_matrix: public sparse_matrix
{
	// These work like the index of the sparse matrix.
	// out_blocks index the original matrix.
	std::vector<row_block> out_blocks;
	// in_blocks index the transpose of the matrix.
	std::vector<row_block> in_blocks;
	bool transposed;

	sparse_asym_matrix(safs::file_io_factory::shared_ptr factory,
			size_t nrows): sparse_matrix(factory, nrows, nrows, false,
				part_dim_t::ROW) {
		transposed = false;
	}
public:
	static ptr create(fg::FG_graph::ptr);

	virtual void transpose() {
		transposed = !transposed;
	}

	virtual void compute(task_creator::ptr creator) const;
};

sparse_matrix::ptr sparse_asym_matrix::create(fg::FG_graph::ptr fg)
{
	// Initialize vertex index.
	fg::vertex_index::ptr index = fg->get_index_data();
	assert(index != NULL);
	assert(index->get_graph_header().is_directed_graph()
			&& !index->is_compressed());
	fg::directed_vertex_index::ptr dindex = fg::directed_vertex_index::cast(index);

	fg::vsize_t num_vertices = dindex->get_num_vertices();
	sparse_asym_matrix *m = new sparse_asym_matrix(fg->get_graph_io_factory(
				safs::REMOTE_ACCESS), num_vertices);

	// Generate the matrix index from the vertex index.
	for (size_t i = 0; i < num_vertices; i += matrix_conf.get_row_block_size()) {
		fg::ext_mem_vertex_info info = dindex->get_vertex_info_out(i);
		m->out_blocks.emplace_back(info.get_off());

		info = dindex->get_vertex_info_in(i);
		m->in_blocks.emplace_back(info.get_off());
	}
	fg::ext_mem_vertex_info info = dindex->get_vertex_info_out(num_vertices - 1);
	m->out_blocks.emplace_back(info.get_off() + info.get_size());
	info = dindex->get_vertex_info_in(num_vertices - 1);
	m->in_blocks.emplace_back(info.get_off() + info.get_size());

	return sparse_matrix::ptr(m);
}

void sparse_asym_matrix::compute(task_creator::ptr creator) const
{
	int num_workers = matrix_conf.get_num_threads();
	int num_nodes = safs::params.get_num_nodes();
	std::vector<matrix_worker_thread::ptr> workers(num_workers);
	std::vector<matrix_io_generator::ptr> io_gens(num_workers);
	for (int i = 0; i < num_workers; i++) {
		io_gens[i] = matrix_io_generator::create(
				transposed ? in_blocks : out_blocks, get_num_rows(),
				get_num_cols(), get_file_id(), i, num_workers);
	}
#ifdef PROFILER
	if (!fg::graph_conf.get_prof_file().empty())
		ProfilerStart(fg::graph_conf.get_prof_file().c_str());
#endif
	for (int i = 0; i < num_workers; i++) {
		int node_id = i % num_nodes;
		matrix_worker_thread::ptr t = matrix_worker_thread::create(i, node_id,
				get_io_factory(), io_gens, creator);
		t->start();
		workers[i] = t;
	}
	for (int i = 0; i < num_workers; i++)
		workers[i]->join();
#ifdef PROFILER
	if (!fg::graph_conf.get_prof_file().empty())
		ProfilerStop();
#endif
}

sparse_matrix::ptr sparse_matrix::create(fg::FG_graph::ptr fg)
{
	const fg::graph_header &header = fg->get_graph_header();
	if (header.is_directed_graph())
		return sparse_asym_matrix::create(fg);
	else
		return sparse_sym_matrix::create(fg);
}

static std::atomic<size_t> init_count;

void init_flash_matrix(config_map::ptr configs)
{
	size_t count = init_count.fetch_add(1);
	if (count == 0) {
		matrix_conf.init(configs);
		try {
			safs::init_io_system(configs);
		} catch (std::exception &e) {
			// If SAFS fails to initialize, we should remove the count
			// increase at the beginning of the function.
			init_count--;
			throw e;
		}
	}
}

void destroy_flash_matrix()
{
	if (init_count.fetch_sub(1) == 1)
		safs::destroy_io_system();
}

}
<|endoftext|>


<commit_before>/*
 *  despot2fm.cpp
 *
 *  Created by Tobias Wood on 2015/06/03.
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <time.h>
#include <getopt.h>
#include <iostream>
#include <atomic>
#include <Eigen/Dense>
#include <unsupported/Eigen/LevenbergMarquardt>
#include <unsupported/Eigen/NumericalDiff>

#include "Util.h"
#include "Filters/ApplyAlgorithmFilter.h"
#include "Model.h"
#include "Sequence.h"
#include "RegionContraction.h"

using namespace std;
using namespace Eigen;

//******************************************************************************
// Arguments / Usage
//******************************************************************************
const string usage {
"Usage is: despot2-fm [options] T1_map ssfp_file\n\
\
Options:\n\
	--help, -h        : Print this message\n\
	--verbose, -v     : Print slice processing times\n\
	--no-prompt, -n   : Suppress input prompts\n\
	--mask, -m file   : Mask input with specified file\n\
	--out, -o path    : Add a prefix to the output filenames\n\
	--f0, -f SYM      : Fit symmetric f0 map (default)\n\
	         ASYM     : Fit asymmetric f0 map\n\
	         file     : Use f0 Map file (in Hertz)\n\
	--B1, -b file     : B1 Map file (ratio)\n\
	--start, -s N     : Start processing from slice N\n\
	--stop, -p  N     : Stop processing at slice N\n\
	--scale, -S 0     : Normalise signals to mean (default)\n\
	            1     : Fit a scaling factor/proton density\n\
	--flip, -F        : Data order is phase, then flip-angle (default opposite)\n\
	--sequences, -M s : Use simple sequences (default)\n\
	            f     : Use finite pulse length correction\n\
	--contract, -c n  : Read contraction settings from stdin (Will prompt)\n\
	--resids, -r      : Write out per flip-angle residuals\n\
	--threads, -T N   : Use N threads (default=hardware limit)\n"
};
/* --complex, -x     : Fit to complex data\n\ */

static auto tesla = FieldStrength::Three;
static int start_slice = 0, stop_slice = 0;
static int verbose = false, prompt = true, all_residuals = false,
           fitFinite = false, fitComplex = false, flipData = false,
           samples = 2000, retain = 20, contract = 10,
           seed = -1;
static double expand = 0.;
static string outPrefix;
static struct option long_opts[] = {
	{"help", no_argument, 0, 'h'},
	{"verbose", no_argument, 0, 'v'},
	{"no-prompt", no_argument, 0, 'n'},
	{"mask", required_argument, 0, 'm'},
	{"out", required_argument, 0, 'o'},
	{"f0", required_argument, 0, 'f'},
	{"B1", required_argument, 0, 'b'},
	{"start", required_argument, 0, 's'},
	{"stop", required_argument, 0, 'p'},
	{"scale", required_argument, 0, 'S'},
	{"flip", required_argument, 0, 'F'},
	{"threads", required_argument, 0, 'T'},
	{"sequences", no_argument, 0, 'M'},
	{"contract", no_argument, 0, 'c'},
	{"resids", no_argument, 0, 'r'},
	{0, 0, 0, 0}
};
static const char* short_opts = "hvnm:o:f:b:s:p:S:FT:M:crd:";

class FMFunctor : public DenseFunctor<double> {
	public:
		const shared_ptr<SequenceBase> m_sequence;
		shared_ptr<SCD> m_model;
		ArrayXd m_data;
		const double m_T1, m_B1;

		FMFunctor(const shared_ptr<SCD> m, const double T1, const shared_ptr<SequenceBase> s, const ArrayXd &d, const double B1) :
			DenseFunctor<double>(3, s->size()),
			m_model(m), m_sequence(s), m_data(d),
			m_T1(T1), m_B1(B1)
		{
			assert(static_cast<size_t>(m_data.rows()) == values());
		}

		const bool constraint(const VectorXd &params) const {
			Array4d fullparams;
			fullparams << params(0), m_T1, params(1), params(2);
			return m_model->ValidParameters(fullparams);
		}

		int operator()(const Ref<VectorXd> &params, Ref<ArrayXd> diffs) const {
			eigen_assert(diffs.size() == values());

			ArrayXd fullparams(5);
			fullparams << params(0), m_T1, params(1), params(2), m_B1;
			ArrayXcd s = m_sequence->signal(m_model, fullparams);
			diffs = s.abs() - m_data;
			return 0;
		}
};

class FMAlgo : public Algorithm<double> {
	private:
		size_t m_samples = 2000, m_retain = 20, m_contractions = 10;
		Array2d m_f0Bounds = Array2d::Zero();
		const shared_ptr<SCD> m_model = make_shared<SCD>();
		shared_ptr<SteadyState> m_sequence;

	public:
		void setSequence(shared_ptr<SteadyState> s) { m_sequence = s; }
		void setSamples(size_t s) { m_samples = s; }
		void setRetain(size_t r) { m_retain = r; }
		void setContractions(size_t c) { m_contractions = c; }
		void setScaling(Model::Scale s) { m_model->setScaling(s); }
		void setf0Bounds(Array2d b) { m_f0Bounds = b; }

		size_t numInputs() const override  { return m_sequence->count(); }
		size_t numConsts() const override  { return 2; }
		size_t numOutputs() const override { return 3; }
		size_t dataSize() const override   { return m_sequence->size(); }

		virtual VectorXd defaultConsts() {
			// T1 & B1
			VectorXd def = VectorXd::Ones(2);
			return def;
		}

		virtual void apply(const VectorXd &data, const VectorXd &inputs,
		                   VectorXd &outputs, ArrayXd &resids) const override
		{
			ArrayXd thresh(3); thresh.setConstant(0.05);
			ArrayXd weights(m_sequence->size()); weights.setOnes();
			ArrayXXd bounds = ArrayXXd::Zero(3, 2);
			double T1 = inputs[0];
			double B1 = inputs[1];
			if (m_model->scaling() == Model::Scale::None) {
				bounds(0, 0) = 0.;
				bounds(0, 1) = data.array().abs().maxCoeff() * 25;
			} else {
				bounds.row(0).setConstant(1.);
			}
			bounds(1,0) = 0.001;
			bounds(1,1) = T1;
			bounds.row(2) = m_f0Bounds;
			//cout << "T1 " << T1 << " B1 " << B1 << " inputs " << inputs.transpose() << endl;
			//cout << bounds << endl;
			FMFunctor func(m_model, T1, m_sequence, data, B1);
			RegionContraction<FMFunctor> rc(func, bounds, weights, thresh,
			                                m_samples, m_retain, m_contractions, expand, false, false);
			rc.optimise(outputs);
			resids = rc.residuals();
		}
};

//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv) {
	Eigen::initParallel();
	QI::ReadImageF::Pointer mask, B1, f0 = ITK_NULLPTR;
	shared_ptr<FMAlgo> fm = make_shared<FMAlgo>();
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, short_opts, long_opts, &indexptr)) != -1) {
		switch (c) {
			case 'v': verbose = true; break;
			case 'n': prompt = false; break;
			case 'm':
				if (verbose) cout << "Reading mask file " << optarg << endl;
				mask = QI::ReadImageF::New();
				mask->SetFileName(optarg);
				break;
			case 'o':
				outPrefix = optarg;
				if (verbose) cout << "Output prefix will be: " << outPrefix << endl;
				break;
			case 'f':
				if (verbose) cout << "Reading f0 file: " << optarg << endl;
				f0 = QI::ReadImageF::New();
				f0->SetFileName(optarg);
				break;
			case 'b':
				if (verbose) cout << "Reading B1 file: " << optarg << endl;
				B1 = QI::ReadImageF::New();
				B1->SetFileName(optarg);
				break;
			case 's': start_slice = atoi(optarg); break;
			case 'p': stop_slice = atoi(optarg); break;
			case 'S':
				switch (atoi(optarg)) {
					case 0 : fm->setScaling(Model::Scale::ToMean); break;
					case 1 : fm->setScaling(Model::Scale::None); break;
					default:
						cout << "Invalid scaling mode: " + to_string(atoi(optarg)) << endl;
						return EXIT_FAILURE;
						break;
				} break;
			case 'F': flipData = true; break;
			case 'T': itk::MultiThreader::SetGlobalMaximumNumberOfThreads(atoi(optarg)); break;
			case 'd': seed = atoi(optarg); break;
			case 'M':
				switch (*optarg) {
					case 's': fitFinite = false; cout << "Simple sequences selected." << endl; break;
					case 'f': fitFinite = true; cout << "Finite pulse correction selected." << endl; break;
					default:
						cout << "Unknown sequences type " << *optarg << endl;
						return EXIT_FAILURE;
						break;
				}
				break;
			case 'c':
				cout << "Enter max number of contractions: " << flush; cin >> contract;
				cout << "Enter number of samples per contraction: " << flush; cin >> samples;
				cout << "Enter number of samples to retain: " << flush; cin >> retain;
				cout << "Enter fraction to expand region by: " << flush; cin >> expand;
				break;
			case 'r': all_residuals = true; break;
			case '?': // getopt will print an error message
			case 'h':
			default:
				cout << usage << endl;
				return EXIT_SUCCESS;
				break;
		}
	}
	if ((argc - optind) != 2) {
		cout << "Wrong number of arguments. Need a T1 map and one SSFP file." << endl;
		return EXIT_FAILURE;
	}
	shared_ptr<SSFPSimple> ssfpSequence;
	if (fitFinite) {
		ssfpSequence = make_shared<SSFPFinite>(prompt);
	} else {
		ssfpSequence = make_shared<SSFPSimple>(prompt);
	}
	if (verbose) cout << *ssfpSequence << endl;

	if (verbose) cout << "Reading T1 Map from: " << argv[optind] << endl;
	auto T1File = QI::ReadImageF::New();
	auto T1Slice = QI::ImageROIF::New(), B1Slice = QI::ImageROIF::New(),
	     maskSlice = QI::ImageROIF::New();
	auto ssfpSlice = QI::VectorImageROIF::New();

	T1File->SetFileName(argv[optind++]);
	T1File->Update(); // Need to have some image dimensions to do this
	QI::ImageF::RegionType region = T1File->GetOutput()->GetLargestPossibleRegion();
	region.GetModifiableIndex()[2] = start_slice;
	if (stop_slice != 0)
		region.GetModifiableSize()[2] = stop_slice - start_slice;
	else
		region.GetModifiableSize()[2] = region.GetSize()[2] - start_slice;
	T1Slice->SetRegionOfInterest(region);
	T1Slice->SetInput(T1File->GetOutput());

	if (verbose) cout << "Opening SSFP file: " << argv[optind] << endl;
	auto ssfpFile = QI::ReadTimeseriesF::New();
	ssfpFile->SetFileName(argv[optind++]);
	auto ssfpData = QI::TimeseriesToVectorF::New();
	ssfpData->SetInput(ssfpFile->GetOutput());
	ssfpSlice->SetRegionOfInterest(region);
	ssfpSlice->SetInput(ssfpData->GetOutput());
	auto ssfpFlip = QI::ReorderF::New();
	if (flipData) {
		ssfpFlip->SetStride(ssfpSequence->phases());
	}
	ssfpFlip->SetInput(ssfpSlice->GetOutput());

	auto apply = itk::ApplyAlgorithmFilter<QI::VectorImageF, FMAlgo>::New();
	fm->setSequence(ssfpSequence);
	fm->setf0Bounds(ssfpSequence->bandwidth());
	apply->SetAlgorithm(fm);
	apply->SetDataInput(0, ssfpFlip->GetOutput());
	apply->SetConstInput(0, T1Slice->GetOutput());
	if (B1) {
		B1Slice->SetRegionOfInterest(region);
		B1Slice->SetInput(B1->GetOutput());
		apply->SetConstInput(1, B1Slice->GetOutput());
	}
	if (mask) {
		maskSlice->SetRegionOfInterest(region);
		maskSlice->SetInput(mask->GetOutput());
		apply->SetMask(maskSlice->GetOutput());
	}
	time_t startTime;
	if (verbose) startTime = QI::printStartTime();
	apply->Update();
	QI::printElapsedTime(startTime);
	if (verbose) cout << "Writing output files." << endl;
	outPrefix = outPrefix + "FM_";
	QI::writeResult(apply->GetOutput(0), outPrefix + "PD.nii");
	QI::writeResult(apply->GetOutput(1), outPrefix + "T2.nii");
	QI::writeResult(apply->GetOutput(2), outPrefix + "f0.nii");
	QI::writeResiduals(apply->GetResidOutput(), outPrefix, all_residuals);
	return EXIT_SUCCESS;
}
<commit_msg>Changed the order that the pipeline is connected.<commit_after>/*
 *  despot2fm.cpp
 *
 *  Created by Tobias Wood on 2015/06/03.
 *  Copyright (c) 2015 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <time.h>
#include <getopt.h>
#include <iostream>
#include <atomic>
#include <Eigen/Dense>
#include <unsupported/Eigen/LevenbergMarquardt>
#include <unsupported/Eigen/NumericalDiff>

#include "Util.h"
#include "Filters/ApplyAlgorithmFilter.h"
#include "Model.h"
#include "Sequence.h"
#include "RegionContraction.h"

using namespace std;
using namespace Eigen;

//******************************************************************************
// Arguments / Usage
//******************************************************************************
const string usage {
"Usage is: despot2-fm [options] T1_map ssfp_file\n\
\
Options:\n\
	--help, -h        : Print this message\n\
	--verbose, -v     : Print slice processing times\n\
	--no-prompt, -n   : Suppress input prompts\n\
	--mask, -m file   : Mask input with specified file\n\
	--out, -o path    : Add a prefix to the output filenames\n\
	--f0, -f SYM      : Fit symmetric f0 map (default)\n\
	         ASYM     : Fit asymmetric f0 map\n\
	         file     : Use f0 Map file (in Hertz)\n\
	--B1, -b file     : B1 Map file (ratio)\n\
	--start, -s N     : Start processing from slice N\n\
	--stop, -p  N     : Stop processing at slice N\n\
	--scale, -S 0     : Normalise signals to mean (default)\n\
	            1     : Fit a scaling factor/proton density\n\
	--flip, -F        : Data order is phase, then flip-angle (default opposite)\n\
	--sequences, -M s : Use simple sequences (default)\n\
	            f     : Use finite pulse length correction\n\
	--contract, -c n  : Read contraction settings from stdin (Will prompt)\n\
	--resids, -r      : Write out per flip-angle residuals\n\
	--threads, -T N   : Use N threads (default=hardware limit)\n"
};
/* --complex, -x     : Fit to complex data\n\ */

static auto tesla = FieldStrength::Three;
static int start_slice = 0, stop_slice = 0;
static int verbose = false, prompt = true, all_residuals = false,
           fitFinite = false, fitComplex = false, flipData = false,
           samples = 2000, retain = 20, contract = 10,
           seed = -1;
static double expand = 0.;
static string outPrefix;
static struct option long_opts[] = {
	{"help", no_argument, 0, 'h'},
	{"verbose", no_argument, 0, 'v'},
	{"no-prompt", no_argument, 0, 'n'},
	{"mask", required_argument, 0, 'm'},
	{"out", required_argument, 0, 'o'},
	{"f0", required_argument, 0, 'f'},
	{"B1", required_argument, 0, 'b'},
	{"start", required_argument, 0, 's'},
	{"stop", required_argument, 0, 'p'},
	{"scale", required_argument, 0, 'S'},
	{"flip", required_argument, 0, 'F'},
	{"threads", required_argument, 0, 'T'},
	{"sequences", no_argument, 0, 'M'},
	{"contract", no_argument, 0, 'c'},
	{"resids", no_argument, 0, 'r'},
	{0, 0, 0, 0}
};
static const char* short_opts = "hvnm:o:f:b:s:p:S:FT:M:crd:";

class FMFunctor : public DenseFunctor<double> {
	public:
		const shared_ptr<SequenceBase> m_sequence;
		shared_ptr<SCD> m_model;
		ArrayXd m_data;
		const double m_T1, m_B1;

		FMFunctor(const shared_ptr<SCD> m, const double T1, const shared_ptr<SequenceBase> s, const ArrayXd &d, const double B1) :
			DenseFunctor<double>(3, s->size()),
			m_model(m), m_sequence(s), m_data(d),
			m_T1(T1), m_B1(B1)
		{
			assert(static_cast<size_t>(m_data.rows()) == values());
		}

		const bool constraint(const VectorXd &params) const {
			Array4d fullparams;
			fullparams << params(0), m_T1, params(1), params(2);
			return m_model->ValidParameters(fullparams);
		}

		int operator()(const Ref<VectorXd> &params, Ref<ArrayXd> diffs) const {
			eigen_assert(diffs.size() == values());

			ArrayXd fullparams(5);
			fullparams << params(0), m_T1, params(1), params(2), m_B1;
			ArrayXcd s = m_sequence->signal(m_model, fullparams);
			diffs = s.abs() - m_data;
			return 0;
		}
};

class FMAlgo : public Algorithm<double> {
	private:
		size_t m_samples = 2000, m_retain = 20, m_contractions = 10;
		Array2d m_f0Bounds = Array2d::Zero();
		const shared_ptr<SCD> m_model = make_shared<SCD>();
		shared_ptr<SteadyState> m_sequence;

	public:
		void setSequence(shared_ptr<SteadyState> s) { m_sequence = s; }
		void setSamples(size_t s) { m_samples = s; }
		void setRetain(size_t r) { m_retain = r; }
		void setContractions(size_t c) { m_contractions = c; }
		void setScaling(Model::Scale s) { m_model->setScaling(s); }
		void setf0Bounds(Array2d b) { m_f0Bounds = b; }

		size_t numInputs() const override  { return m_sequence->count(); }
		size_t numConsts() const override  { return 2; }
		size_t numOutputs() const override { return 3; }
		size_t dataSize() const override   { return m_sequence->size(); }

		virtual VectorXd defaultConsts() {
			// T1 & B1
			VectorXd def = VectorXd::Ones(2);
			return def;
		}

		virtual void apply(const VectorXd &data, const VectorXd &inputs,
		                   VectorXd &outputs, ArrayXd &resids) const override
		{
			ArrayXd thresh(3); thresh.setConstant(0.05);
			ArrayXd weights(m_sequence->size()); weights.setOnes();
			ArrayXXd bounds = ArrayXXd::Zero(3, 2);
			double T1 = inputs[0];
			double B1 = inputs[1];
			if (m_model->scaling() == Model::Scale::None) {
				bounds(0, 0) = 0.;
				bounds(0, 1) = data.array().abs().maxCoeff() * 25;
			} else {
				bounds.row(0).setConstant(1.);
			}
			bounds(1,0) = 0.001;
			bounds(1,1) = T1;
			bounds.row(2) = m_f0Bounds;
			//cout << "T1 " << T1 << " B1 " << B1 << " inputs " << inputs.transpose() << endl;
			//cout << bounds << endl;
			FMFunctor func(m_model, T1, m_sequence, data, B1);
			RegionContraction<FMFunctor> rc(func, bounds, weights, thresh,
			                                m_samples, m_retain, m_contractions, expand, false, false);
			rc.optimise(outputs);
			resids = rc.residuals();
		}
};

//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv) {
	Eigen::initParallel();
	QI::ReadImageF::Pointer mask, B1, f0 = ITK_NULLPTR;
	shared_ptr<FMAlgo> fm = make_shared<FMAlgo>();
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, short_opts, long_opts, &indexptr)) != -1) {
		switch (c) {
			case 'v': verbose = true; break;
			case 'n': prompt = false; break;
			case 'm':
				if (verbose) cout << "Reading mask file " << optarg << endl;
				mask = QI::ReadImageF::New();
				mask->SetFileName(optarg);
				break;
			case 'o':
				outPrefix = optarg;
				if (verbose) cout << "Output prefix will be: " << outPrefix << endl;
				break;
			case 'f':
				if (verbose) cout << "Reading f0 file: " << optarg << endl;
				f0 = QI::ReadImageF::New();
				f0->SetFileName(optarg);
				break;
			case 'b':
				if (verbose) cout << "Reading B1 file: " << optarg << endl;
				B1 = QI::ReadImageF::New();
				B1->SetFileName(optarg);
				break;
			case 's': start_slice = atoi(optarg); break;
			case 'p': stop_slice = atoi(optarg); break;
			case 'S':
				switch (atoi(optarg)) {
					case 0 : fm->setScaling(Model::Scale::ToMean); break;
					case 1 : fm->setScaling(Model::Scale::None); break;
					default:
						cout << "Invalid scaling mode: " + to_string(atoi(optarg)) << endl;
						return EXIT_FAILURE;
						break;
				} break;
			case 'F': flipData = true; break;
			case 'T': itk::MultiThreader::SetGlobalMaximumNumberOfThreads(atoi(optarg)); break;
			case 'd': seed = atoi(optarg); break;
			case 'M':
				switch (*optarg) {
					case 's': fitFinite = false; cout << "Simple sequences selected." << endl; break;
					case 'f': fitFinite = true; cout << "Finite pulse correction selected." << endl; break;
					default:
						cout << "Unknown sequences type " << *optarg << endl;
						return EXIT_FAILURE;
						break;
				}
				break;
			case 'c':
				cout << "Enter max number of contractions: " << flush; cin >> contract;
				cout << "Enter number of samples per contraction: " << flush; cin >> samples;
				cout << "Enter number of samples to retain: " << flush; cin >> retain;
				cout << "Enter fraction to expand region by: " << flush; cin >> expand;
				break;
			case 'r': all_residuals = true; break;
			case '?': // getopt will print an error message
			case 'h':
			default:
				cout << usage << endl;
				return EXIT_SUCCESS;
				break;
		}
	}
	if ((argc - optind) != 2) {
		cout << "Wrong number of arguments. Need a T1 map and one SSFP file." << endl;
		return EXIT_FAILURE;
	}
	shared_ptr<SSFPSimple> ssfpSequence;
	if (fitFinite) {
		ssfpSequence = make_shared<SSFPFinite>(prompt);
	} else {
		ssfpSequence = make_shared<SSFPSimple>(prompt);
	}
	if (verbose) cout << *ssfpSequence << endl;

	if (verbose) cout << "Reading T1 Map from: " << argv[optind] << endl;
	auto T1File = QI::ReadImageF::New();
	auto T1Slice = QI::ImageROIF::New(), B1Slice = QI::ImageROIF::New(),
	     maskSlice = QI::ImageROIF::New();

	T1File->SetFileName(argv[optind++]);
	T1File->Update(); // Need to have some image dimensions to do this
	QI::ImageF::RegionType region = T1File->GetOutput()->GetLargestPossibleRegion();
	region.GetModifiableIndex()[2] = start_slice;
	if (stop_slice != 0)
		region.GetModifiableSize()[2] = stop_slice - start_slice;
	else
		region.GetModifiableSize()[2] = region.GetSize()[2] - start_slice;
	T1Slice->SetRegionOfInterest(region);
	T1Slice->SetInput(T1File->GetOutput());
	if (verbose) cout << "Processing region: " << endl << region << endl;
	if (verbose) cout << "Opening SSFP file: " << argv[optind] << endl;
	auto ssfpFile = QI::ReadTimeseriesF::New();
	auto ssfpData = QI::TimeseriesToVectorF::New();
	auto ssfpFlip = QI::ReorderF::New();
	auto ssfpSlice = QI::VectorImageROIF::New();
	ssfpFile->SetFileName(argv[optind++]);
	ssfpData->SetInput(ssfpFile->GetOutput());
	ssfpFlip->SetInput(ssfpData->GetOutput());
	if (flipData) {
		ssfpFlip->SetStride(ssfpSequence->phases());
	}
	ssfpSlice->SetInput(ssfpFlip->GetOutput());
	ssfpSlice->SetRegionOfInterest(region);

	auto apply = itk::ApplyAlgorithmFilter<QI::VectorImageF, FMAlgo>::New();
	fm->setSequence(ssfpSequence);
	fm->setf0Bounds(ssfpSequence->bandwidth());
	apply->SetAlgorithm(fm);
	apply->SetDataInput(0, ssfpSlice->GetOutput());
	apply->SetConstInput(0, T1Slice->GetOutput());
	if (B1) {
		B1Slice->SetRegionOfInterest(region);
		B1Slice->SetInput(B1->GetOutput());
		apply->SetConstInput(1, B1Slice->GetOutput());
	}
	if (mask) {
		maskSlice->SetRegionOfInterest(region);
		maskSlice->SetInput(mask->GetOutput());
		apply->SetMask(maskSlice->GetOutput());
	}
	time_t startTime;
	if (verbose) startTime = QI::printStartTime();
	apply->Update();
	QI::printElapsedTime(startTime);
	if (verbose) cout << "Writing output files." << endl;
	outPrefix = outPrefix + "FM_";
	QI::writeResult(apply->GetOutput(0), outPrefix + "PD.nii");
	QI::writeResult(apply->GetOutput(1), outPrefix + "T2.nii");
	QI::writeResult(apply->GetOutput(2), outPrefix + "f0.nii");
	QI::writeResiduals(apply->GetResidOutput(), outPrefix, all_residuals);
	return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2015 Paul Asmuth
 *   Copyright (c) 2015 Laura Schlimmer, FnordCorp B.V.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <stx/stdtypes.h>
#include <stx/io/file.h>
#include <stx/test/unittest.h>
#include <cstable/CSTableWriter.h>
#include <cstable/CSTableReader.h>
#include <cstable/BitPackedIntColumnWriter.h>
#include <cstable/BooleanColumnWriter.h>
#include <cstable/DoubleColumnWriter.h>
#include <cstable/LEB128ColumnWriter.h>
#include <cstable/StringColumnWriter.h>
#include <cstable/UInt32ColumnWriter.h>
#include <cstable/UInt64ColumnWriter.h>

using namespace stx;

UNIT_TEST(CSTableTest);

TEST_CASE(CSTableTest, TestCSTableContainer, [] () {
  const String filename = "/tmp/__fnord__cstabletest1.cstable";
  auto num_records = 10;

  FileUtil::rm(filename);

  RefPtr<cstable::BitPackedIntColumnWriter> column1_writer = mkRef(
    new cstable::BitPackedIntColumnWriter(10, 10));
  RefPtr<cstable::BitPackedIntColumnWriter> column2_writer = mkRef(
    new cstable::BitPackedIntColumnWriter(10, 10));
  cstable::CSTableWriter tbl_writer(filename, num_records);

  tbl_writer.addColumn("key1", column1_writer.get());
  tbl_writer.addColumn("key2", column2_writer.get());
  tbl_writer.commit();

  cstable::CSTableReader tbl_reader(filename);
  EXPECT_EQ(tbl_reader.numRecords(), num_records);
  EXPECT_EQ(tbl_reader.hasColumn("key1"), true);
  EXPECT_EQ(tbl_reader.hasColumn("key2"), true);
});

TEST_CASE(CSTableTest, TestCSTableColumnWriterReader, [] () {
  const String filename = "/tmp/__fnord__cstabletest2.cstable";
  auto num_records = 4000;
  auto rep_max = 1;
  auto def_max = 1;

  FileUtil::rm(filename);

  RefPtr<cstable::BitPackedIntColumnWriter> bitpacked_writer = mkRef(
    new cstable::BitPackedIntColumnWriter(rep_max, def_max));
  RefPtr<cstable::BooleanColumnWriter> boolean_writer = mkRef(
    new cstable::BooleanColumnWriter(rep_max, def_max));
  RefPtr<cstable::DoubleColumnWriter> double_writer = mkRef(
    new cstable::DoubleColumnWriter(rep_max, def_max));
  RefPtr<cstable::LEB128ColumnWriter> leb128_writer = mkRef(
    new cstable::LEB128ColumnWriter(rep_max, def_max));
  RefPtr<cstable::StringColumnWriter> string_writer = mkRef(
    new cstable::StringColumnWriter(rep_max, def_max));
  RefPtr<cstable::UInt32ColumnWriter> uint32_writer = mkRef(
    new cstable::UInt32ColumnWriter(rep_max, def_max));
  RefPtr<cstable::UInt64ColumnWriter> uint64_writer = mkRef(
    new cstable::UInt64ColumnWriter(rep_max, def_max));

  for (auto i = 0; i < num_records; i++) {
    uint8_t boolean_v = i % 2;
    double double_v = i * 1.1;
    uint64_t uint64_v = static_cast<uint64_t>(i);
    const String string_v = "value";

    bitpacked_writer->addDatum(rep_max, def_max, &i, sizeof(i));
    boolean_writer->addDatum(rep_max, def_max, &boolean_v, sizeof(boolean_v));
    double_writer->addDatum(rep_max, def_max, &double_v, sizeof(double_v));
    leb128_writer->addDatum(rep_max, def_max, &i, sizeof(i));
    string_writer->addDatum(rep_max, def_max, &string_v, sizeof(string_v));
    uint32_writer->addDatum(rep_max, def_max, &i, sizeof(i));
    uint64_writer->addDatum(rep_max, def_max, &uint64_v, sizeof(uint64_v));
  }

  cstable::CSTableWriter tbl_writer(filename, num_records);
  tbl_writer.addColumn("bitpacked", bitpacked_writer.get());
  tbl_writer.addColumn("boolean", boolean_writer.get());
  tbl_writer.addColumn("double", double_writer.get());
  tbl_writer.addColumn("leb128", leb128_writer.get());
  tbl_writer.addColumn("string", string_writer.get());
  tbl_writer.addColumn("uint32", uint32_writer.get());
  tbl_writer.addColumn("uint64", uint64_writer.get());
  tbl_writer.commit();

  cstable::CSTableReader tbl_reader(filename);
  RefPtr<cstable::ColumnReader> bitpacked_reader = tbl_reader.getColumnReader(
    "bitpacked");
  RefPtr<cstable::ColumnReader> boolean_reader = tbl_reader.getColumnReader(
    "boolean");
  RefPtr<cstable::ColumnReader> double_reader = tbl_reader.getColumnReader(
    "double");
  RefPtr<cstable::ColumnReader> leb128_reader = tbl_reader.getColumnReader(
    "leb128");
  RefPtr<cstable::ColumnReader> string_reader = tbl_reader.getColumnReader(
    "string");
  RefPtr<cstable::ColumnReader> uint32_reader = tbl_reader.getColumnReader(
    "uint32");
  RefPtr<cstable::ColumnReader> uint64_reader = tbl_reader.getColumnReader(
    "uint64");

  EXPECT_EQ(bitpacked_reader->type() == msg::FieldType::UINT32, true);
  EXPECT_EQ(boolean_reader->type() == msg::FieldType::BOOLEAN, true);
  EXPECT_EQ(double_reader->type() == msg::FieldType::DOUBLE, true);
  EXPECT_EQ(leb128_reader->type() == msg::FieldType::UINT64, true);
  EXPECT_EQ(string_reader->type() == msg::FieldType::STRING, true);
  EXPECT_EQ(uint32_reader->type() == msg::FieldType::UINT32, true);
  EXPECT_EQ(uint64_reader->type() == msg::FieldType::UINT64, true);

  uint64_t rep_level;
  uint64_t def_level;
  size_t size;
  void* data;
  uint32_t* bitpacked_val;
  uint8_t* boolean_val;
  double* double_val;
  uint64_t* leb128_val;
  String* string_val;
  uint32_t* uint32_val;
  uint64_t* uint64_val;

  for (auto i = 0; i < num_records; i++) {
    const String& string_v = "value";

    EXPECT_EQ(
      bitpacked_reader->next(&rep_level, &def_level, &data, &size),
      true);
    bitpacked_val = static_cast<uint32_t*>(data);
    EXPECT_EQ(*bitpacked_val, i);

    EXPECT_EQ(
      boolean_reader->next(&rep_level, &def_level, &data, &size),
      true);
    boolean_val = static_cast<uint8_t*>(data);
    EXPECT_EQ(*boolean_val, i % 2);

    EXPECT_EQ(
      double_reader->next(&rep_level, &def_level, &data, &size),
      true);
    double_val = static_cast<double*>(data);
    EXPECT_EQ(*double_val, i * 1.1);

    EXPECT_EQ(
      leb128_reader->next(&rep_level, &def_level, &data, &size),
      true);
    leb128_val = static_cast<uint64_t*>(data);
    EXPECT_EQ(*leb128_val, i);

    EXPECT_EQ(
      string_reader->next(&rep_level, &def_level, &data, &size),
      true);
    string_val = static_cast<String*>(data);
    EXPECT_EQ(*string_val, string_v);

    EXPECT_EQ(
      uint32_reader->next(&rep_level, &def_level, &data, &size),
      true);
    uint32_val = static_cast<uint32_t*>(data);
    EXPECT_EQ(*uint32_val, i);

    EXPECT_EQ(
      uint64_reader->next(&rep_level, &def_level, &data, &size),
      true);
    uint64_val = static_cast<uint64_t*>(data);
    EXPECT_EQ(*uint64_val, static_cast<uint64_t>(i));
  }
});

<commit_msg>anonymous static cast<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2015 Paul Asmuth
 *   Copyright (c) 2015 Laura Schlimmer, FnordCorp B.V.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <stx/stdtypes.h>
#include <stx/io/file.h>
#include <stx/test/unittest.h>
#include <cstable/CSTableWriter.h>
#include <cstable/CSTableReader.h>
#include <cstable/BitPackedIntColumnWriter.h>
#include <cstable/BooleanColumnWriter.h>
#include <cstable/DoubleColumnWriter.h>
#include <cstable/LEB128ColumnWriter.h>
#include <cstable/StringColumnWriter.h>
#include <cstable/UInt32ColumnWriter.h>
#include <cstable/UInt64ColumnWriter.h>

using namespace stx;

UNIT_TEST(CSTableTest);

TEST_CASE(CSTableTest, TestCSTableContainer, [] () {
  const String filename = "/tmp/__fnord__cstabletest1.cstable";
  auto num_records = 10;

  FileUtil::rm(filename);

  RefPtr<cstable::BitPackedIntColumnWriter> column1_writer = mkRef(
    new cstable::BitPackedIntColumnWriter(10, 10));
  RefPtr<cstable::BitPackedIntColumnWriter> column2_writer = mkRef(
    new cstable::BitPackedIntColumnWriter(10, 10));
  cstable::CSTableWriter tbl_writer(filename, num_records);

  tbl_writer.addColumn("key1", column1_writer.get());
  tbl_writer.addColumn("key2", column2_writer.get());
  tbl_writer.commit();

  cstable::CSTableReader tbl_reader(filename);
  EXPECT_EQ(tbl_reader.numRecords(), num_records);
  EXPECT_EQ(tbl_reader.hasColumn("key1"), true);
  EXPECT_EQ(tbl_reader.hasColumn("key2"), true);
});

TEST_CASE(CSTableTest, TestCSTableColumnWriterReader, [] () {
  const String filename = "/tmp/__fnord__cstabletest2.cstable";
  auto num_records = 4000;
  auto rep_max = 1;
  auto def_max = 1;

  FileUtil::rm(filename);

  RefPtr<cstable::BitPackedIntColumnWriter> bitpacked_writer = mkRef(
    new cstable::BitPackedIntColumnWriter(rep_max, def_max));
  RefPtr<cstable::BooleanColumnWriter> boolean_writer = mkRef(
    new cstable::BooleanColumnWriter(rep_max, def_max));
  RefPtr<cstable::DoubleColumnWriter> double_writer = mkRef(
    new cstable::DoubleColumnWriter(rep_max, def_max));
  RefPtr<cstable::LEB128ColumnWriter> leb128_writer = mkRef(
    new cstable::LEB128ColumnWriter(rep_max, def_max));
  RefPtr<cstable::StringColumnWriter> string_writer = mkRef(
    new cstable::StringColumnWriter(rep_max, def_max));
  RefPtr<cstable::UInt32ColumnWriter> uint32_writer = mkRef(
    new cstable::UInt32ColumnWriter(rep_max, def_max));
  RefPtr<cstable::UInt64ColumnWriter> uint64_writer = mkRef(
    new cstable::UInt64ColumnWriter(rep_max, def_max));

  for (auto i = 0; i < num_records; i++) {
    uint8_t boolean_v = i % 2;
    double double_v = i * 1.1;
    uint64_t uint64_v = static_cast<uint64_t>(i);
    const String string_v = "value";

    bitpacked_writer->addDatum(rep_max, def_max, &i, sizeof(i));
    boolean_writer->addDatum(rep_max, def_max, &boolean_v, sizeof(boolean_v));
    double_writer->addDatum(rep_max, def_max, &double_v, sizeof(double_v));
    leb128_writer->addDatum(rep_max, def_max, &i, sizeof(i));
    string_writer->addDatum(rep_max, def_max, &string_v, sizeof(string_v));
    uint32_writer->addDatum(rep_max, def_max, &i, sizeof(i));
    uint64_writer->addDatum(rep_max, def_max, &uint64_v, sizeof(uint64_v));
  }

  cstable::CSTableWriter tbl_writer(filename, num_records);
  tbl_writer.addColumn("bitpacked", bitpacked_writer.get());
  tbl_writer.addColumn("boolean", boolean_writer.get());
  tbl_writer.addColumn("double", double_writer.get());
  tbl_writer.addColumn("leb128", leb128_writer.get());
  tbl_writer.addColumn("string", string_writer.get());
  tbl_writer.addColumn("uint32", uint32_writer.get());
  tbl_writer.addColumn("uint64", uint64_writer.get());
  tbl_writer.commit();

  cstable::CSTableReader tbl_reader(filename);
  RefPtr<cstable::ColumnReader> bitpacked_reader = tbl_reader.getColumnReader(
    "bitpacked");
  RefPtr<cstable::ColumnReader> boolean_reader = tbl_reader.getColumnReader(
    "boolean");
  RefPtr<cstable::ColumnReader> double_reader = tbl_reader.getColumnReader(
    "double");
  RefPtr<cstable::ColumnReader> leb128_reader = tbl_reader.getColumnReader(
    "leb128");
  RefPtr<cstable::ColumnReader> string_reader = tbl_reader.getColumnReader(
    "string");
  RefPtr<cstable::ColumnReader> uint32_reader = tbl_reader.getColumnReader(
    "uint32");
  RefPtr<cstable::ColumnReader> uint64_reader = tbl_reader.getColumnReader(
    "uint64");

  EXPECT_EQ(bitpacked_reader->type() == msg::FieldType::UINT32, true);
  EXPECT_EQ(boolean_reader->type() == msg::FieldType::BOOLEAN, true);
  EXPECT_EQ(double_reader->type() == msg::FieldType::DOUBLE, true);
  EXPECT_EQ(leb128_reader->type() == msg::FieldType::UINT64, true);
  EXPECT_EQ(string_reader->type() == msg::FieldType::STRING, true);
  EXPECT_EQ(uint32_reader->type() == msg::FieldType::UINT32, true);
  EXPECT_EQ(uint64_reader->type() == msg::FieldType::UINT64, true);

  for (auto i = 0; i < num_records; i++) {
    uint64_t rep_level;
    uint64_t def_level;
    size_t size;
    void* data;

    EXPECT_EQ(
      bitpacked_reader->next(&rep_level, &def_level, &data, &size),
      true);
    EXPECT_EQ(*static_cast<uint32_t*>(data), i);

    EXPECT_EQ(
      boolean_reader->next(&rep_level, &def_level, &data, &size),
      true);
    EXPECT_EQ(*static_cast<uint8_t*>(data), i % 2);

    EXPECT_EQ(
      double_reader->next(&rep_level, &def_level, &data, &size),
      true);
    EXPECT_EQ(*static_cast<double*>(data), i * 1.1);

    EXPECT_EQ(
      leb128_reader->next(&rep_level, &def_level, &data, &size),
      true);
    EXPECT_EQ(*static_cast<uint64_t*>(data), i);

    EXPECT_EQ(
      string_reader->next(&rep_level, &def_level, &data, &size),
      true);
    EXPECT_EQ(*static_cast<String*>(data), "value");

    EXPECT_EQ(
      uint32_reader->next(&rep_level, &def_level, &data, &size),
      true);
    EXPECT_EQ(*static_cast<uint32_t*>(data), i);

    EXPECT_EQ(
      uint64_reader->next(&rep_level, &def_level, &data, &size),
      true);
    EXPECT_EQ(*static_cast<uint64_t*>(data), static_cast<uint64_t>(i));
  }
});

<|endoftext|>