<commit_before>//===-- SelectionDAGPrinter.cpp - Implement SelectionDAG::viewGraph() -----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This implements the SelectionDAG::viewGraph method.
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/ScheduleDAG.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
#include <fstream>
#include <sstream>
using namespace llvm;

namespace llvm {
  template<>
  struct DOTGraphTraits<SelectionDAG*> : public DefaultDOTGraphTraits {
    static bool hasEdgeDestLabels() {
      return true;
    }

    static unsigned numEdgeDestLabels(const void *Node) {
      return ((const SDNode *) Node)->getNumValues();
    }

    static std::string getEdgeDestLabel(const void *Node, unsigned i) {
      return ((const SDNode *) Node)->getValueType(i).getMVTString();
    }

    /// edgeTargetsEdgeSource - This method returns true if this outgoing edge
    /// should actually target another edge source, not a node.  If this method is
    /// implemented, getEdgeTarget should be implemented.
    template<typename EdgeIter>
    static bool edgeTargetsEdgeSource(const void *Node, EdgeIter I) {
      return true;
    }

    /// getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is
    /// called to determine which outgoing edge of Node is the target of this
    /// edge.
    template<typename EdgeIter>
    static EdgeIter getEdgeTarget(const void *Node, EdgeIter I) {
      SDNode *TargetNode = *I;
      SDNodeIterator NI = SDNodeIterator::begin(TargetNode);
      std::advance(NI, I.getNode()->getOperand(I.getOperand()).ResNo);
      return NI;
    }

    static std::string getGraphName(const SelectionDAG *G) {
      return G->getMachineFunction().getFunction()->getName();
    }

    static bool renderGraphFromBottomUp() {
      return true;
    }

    static bool hasNodeAddressLabel(const SDNode *Node,
                                    const SelectionDAG *Graph) {
      return true;
    }

    /// If you want to override the dot attributes printed for a particular
    /// edge, override this method.
    template<typename EdgeIter>
    static std::string getEdgeAttributes(const void *Node, EdgeIter EI) {
      SDValue Op = EI.getNode()->getOperand(EI.getOperand());
      MVT VT = Op.getValueType();
      if (VT == MVT::Flag)
        return "color=red,style=bold";
      else if (VT == MVT::Other)
        return "color=blue,style=dashed";
      return "";
    }

    static std::string getNodeLabel(const SDNode *Node,
                                    const SelectionDAG *Graph);
    static std::string getNodeAttributes(const SDNode *N,
                                         const SelectionDAG *Graph) {
#ifndef NDEBUG
      const std::string &Attrs = Graph->getGraphAttrs(N);
      if (!Attrs.empty()) {
        if (Attrs.find("shape=") == std::string::npos)
          return std::string("shape=Mrecord,") + Attrs;
        else
          return Attrs;
      }
#endif
      return "shape=Mrecord";
    }

    static void addCustomGraphFeatures(SelectionDAG *G,
                                       GraphWriter<SelectionDAG*> &GW) {
      GW.emitSimpleNode(0, "plaintext=circle", "GraphRoot");
      if (G->getRoot().Val)
        GW.emitEdge(0, -1, G->getRoot().Val, G->getRoot().ResNo,
                    "color=blue,style=dashed");
    }
  };
}

std::string DOTGraphTraits<SelectionDAG*>::getNodeLabel(const SDNode *Node,
                                                        const SelectionDAG *G) {
  std::string Op = Node->getOperationName(G);

  if (const ConstantSDNode *CSDN = dyn_cast<ConstantSDNode>(Node)) {
    Op += ": " + utostr(CSDN->getValue());
  } else if (const ConstantFPSDNode *CSDN = dyn_cast<ConstantFPSDNode>(Node)) {
    Op += ": " + ftostr(CSDN->getValueAPF());
  } else if (const GlobalAddressSDNode *GADN =
             dyn_cast<GlobalAddressSDNode>(Node)) {
    int offset = GADN->getOffset();
    Op += ": " + GADN->getGlobal()->getName();
    if (offset > 0)
      Op += "+" + itostr(offset);
    else
      Op += itostr(offset);
  } else if (const FrameIndexSDNode *FIDN = dyn_cast<FrameIndexSDNode>(Node)) {
    Op += " " + itostr(FIDN->getIndex());
  } else if (const JumpTableSDNode *JTDN = dyn_cast<JumpTableSDNode>(Node)) {
    Op += " " + itostr(JTDN->getIndex());
  } else if (const ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Node)){
    if (CP->isMachineConstantPoolEntry()) {
      std::ostringstream SS;
      CP->getMachineCPVal()->print(SS);
      Op += "<" + SS.str() + ">";
    } else {
      if (ConstantFP *CFP = dyn_cast<ConstantFP>(CP->getConstVal()))
        Op += "<" + ftostr(CFP->getValueAPF()) + ">";
      else if (ConstantInt *CI = dyn_cast<ConstantInt>(CP->getConstVal()))
        Op += "<" + utostr(CI->getZExtValue()) + ">";
      else {
        std::ostringstream SS;
        WriteAsOperand(SS, CP->getConstVal(), false);
        Op += "<" + SS.str() + ">";
      }
    }
  } else if (const BasicBlockSDNode *BBDN = dyn_cast<BasicBlockSDNode>(Node)) {
    Op = "BB: ";
    const Value *LBB = (const Value*)BBDN->getBasicBlock()->getBasicBlock();
    if (LBB)
      Op += LBB->getName();
    //Op += " " + (const void*)BBDN->getBasicBlock();
  } else if (const RegisterSDNode *R = dyn_cast<RegisterSDNode>(Node)) {
    if (G && R->getReg() != 0 &&
        TargetRegisterInfo::isPhysicalRegister(R->getReg())) {
      Op = Op + " " +
        G->getTarget().getRegisterInfo()->getName(R->getReg());
    } else {
      Op += " #" + utostr(R->getReg());
    }
  } else if (const DbgStopPointSDNode *D = dyn_cast<DbgStopPointSDNode>(Node)) {
    Op += ": " + D->getCompileUnit()->getFileName();
    Op += ":" + utostr(D->getLine());
    if (D->getColumn() != 0)
      Op += ":" + utostr(D->getColumn());
  } else if (const LabelSDNode *L = dyn_cast<LabelSDNode>(Node)) {
    Op += ": LabelID=" + utostr(L->getLabelID());
  } else if (const ExternalSymbolSDNode *ES =
             dyn_cast<ExternalSymbolSDNode>(Node)) {
    Op += "'" + std::string(ES->getSymbol()) + "'";
  } else if (const SrcValueSDNode *M = dyn_cast<SrcValueSDNode>(Node)) {
    if (M->getValue())
      Op += "<" + M->getValue()->getName() + ">";
    else
      Op += "<null>";
  } else if (const MemOperandSDNode *M = dyn_cast<MemOperandSDNode>(Node)) {
    const Value *V = M->MO.getValue();
    Op += '<';
    if (!V) {
      Op += "(unknown)";
    } else if (isa<PseudoSourceValue>(V)) {
      // PseudoSourceValues don't have names, so use their print method.
      std::ostringstream SS;
      M->MO.getValue()->print(SS);
      Op += SS.str();
    } else {
      Op += V->getName();
    }
    Op += '+' + itostr(M->MO.getOffset()) + '>';
  } else if (const ARG_FLAGSSDNode *N = dyn_cast<ARG_FLAGSSDNode>(Node)) {
    Op = Op + " AF=" + N->getArgFlags().getArgFlagsString();
  } else if (const VTSDNode *N = dyn_cast<VTSDNode>(Node)) {
    Op = Op + " VT=" + N->getVT().getMVTString();
  } else if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(Node)) {
    bool doExt = true;
    switch (LD->getExtensionType()) {
    default: doExt = false; break;
    case ISD::EXTLOAD:
      Op = Op + "<anyext ";
      break;
    case ISD::SEXTLOAD:
      Op = Op + " <sext ";
      break;
    case ISD::ZEXTLOAD:
      Op = Op + " <zext ";
      break;
    }
    if (doExt)
      Op += LD->getMemoryVT().getMVTString() + ">";
    if (LD->isVolatile())
      Op += "<V>";
    Op += LD->getIndexedModeName(LD->getAddressingMode());
    if (LD->getAlignment() > 1)
      Op += " A=" + utostr(LD->getAlignment());
  } else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(Node)) {
    if (ST->isTruncatingStore())
      Op += "<trunc " + ST->getMemoryVT().getMVTString() + ">";
    if (ST->isVolatile())
      Op += "<V>";
    Op += ST->getIndexedModeName(ST->getAddressingMode());
    if (ST->getAlignment() > 1)
      Op += " A=" + utostr(ST->getAlignment());
  }

#if 0
  Op += " Id=" + itostr(Node->getNodeId());
#endif

  return Op;
}

/// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
/// rendered using 'dot'.
///
void SelectionDAG::viewGraph(const std::string &Title) {
// This code is only for debugging!
#ifndef NDEBUG
  ViewGraph(this, "dag." + getMachineFunction().getFunction()->getName(),
            Title);
#else
  cerr << "SelectionDAG::viewGraph is only available in debug builds on "
       << "systems with Graphviz or gv!\n";
#endif  // NDEBUG
}

/// clearGraphAttrs - Clear all previously defined node graph attributes.
/// Intended to be used from a debugging tool (eg. gdb).
void SelectionDAG::clearGraphAttrs() {
#ifndef NDEBUG
  NodeGraphAttrs.clear();
#else
  cerr << "SelectionDAG::clearGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// setGraphAttrs - Set graph attributes for a node. (eg. "color=red".)
///
void SelectionDAG::setGraphAttrs(const SDNode *N, const char *Attrs) {
#ifndef NDEBUG
  NodeGraphAttrs[N] = Attrs;
#else
  cerr << "SelectionDAG::setGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// getGraphAttrs - Get graph attributes for a node. (eg. "color=red".)
/// Used from getNodeAttributes.
const std::string SelectionDAG::getGraphAttrs(const SDNode *N) const {
#ifndef NDEBUG
  std::map<const SDNode *, std::string>::const_iterator I =
    NodeGraphAttrs.find(N);

  if (I != NodeGraphAttrs.end())
    return I->second;
  else
    return "";
#else
  cerr << "SelectionDAG::getGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
  return std::string("");
#endif
}

/// setGraphColor - Convenience for setting node color attribute.
///
void SelectionDAG::setGraphColor(const SDNode *N, const char *Color) {
#ifndef NDEBUG
  NodeGraphAttrs[N] = std::string("color=") + Color;
#else
  cerr << "SelectionDAG::setGraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

namespace llvm {
  template<>
  struct DOTGraphTraits<ScheduleDAG*> : public DefaultDOTGraphTraits {
    static std::string getGraphName(const ScheduleDAG *G) {
      return DOTGraphTraits<SelectionDAG*>::getGraphName(&G->DAG);
    }

    static bool renderGraphFromBottomUp() {
      return true;
    }

    static bool hasNodeAddressLabel(const SUnit *Node,
                                    const ScheduleDAG *Graph) {
      return true;
    }

    /// If you want to override the dot attributes printed for a particular
    /// edge, override this method.
    template<typename EdgeIter>
    static std::string getEdgeAttributes(const void *Node, EdgeIter EI) {
      if (EI.isSpecialDep())
        return "color=cyan,style=dashed";
      if (EI.isCtrlDep())
        return "color=blue,style=dashed";
      return "";
    }

    static std::string getNodeLabel(const SUnit *Node,
                                    const ScheduleDAG *Graph);
    static std::string getNodeAttributes(const SUnit *N,
                                         const ScheduleDAG *Graph) {
      return "shape=Mrecord";
    }

    static void addCustomGraphFeatures(ScheduleDAG *G,
                                       GraphWriter<ScheduleDAG*> &GW) {
      GW.emitSimpleNode(0, "plaintext=circle", "GraphRoot");
      const SDNode *N = G->DAG.getRoot().Val;
      if (N && N->getNodeId() != -1)
        GW.emitEdge(0, -1, &G->SUnits[N->getNodeId()], -1, "");
    }
  };
}

std::string DOTGraphTraits<ScheduleDAG*>::getNodeLabel(const SUnit *SU,
                                                       const ScheduleDAG *G) {
  std::string Op;

  for (unsigned i = 0; i < SU->FlaggedNodes.size(); ++i) {
    Op += DOTGraphTraits<SelectionDAG*>::getNodeLabel(SU->FlaggedNodes[i],
                                                      &G->DAG) + "\n";
  }

  if (SU->Node)
    Op += DOTGraphTraits<SelectionDAG*>::getNodeLabel(SU->Node, &G->DAG);
  else
    Op += "<CROSS RC COPY>";

  return Op;
}

/// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
/// rendered using 'dot'.
///
void ScheduleDAG::viewGraph() {
// This code is only for debugging!
#ifndef NDEBUG
  ViewGraph(this, "dag." + MF->getFunction()->getName(),
            "Scheduling-Units Graph for " + MF->getFunction()->getName() + ':' +
            BB->getBasicBlock()->getName());
#else
  cerr << "ScheduleDAG::viewGraph is only available in debug builds on "
       << "systems with Graphviz or gv!\n";
#endif  // NDEBUG
}
<commit_msg>Make the ScheduleDAG's GraphRoot edge be blue and dashed too, like the SelectionDAG's.<commit_after>//===-- SelectionDAGPrinter.cpp - Implement SelectionDAG::viewGraph() -----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This implements the SelectionDAG::viewGraph method.
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/ScheduleDAG.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
#include <fstream>
#include <sstream>
using namespace llvm;

namespace llvm {
  template<>
  struct DOTGraphTraits<SelectionDAG*> : public DefaultDOTGraphTraits {
    static bool hasEdgeDestLabels() {
      return true;
    }

    static unsigned numEdgeDestLabels(const void *Node) {
      return ((const SDNode *) Node)->getNumValues();
    }

    static std::string getEdgeDestLabel(const void *Node, unsigned i) {
      return ((const SDNode *) Node)->getValueType(i).getMVTString();
    }

    /// edgeTargetsEdgeSource - This method returns true if this outgoing edge
    /// should actually target another edge source, not a node.  If this method is
    /// implemented, getEdgeTarget should be implemented.
    template<typename EdgeIter>
    static bool edgeTargetsEdgeSource(const void *Node, EdgeIter I) {
      return true;
    }

    /// getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is
    /// called to determine which outgoing edge of Node is the target of this
    /// edge.
    template<typename EdgeIter>
    static EdgeIter getEdgeTarget(const void *Node, EdgeIter I) {
      SDNode *TargetNode = *I;
      SDNodeIterator NI = SDNodeIterator::begin(TargetNode);
      std::advance(NI, I.getNode()->getOperand(I.getOperand()).ResNo);
      return NI;
    }

    static std::string getGraphName(const SelectionDAG *G) {
      return G->getMachineFunction().getFunction()->getName();
    }

    static bool renderGraphFromBottomUp() {
      return true;
    }

    static bool hasNodeAddressLabel(const SDNode *Node,
                                    const SelectionDAG *Graph) {
      return true;
    }

    /// If you want to override the dot attributes printed for a particular
    /// edge, override this method.
    template<typename EdgeIter>
    static std::string getEdgeAttributes(const void *Node, EdgeIter EI) {
      SDValue Op = EI.getNode()->getOperand(EI.getOperand());
      MVT VT = Op.getValueType();
      if (VT == MVT::Flag)
        return "color=red,style=bold";
      else if (VT == MVT::Other)
        return "color=blue,style=dashed";
      return "";
    }

    static std::string getNodeLabel(const SDNode *Node,
                                    const SelectionDAG *Graph);
    static std::string getNodeAttributes(const SDNode *N,
                                         const SelectionDAG *Graph) {
#ifndef NDEBUG
      const std::string &Attrs = Graph->getGraphAttrs(N);
      if (!Attrs.empty()) {
        if (Attrs.find("shape=") == std::string::npos)
          return std::string("shape=Mrecord,") + Attrs;
        else
          return Attrs;
      }
#endif
      return "shape=Mrecord";
    }

    static void addCustomGraphFeatures(SelectionDAG *G,
                                       GraphWriter<SelectionDAG*> &GW) {
      GW.emitSimpleNode(0, "plaintext=circle", "GraphRoot");
      if (G->getRoot().Val)
        GW.emitEdge(0, -1, G->getRoot().Val, G->getRoot().ResNo,
                    "color=blue,style=dashed");
    }
  };
}

std::string DOTGraphTraits<SelectionDAG*>::getNodeLabel(const SDNode *Node,
                                                        const SelectionDAG *G) {
  std::string Op = Node->getOperationName(G);

  if (const ConstantSDNode *CSDN = dyn_cast<ConstantSDNode>(Node)) {
    Op += ": " + utostr(CSDN->getValue());
  } else if (const ConstantFPSDNode *CSDN = dyn_cast<ConstantFPSDNode>(Node)) {
    Op += ": " + ftostr(CSDN->getValueAPF());
  } else if (const GlobalAddressSDNode *GADN =
             dyn_cast<GlobalAddressSDNode>(Node)) {
    int offset = GADN->getOffset();
    Op += ": " + GADN->getGlobal()->getName();
    if (offset > 0)
      Op += "+" + itostr(offset);
    else
      Op += itostr(offset);
  } else if (const FrameIndexSDNode *FIDN = dyn_cast<FrameIndexSDNode>(Node)) {
    Op += " " + itostr(FIDN->getIndex());
  } else if (const JumpTableSDNode *JTDN = dyn_cast<JumpTableSDNode>(Node)) {
    Op += " " + itostr(JTDN->getIndex());
  } else if (const ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Node)){
    if (CP->isMachineConstantPoolEntry()) {
      std::ostringstream SS;
      CP->getMachineCPVal()->print(SS);
      Op += "<" + SS.str() + ">";
    } else {
      if (ConstantFP *CFP = dyn_cast<ConstantFP>(CP->getConstVal()))
        Op += "<" + ftostr(CFP->getValueAPF()) + ">";
      else if (ConstantInt *CI = dyn_cast<ConstantInt>(CP->getConstVal()))
        Op += "<" + utostr(CI->getZExtValue()) + ">";
      else {
        std::ostringstream SS;
        WriteAsOperand(SS, CP->getConstVal(), false);
        Op += "<" + SS.str() + ">";
      }
    }
  } else if (const BasicBlockSDNode *BBDN = dyn_cast<BasicBlockSDNode>(Node)) {
    Op = "BB: ";
    const Value *LBB = (const Value*)BBDN->getBasicBlock()->getBasicBlock();
    if (LBB)
      Op += LBB->getName();
    //Op += " " + (const void*)BBDN->getBasicBlock();
  } else if (const RegisterSDNode *R = dyn_cast<RegisterSDNode>(Node)) {
    if (G && R->getReg() != 0 &&
        TargetRegisterInfo::isPhysicalRegister(R->getReg())) {
      Op = Op + " " +
        G->getTarget().getRegisterInfo()->getName(R->getReg());
    } else {
      Op += " #" + utostr(R->getReg());
    }
  } else if (const DbgStopPointSDNode *D = dyn_cast<DbgStopPointSDNode>(Node)) {
    Op += ": " + D->getCompileUnit()->getFileName();
    Op += ":" + utostr(D->getLine());
    if (D->getColumn() != 0)
      Op += ":" + utostr(D->getColumn());
  } else if (const LabelSDNode *L = dyn_cast<LabelSDNode>(Node)) {
    Op += ": LabelID=" + utostr(L->getLabelID());
  } else if (const ExternalSymbolSDNode *ES =
             dyn_cast<ExternalSymbolSDNode>(Node)) {
    Op += "'" + std::string(ES->getSymbol()) + "'";
  } else if (const SrcValueSDNode *M = dyn_cast<SrcValueSDNode>(Node)) {
    if (M->getValue())
      Op += "<" + M->getValue()->getName() + ">";
    else
      Op += "<null>";
  } else if (const MemOperandSDNode *M = dyn_cast<MemOperandSDNode>(Node)) {
    const Value *V = M->MO.getValue();
    Op += '<';
    if (!V) {
      Op += "(unknown)";
    } else if (isa<PseudoSourceValue>(V)) {
      // PseudoSourceValues don't have names, so use their print method.
      std::ostringstream SS;
      M->MO.getValue()->print(SS);
      Op += SS.str();
    } else {
      Op += V->getName();
    }
    Op += '+' + itostr(M->MO.getOffset()) + '>';
  } else if (const ARG_FLAGSSDNode *N = dyn_cast<ARG_FLAGSSDNode>(Node)) {
    Op = Op + " AF=" + N->getArgFlags().getArgFlagsString();
  } else if (const VTSDNode *N = dyn_cast<VTSDNode>(Node)) {
    Op = Op + " VT=" + N->getVT().getMVTString();
  } else if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(Node)) {
    bool doExt = true;
    switch (LD->getExtensionType()) {
    default: doExt = false; break;
    case ISD::EXTLOAD:
      Op = Op + "<anyext ";
      break;
    case ISD::SEXTLOAD:
      Op = Op + " <sext ";
      break;
    case ISD::ZEXTLOAD:
      Op = Op + " <zext ";
      break;
    }
    if (doExt)
      Op += LD->getMemoryVT().getMVTString() + ">";
    if (LD->isVolatile())
      Op += "<V>";
    Op += LD->getIndexedModeName(LD->getAddressingMode());
    if (LD->getAlignment() > 1)
      Op += " A=" + utostr(LD->getAlignment());
  } else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(Node)) {
    if (ST->isTruncatingStore())
      Op += "<trunc " + ST->getMemoryVT().getMVTString() + ">";
    if (ST->isVolatile())
      Op += "<V>";
    Op += ST->getIndexedModeName(ST->getAddressingMode());
    if (ST->getAlignment() > 1)
      Op += " A=" + utostr(ST->getAlignment());
  }

#if 0
  Op += " Id=" + itostr(Node->getNodeId());
#endif

  return Op;
}

/// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
/// rendered using 'dot'.
///
void SelectionDAG::viewGraph(const std::string &Title) {
// This code is only for debugging!
#ifndef NDEBUG
  ViewGraph(this, "dag." + getMachineFunction().getFunction()->getName(),
            Title);
#else
  cerr << "SelectionDAG::viewGraph is only available in debug builds on "
       << "systems with Graphviz or gv!\n";
#endif  // NDEBUG
}

/// clearGraphAttrs - Clear all previously defined node graph attributes.
/// Intended to be used from a debugging tool (eg. gdb).
void SelectionDAG::clearGraphAttrs() {
#ifndef NDEBUG
  NodeGraphAttrs.clear();
#else
  cerr << "SelectionDAG::clearGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// setGraphAttrs - Set graph attributes for a node. (eg. "color=red".)
///
void SelectionDAG::setGraphAttrs(const SDNode *N, const char *Attrs) {
#ifndef NDEBUG
  NodeGraphAttrs[N] = Attrs;
#else
  cerr << "SelectionDAG::setGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// getGraphAttrs - Get graph attributes for a node. (eg. "color=red".)
/// Used from getNodeAttributes.
const std::string SelectionDAG::getGraphAttrs(const SDNode *N) const {
#ifndef NDEBUG
  std::map<const SDNode *, std::string>::const_iterator I =
    NodeGraphAttrs.find(N);

  if (I != NodeGraphAttrs.end())
    return I->second;
  else
    return "";
#else
  cerr << "SelectionDAG::getGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
  return std::string("");
#endif
}

/// setGraphColor - Convenience for setting node color attribute.
///
void SelectionDAG::setGraphColor(const SDNode *N, const char *Color) {
#ifndef NDEBUG
  NodeGraphAttrs[N] = std::string("color=") + Color;
#else
  cerr << "SelectionDAG::setGraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

namespace llvm {
  template<>
  struct DOTGraphTraits<ScheduleDAG*> : public DefaultDOTGraphTraits {
    static std::string getGraphName(const ScheduleDAG *G) {
      return DOTGraphTraits<SelectionDAG*>::getGraphName(&G->DAG);
    }

    static bool renderGraphFromBottomUp() {
      return true;
    }

    static bool hasNodeAddressLabel(const SUnit *Node,
                                    const ScheduleDAG *Graph) {
      return true;
    }

    /// If you want to override the dot attributes printed for a particular
    /// edge, override this method.
    template<typename EdgeIter>
    static std::string getEdgeAttributes(const void *Node, EdgeIter EI) {
      if (EI.isSpecialDep())
        return "color=cyan,style=dashed";
      if (EI.isCtrlDep())
        return "color=blue,style=dashed";
      return "";
    }

    static std::string getNodeLabel(const SUnit *Node,
                                    const ScheduleDAG *Graph);
    static std::string getNodeAttributes(const SUnit *N,
                                         const ScheduleDAG *Graph) {
      return "shape=Mrecord";
    }

    static void addCustomGraphFeatures(ScheduleDAG *G,
                                       GraphWriter<ScheduleDAG*> &GW) {
      GW.emitSimpleNode(0, "plaintext=circle", "GraphRoot");
      const SDNode *N = G->DAG.getRoot().Val;
      if (N && N->getNodeId() != -1)
        GW.emitEdge(0, -1, &G->SUnits[N->getNodeId()], -1,
                    "color=blue,style=dashed");
    }
  };
}

std::string DOTGraphTraits<ScheduleDAG*>::getNodeLabel(const SUnit *SU,
                                                       const ScheduleDAG *G) {
  std::string Op;

  for (unsigned i = 0; i < SU->FlaggedNodes.size(); ++i) {
    Op += DOTGraphTraits<SelectionDAG*>::getNodeLabel(SU->FlaggedNodes[i],
                                                      &G->DAG) + "\n";
  }

  if (SU->Node)
    Op += DOTGraphTraits<SelectionDAG*>::getNodeLabel(SU->Node, &G->DAG);
  else
    Op += "<CROSS RC COPY>";

  return Op;
}

/// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
/// rendered using 'dot'.
///
void ScheduleDAG::viewGraph() {
// This code is only for debugging!
#ifndef NDEBUG
  ViewGraph(this, "dag." + MF->getFunction()->getName(),
            "Scheduling-Units Graph for " + MF->getFunction()->getName() + ':' +
            BB->getBasicBlock()->getName());
#else
  cerr << "ScheduleDAG::viewGraph is only available in debug builds on "
       << "systems with Graphviz or gv!\n";
#endif  // NDEBUG
}
<|endoftext|>


<commit_before>//              Implementation of the AAA algorithm
//
//   Here, we implement the triple-A algorithm [1] for the rational approximation
//   of complex-valued functions,
//
//          p(z)/q(z) ≈ f(z).
//
//   In this file, we always assume f(z) = z^{-α}. The triple-A algorithm
//   provides a robust, accurate approximation in rational barycentric form.
//   This representation must be transformed into a partial fraction
//   representation in order to be used to solve a spectral FPDE.
//
//   More specifically, we first expand the numerator in terms of the zeros of
//   the rational approximation,
//
//          p(z) ∝ Π_i (z - z_i),
//
//   and expand the denominator in terms of the poles of the rational
//   approximation,
//
//          q(z) ∝ Π_i (z - p_i).
//
//   We then use these zeros and poles to derive the partial fraction
//   expansion
//
//          f(z) ≈ p(z)/q(z) = Σ_i c_i / (z - p_i).
//
//
//   REFERENCE
//
//   [1] Nakatsukasa, Y., Sète, O., & Trefethen, L. N. (2018). The AAA
//       algorithm for rational approximation. SIAM Journal on Scientific
//       Computing, 40(3), A1494-A1522.

#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace std;
using namespace mfem;

/**
 * RationalApproximation_AAA : compute the rational approximation (RA) of
 * data @a val at the set of points @a pt.
 *
 *  INPUT:  @a val       = vector of data values
 *          @a pt        = vector of sample points
 *          @a tol       = relative tolerance
 *          @a max_order = maximum number of terms (order) of the RA
 *
 *  OUTPUT: @a z = support points of the RA in rational barycentric form
 *          @a f = data values at support points @a z
 *          @a w = weights of the RA in rational barycentric form
 *
 * See pg. A1501 of Nakatsukasa et al. [1].
 */
void RationalApproximation_AAA(const Vector &val, const Vector &pt,
                               Array<double> &z, Array<double> &f, Vector &w,
                               double tol, int max_order)
{

   // number of sample points
   int size = val.Size();
   MFEM_VERIFY(pt.Size() == size, "size mismatch");

   // Initializations
   Array<int> J(size);
   for (int i = 0; i < size; i++) { J[i] = i; }
   z.SetSize(0);
   f.SetSize(0);

   DenseMatrix C, Ctemp, A, Am;
   // auxiliary arrays and vectors
   Vector f_vec;
   Array<double> c_i;

   // mean of the value vector
   Vector R(val.Size());
   double mean_val = val.Sum()/size;

   for (int i = 0; i<R.Size(); i++) { R(i) = mean_val; }

   for (int k = 0; k < max_order; k++)
   {
      // select next support point
      int idx = 0;
      double tmp_max = 0;
      for (int j = 0; j < size; j++)
      {
         double tmp = abs(val(j)-R(j));
         if (tmp > tmp_max)
         {
            tmp_max = tmp;
            idx = j;
         }
      }

      // Append support points and data values
      z.Append(pt(idx));
      f.Append(val(idx));

      // Update index vector
      J.DeleteFirst(idx);

      // next column in Cauchy matrix
      Array<double> C_tmp(size);
      for (int j = 0; j < size; j++)
      {
         C_tmp[j] = 1.0/(pt(j)-pt(idx));
      }
      c_i.Append(C_tmp);
      int h_C = C_tmp.Size();
      int w_C = k+1;
      C.UseExternalData(c_i.GetData(),h_C,w_C);

      Ctemp = C;

      f_vec.SetDataAndSize(f.GetData(),f.Size());
      Ctemp.InvLeftScaling(val);
      Ctemp.RightScaling(f_vec);

      A.SetSize(C.Height(), C.Width());
      Add(C,Ctemp,-1.0,A);
      A.LeftScaling(val);

      int h_Am = J.Size();
      int w_Am = A.Width();
      Am.SetSize(h_Am,w_Am);
      for (int i = 0; i<h_Am; i++)
      {
         int ii = J[i];
         for (int j = 0; j<w_Am; j++)
         {
            Am(i,j) = A(ii,j);
         }
      }

#ifdef MFEM_USE_LAPACK
      DenseMatrixSVD svd(Am,false,true);
      svd.Eval(Am);
      DenseMatrix &v = svd.RightSingularvectors();
      v.GetRow(k,w);
#else
      mfem_error("Compiled without LAPACK");
#endif

      // N = C*(w.*f); D = C*w; % numerator and denominator
      Vector aux(w);
      aux *= f_vec;
      Vector N(C.Height()); // Numerator
      C.Mult(aux,N);
      Vector D(C.Height()); // Denominator
      C.Mult(w,D);

      R = val;
      for (int i = 0; i<J.Size(); i++)
      {
         int ii = J[i];
         R(ii) = N(ii)/D(ii);
      }

      Vector verr(val);
      verr-=R;

      if (verr.Normlinf() <= tol*val.Normlinf()) { break; }
   }
}

/**
 * ComputePolesAndZeros : computes the @a poles and @a zeros of the rational
 * rational function f(z) = C p(z)/q(z) from its ration barycentric form.
 *
 *  INPUT:  @a z = support points in rational barycentric form
 *          @a f = data values at support points @a z
 *          @a w = weights in rational barycentric form
 *
 *  OUTPUT: @a poles = array of poles (roots of p(z))
 *          @a zeros = array of zeros (roots of q(z))
 *          @a scale = scaling constant in f(z) = C p(z)/q(z)
 *
 * See pg. A1501 of Nakatsukasa et al. [1].
 */
void ComputePolesAndZeros(const Vector &z, const Vector &f, const Vector &w,
                          Array<double> & poles, Array<double> & zeros, double &scale)
{
   // Initialization
   poles.SetSize(0);
   zeros.SetSize(0);

   // Compute the poles
   int m = w.Size();
   DenseMatrix B(m+1); B = 0.;
   DenseMatrix E(m+1); E = 0.;
   for (int i = 1; i<=m; i++)
   {
      B(i,i) = 1.;
      E(0,i) = w(i-1);
      E(i,0) = 1.;
      E(i,i) = z(i-1);
   }

#ifdef MFEM_USE_LAPACK
   DenseMatrixGeneralizedEigensystem eig1(E,B);
   eig1.Eval();
   Vector & evalues = eig1.EigenvaluesRealPart();
   for (int i = 0; i<evalues.Size(); i++)
   {
      if (IsFinite(evalues(i)))
      {
         poles.Append(evalues(i));
      }
   }
#else
   mfem_error("Compiled without LAPACK");
#endif
   // compute the zeros
   B = 0.;
   E = 0.;
   for (int i = 1; i<=m; i++)
   {
      B(i,i) = 1.;
      E(0,i) = w(i-1) * f(i-1);
      E(i,0) = 1.;
      E(i,i) = z(i-1);
   }

#ifdef MFEM_USE_LAPACK
   DenseMatrixGeneralizedEigensystem eig2(E,B);
   eig2.Eval();
   evalues = eig2.EigenvaluesRealPart();
   for (int i = 0; i<evalues.Size(); i++)
   {
      if (IsFinite(evalues(i)))
      {
         zeros.Append(evalues(i));
      }
   }
#else
   mfem_error("Compiled without LAPACK");
#endif

   scale = w * f / w.Sum();
}

/**
 * PartialFractionExpansion : computes the partial fraction expansion
 * of the rational rational function f(z) = Σ_i c_i / (z - p_i) from its
 * @a poles and @a zeros.
 *
 *  INPUT:  @a poles = array of poles (same as p_i above)
 *          @a zeros = array of zeros
 *          @a scale = scaling constant
 *
 *  OUTPUT: @a coeffs = coefficients c_i
 *
 */
void PartialFractionExpansion(double scale, Array<double> & poles,
                              Array<double> & zeros, Array<double> & coeffs)
{
   int psize = poles.Size();
   int zsize = zeros.Size();
   coeffs.SetSize(psize);
   coeffs = scale;

   for (int i=0; i<psize; i++)
   {
      double tmp_numer=1.0;
      for (int j=0; j<zsize; j++)
      {
         tmp_numer *= poles[i]-zeros[j];
      }

      double tmp_denom=1.0;
      for (int k=0; k<psize; k++)
      {
         if (k != i) { tmp_denom *= poles[i]-poles[k]; }
      }
      coeffs[i] *= tmp_numer / tmp_denom;
   }
}

/**
 * ComputePartialFractionApproximation : computes a rational approximation (RA) of the function
 * f(z) = z^{-a}, 0 < a < 1, in partial fraction form f(z) ≈ Σ_i c_i / (z - p_i).
 *
 *  INPUT:  @a alpha     = exponent in f(z) = z^-a
 *          @a lmin, @a lmax, @a npoints
 *                       = f(z) is uniformly sampled @a npoints times on
 *                         the interval [ @a lmin, @a lmax]
 *          @a tol       = relative tolerance
 *          @a max_order = maximum number of terms (order) of the RA
 *
 *  OUTPUT: @a coeffs = coefficients c_i
 *          @a poles  = poles p_i
 *
 * See pg. A1501 of Nakatsukasa et al. [1].
 */
void ComputePartialFractionApproximation(double alpha,
                                         Array<double> & coeffs, Array<double> & poles,
                                         double lmin = 1., double lmax = 1000.,
                                         double tol=1e-10,  int npoints = 1000,
                                         int max_order = 100)
{
#ifndef MFEM_USE_LAPACK
   mfem::out
         << "MFEM is compiled without LAPACK. Using precomputed PartialFractionApproximation"
         << std::endl;

   MFEM_ASSERT(alpha < 1, "alpha must be less than 1");
   MFEM_ASSERT(alpha > 0, "alpha must be greater than 0");

   if (alpha == 0.33)
   {
      coeffs = Array<double> ({2002.55,  99.7691,  29.0575,  12.9842,
                               6.90263,  3.96688,  2.36013,  1.42565,
                               0.867623, 0.529436, 0.317975, 0.0891797});
      poles = Array<double> ({-47928.,  -3451.45, -996.636, -388.58,
                              -168.228, -75.3162, -33.6235, -14.5403,
                              -5.84563, -1.9975, -0.434608,  0.});
   }
   else if (alpha == 0.99)
   {
      coeffs = Array<double>({0.0292386, 0.0143338, 0.0109015, 0.00976958,
                              0.00943417, 0.00948077, 0.00985799, 0.010889,
                              0.0138588, 0.0263289, 0.96953});
      poles = Array<double> ({-10085.1, -1652.6, -524.342, -199.521,
                              -80.2328, -32.3926, -12.7148, -4.63855,
                              -1.39884, -0.221076, 0.});
   }
   else
   {
      if (alpha != 0.5)
      {
         mfem::out << "Using default value of alpha = 0.5" << std::endl;
      }
      coeffs = Array<double>({209.629, 24.2714, 9.24812, 4.93138,
                              3.02653, 1.98265, 1.34293, 0.931714,
                              0.664382, 0.492972, 0.39114, 0.177527});
      poles = Array<double>({-26466.7, -2673.76, -800.03, -312.646,
                             -134.551, -59.8651, -26.6607, -11.5603,
                             -4.67241, -1.59503, -0.332738, 0.});
   }
   return;
#endif

   Vector x(npoints);
   Vector val(npoints);
   for (int i = 0; i<npoints; i++)
   {
      x(i) = (double)i+1.0;
      val(i) = pow(x(i),1.-alpha);
   }

   // Apply triple-A algorithm to f(x) = x^{1-a}
   Array<double> z, f;
   Vector w;
   RationalApproximation_AAA(val,x,z,f,w,tol,max_order);

   Vector vecz, vecf;
   vecz.SetDataAndSize(z.GetData(), z.Size());
   vecf.SetDataAndSize(f.GetData(), f.Size());

   // Compute poles and zeros for RA of f(x) = x^{1-a}
   double scale;
   Array<double> zeros;
   ComputePolesAndZeros(vecz, vecf, w, poles, zeros, scale);

   // Introduce one extra pole at x=0, thus, delivering a
   // RA for f(x) = x^{-a}
   poles.Append(0.0);

   // Compute partial fraction approximation of f(x) = x^{-a}
   PartialFractionExpansion(scale, poles, zeros, coeffs);
}
<commit_msg>minor<commit_after>//              Implementation of the AAA algorithm
//
//   Here, we implement the triple-A algorithm [1] for the rational approximation
//   of complex-valued functions,
//
//          p(z)/q(z) ≈ f(z).
//
//   In this file, we always assume f(z) = z^{-α}. The triple-A algorithm
//   provides a robust, accurate approximation in rational barycentric form.
//   This representation must be transformed into a partial fraction
//   representation in order to be used to solve a spectral FPDE.
//
//   More specifically, we first expand the numerator in terms of the zeros of
//   the rational approximation,
//
//          p(z) ∝ Π_i (z - z_i),
//
//   and expand the denominator in terms of the poles of the rational
//   approximation,
//
//          q(z) ∝ Π_i (z - p_i).
//
//   We then use these zeros and poles to derive the partial fraction
//   expansion
//
//          f(z) ≈ p(z)/q(z) = Σ_i c_i / (z - p_i).
//
//
//   REFERENCE
//
//   [1] Nakatsukasa, Y., Sète, O., & Trefethen, L. N. (2018). The AAA
//       algorithm for rational approximation. SIAM Journal on Scientific
//       Computing, 40(3), A1494-A1522.

#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace std;
using namespace mfem;

/**
 * RationalApproximation_AAA : compute the rational approximation (RA) of
 * data @a val at the set of points @a pt.
 *
 *  INPUT:  @a val       = vector of data values
 *          @a pt        = vector of sample points
 *          @a tol       = relative tolerance
 *          @a max_order = maximum number of terms (order) of the RA
 *
 *  OUTPUT: @a z = support points of the RA in rational barycentric form
 *          @a f = data values at support points @a z
 *          @a w = weights of the RA in rational barycentric form
 *
 * See pg. A1501 of Nakatsukasa et al. [1].
 */
void RationalApproximation_AAA(const Vector &val, const Vector &pt,
                               Array<double> &z, Array<double> &f, Vector &w,
                               double tol, int max_order)
{

   // number of sample points
   int size = val.Size();
   MFEM_VERIFY(pt.Size() == size, "size mismatch");

   // Initializations
   Array<int> J(size);
   for (int i = 0; i < size; i++) { J[i] = i; }
   z.SetSize(0);
   f.SetSize(0);

   DenseMatrix C, Ctemp, A, Am;
   // auxiliary arrays and vectors
   Vector f_vec;
   Array<double> c_i;

   // mean of the value vector
   Vector R(val.Size());
   double mean_val = val.Sum()/size;

   for (int i = 0; i<R.Size(); i++) { R(i) = mean_val; }

   for (int k = 0; k < max_order; k++)
   {
      // select next support point
      int idx = 0;
      double tmp_max = 0;
      for (int j = 0; j < size; j++)
      {
         double tmp = abs(val(j)-R(j));
         if (tmp > tmp_max)
         {
            tmp_max = tmp;
            idx = j;
         }
      }

      // Append support points and data values
      z.Append(pt(idx));
      f.Append(val(idx));

      // Update index vector
      J.DeleteFirst(idx);

      // next column in Cauchy matrix
      Array<double> C_tmp(size);
      for (int j = 0; j < size; j++)
      {
         C_tmp[j] = 1.0/(pt(j)-pt(idx));
      }
      c_i.Append(C_tmp);
      int h_C = C_tmp.Size();
      int w_C = k+1;
      C.UseExternalData(c_i.GetData(),h_C,w_C);

      Ctemp = C;

      f_vec.SetDataAndSize(f.GetData(),f.Size());
      Ctemp.InvLeftScaling(val);
      Ctemp.RightScaling(f_vec);

      A.SetSize(C.Height(), C.Width());
      Add(C,Ctemp,-1.0,A);
      A.LeftScaling(val);

      int h_Am = J.Size();
      int w_Am = A.Width();
      Am.SetSize(h_Am,w_Am);
      for (int i = 0; i<h_Am; i++)
      {
         int ii = J[i];
         for (int j = 0; j<w_Am; j++)
         {
            Am(i,j) = A(ii,j);
         }
      }

#ifdef MFEM_USE_LAPACK
      DenseMatrixSVD svd(Am,false,true);
      svd.Eval(Am);
      DenseMatrix &v = svd.RightSingularvectors();
      v.GetRow(k,w);
#else
      mfem_error("Compiled without LAPACK");
#endif

      // N = C*(w.*f); D = C*w; % numerator and denominator
      Vector aux(w);
      aux *= f_vec;
      Vector N(C.Height()); // Numerator
      C.Mult(aux,N);
      Vector D(C.Height()); // Denominator
      C.Mult(w,D);

      R = val;
      for (int i = 0; i<J.Size(); i++)
      {
         int ii = J[i];
         R(ii) = N(ii)/D(ii);
      }

      Vector verr(val);
      verr-=R;

      if (verr.Normlinf() <= tol*val.Normlinf()) { break; }
   }
}

/**
 * ComputePolesAndZeros : computes the @a poles and @a zeros of the rational
 * rational function f(z) = C p(z)/q(z) from its ration barycentric form.
 *
 *  INPUT:  @a z = support points in rational barycentric form
 *          @a f = data values at support points @a z
 *          @a w = weights in rational barycentric form
 *
 *  OUTPUT: @a poles = array of poles (roots of p(z))
 *          @a zeros = array of zeros (roots of q(z))
 *          @a scale = scaling constant in f(z) = C p(z)/q(z)
 *
 * See pg. A1501 of Nakatsukasa et al. [1].
 */
void ComputePolesAndZeros(const Vector &z, const Vector &f, const Vector &w,
                          Array<double> & poles, Array<double> & zeros, double &scale)
{
   // Initialization
   poles.SetSize(0);
   zeros.SetSize(0);

   // Compute the poles
   int m = w.Size();
   DenseMatrix B(m+1); B = 0.;
   DenseMatrix E(m+1); E = 0.;
   for (int i = 1; i<=m; i++)
   {
      B(i,i) = 1.;
      E(0,i) = w(i-1);
      E(i,0) = 1.;
      E(i,i) = z(i-1);
   }

#ifdef MFEM_USE_LAPACK
   DenseMatrixGeneralizedEigensystem eig1(E,B);
   eig1.Eval();
   Vector & evalues = eig1.EigenvaluesRealPart();
   for (int i = 0; i<evalues.Size(); i++)
   {
      if (IsFinite(evalues(i)))
      {
         poles.Append(evalues(i));
      }
   }
#else
   mfem_error("Compiled without LAPACK");
#endif
   // compute the zeros
   B = 0.;
   E = 0.;
   for (int i = 1; i<=m; i++)
   {
      B(i,i) = 1.;
      E(0,i) = w(i-1) * f(i-1);
      E(i,0) = 1.;
      E(i,i) = z(i-1);
   }

#ifdef MFEM_USE_LAPACK
   DenseMatrixGeneralizedEigensystem eig2(E,B);
   eig2.Eval();
   evalues = eig2.EigenvaluesRealPart();
   for (int i = 0; i<evalues.Size(); i++)
   {
      if (IsFinite(evalues(i)))
      {
         zeros.Append(evalues(i));
      }
   }
#else
   mfem_error("Compiled without LAPACK");
#endif

   scale = w * f / w.Sum();
}

/**
 * PartialFractionExpansion : computes the partial fraction expansion
 * of the rational rational function f(z) = Σ_i c_i / (z - p_i) from its
 * @a poles and @a zeros.
 *
 *  INPUT:  @a poles = array of poles (same as p_i above)
 *          @a zeros = array of zeros
 *          @a scale = scaling constant
 *
 *  OUTPUT: @a coeffs = coefficients c_i
 *
 */
void PartialFractionExpansion(double scale, Array<double> & poles,
                              Array<double> & zeros, Array<double> & coeffs)
{
   int psize = poles.Size();
   int zsize = zeros.Size();
   coeffs.SetSize(psize);
   coeffs = scale;

   for (int i=0; i<psize; i++)
   {
      double tmp_numer=1.0;
      for (int j=0; j<zsize; j++)
      {
         tmp_numer *= poles[i]-zeros[j];
      }

      double tmp_denom=1.0;
      for (int k=0; k<psize; k++)
      {
         if (k != i) { tmp_denom *= poles[i]-poles[k]; }
      }
      coeffs[i] *= tmp_numer / tmp_denom;
   }
}

/**
 * ComputePartialFractionApproximation : computes a rational approximation (RA) of the function
 * f(z) = z^{-a}, 0 < a < 1, in partial fraction form f(z) ≈ Σ_i c_i / (z - p_i).
 *
 *  INPUT:  @a alpha     = exponent in f(z) = z^-a
 *          @a lmin, @a lmax, @a npoints
 *                       = f(z) is uniformly sampled @a npoints times on
 *                         the interval [ @a lmin, @a lmax]
 *          @a tol       = relative tolerance
 *          @a max_order = maximum number of terms (order) of the RA
 *
 *  OUTPUT: @a coeffs = coefficients c_i
 *          @a poles  = poles p_i
 *
 * See pg. A1501 of Nakatsukasa et al. [1].
 */
void ComputePartialFractionApproximation(double alpha,
                                         Array<double> & coeffs, Array<double> & poles,
                                         double lmin = 1., double lmax = 1000.,
                                         double tol=1e-10,  int npoints = 1000,
                                         int max_order = 100)
{
#ifndef MFEM_USE_LAPACK
   mfem::out
         << "MFEM is compiled without LAPACK. Using precomputed PartialFractionApproximation"
         << std::endl;

   MFEM_ASSERT(alpha < 1., "alpha must be less than 1");
   MFEM_ASSERT(alpha > 0., "alpha must be greater than 0");

   if (alpha == 0.33)
   {
      coeffs = Array<double> ({2002.55,  99.7691,  29.0575,  12.9842,
                               6.90263,  3.96688,  2.36013,  1.42565,
                               0.867623, 0.529436, 0.317975, 0.0891797});
      poles = Array<double> ({-47928.,  -3451.45, -996.636, -388.58,
                              -168.228, -75.3162, -33.6235, -14.5403,
                              -5.84563, -1.9975, -0.434608,  0.});
   }
   else if (alpha == 0.99)
   {
      coeffs = Array<double>({0.0292386, 0.0143338, 0.0109015, 0.00976958,
                              0.00943417, 0.00948077, 0.00985799, 0.010889,
                              0.0138588, 0.0263289, 0.96953});
      poles = Array<double> ({-10085.1, -1652.6, -524.342, -199.521,
                              -80.2328, -32.3926, -12.7148, -4.63855,
                              -1.39884, -0.221076, 0.});
   }
   else
   {
      if (alpha != 0.5)
      {
         mfem::out << "Using default value of alpha = 0.5" << std::endl;
      }
      coeffs = Array<double>({209.629, 24.2714, 9.24812, 4.93138,
                              3.02653, 1.98265, 1.34293, 0.931714,
                              0.664382, 0.492972, 0.39114, 0.177527});
      poles = Array<double>({-26466.7, -2673.76, -800.03, -312.646,
                             -134.551, -59.8651, -26.6607, -11.5603,
                             -4.67241, -1.59503, -0.332738, 0.});
   }
   return;
#endif

   Vector x(npoints);
   Vector val(npoints);
   for (int i = 0; i<npoints; i++)
   {
      x(i) = (double)i+1.0;
      val(i) = pow(x(i),1.-alpha);
   }

   // Apply triple-A algorithm to f(x) = x^{1-a}
   Array<double> z, f;
   Vector w;
   RationalApproximation_AAA(val,x,z,f,w,tol,max_order);

   Vector vecz, vecf;
   vecz.SetDataAndSize(z.GetData(), z.Size());
   vecf.SetDataAndSize(f.GetData(), f.Size());

   // Compute poles and zeros for RA of f(x) = x^{1-a}
   double scale;
   Array<double> zeros;
   ComputePolesAndZeros(vecz, vecf, w, poles, zeros, scale);

   // Introduce one extra pole at x=0, thus, delivering a
   // RA for f(x) = x^{-a}
   poles.Append(0.0);

   // Compute partial fraction approximation of f(x) = x^{-a}
   PartialFractionExpansion(scale, poles, zeros, coeffs);
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2015 Jason Shipman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#pragma once

#include <CpperoMQ/Common.hpp>

#include <algorithm>

namespace CpperoMQ
{

class Socket
{
    friend class IncomingMessage;
    friend class OutgoingMessage;

public:
    Socket() = delete;
    virtual ~Socket();
    Socket(const Socket& other) = delete;
    Socket& operator=(Socket& other) = delete;

    auto bind(const char* address) -> void;
    auto unbind(const char* address) -> void;

    auto connect(const char* address) -> void;
    auto disconnect(const char* address) -> void;

    auto getBacklog() const                                 -> int;
    auto getHandshakeInterval() const                       -> int;
    auto getImmediate() const                               -> bool;
    auto getIoThreadAffinity() const                        -> uint64_t;
    auto getIPv6() const                                    -> bool;
    auto getLastEndpoint(size_t length, char* buffer) const -> void;
    auto getMaxReconnectInterval() const                    -> int;
    auto getMulticastRate() const                           -> int;
    auto getMulticastRecoveryInterval() const               -> int;
    auto getReconnectInterval() const                       -> int;

    auto setBacklog(const int backlog)                        -> void;
    auto setHandshakeInterval(const int milliseconds)         -> void;
    auto setImmediate(const bool immediate)                   -> void;
    auto setIoThreadAffinity(const uint64_t affinity)         -> void;
    auto setIPv6(const bool ipv6)                             -> void;
    auto setMaxReconnectInterval(const int milliseconds)      -> void;
    auto setMulticastRate(const int kbps)                     -> void;
    auto setMulticastRecoveryInterval(const int milliseconds) -> void;
    auto setReconnectInterval(const int milliseconds)         -> void;

    explicit operator void*();

protected:
    Socket(void* context, int type);
    Socket(Socket&& other);
    Socket& operator=(Socket&& other);

    template <typename T>
    auto getSocketOption(const int option) const -> T;
    auto getSocketOption( const int option
                        , void* value
                        , size_t* valueLength ) const -> void;

    template <typename T>
    auto setSocketOption(const int option, const T value) -> void;
    auto setSocketOption( const int option
                        , const void* value
                        , const size_t valueLength ) -> void;

private:
    void* mSocket;
};

inline
Socket::~Socket()
{
    if (mSocket != nullptr)
    {
        int result = zmq_close(mSocket);
        CPPEROMQ_ASSERT(result == 0);
        mSocket = 0 ;
    }
}

inline
auto Socket::bind(const char* address) -> void
{
    if (0 != zmq_bind(mSocket, address))
    {
        throw Error();
    }
}

inline
auto Socket::unbind(const char* address) -> void
{
    if (0 != zmq_unbind(mSocket, address))
    {
        throw Error();
    }
}

inline
auto Socket::connect(const char* address) -> void
{
    if (0 != zmq_connect(mSocket, address))
    {
        throw Error();
    }
}

inline
auto Socket::disconnect(const char* address) -> void
{
    if (0 != zmq_disconnect(mSocket, address))
    {
        throw Error();
    }
}

inline
Socket::Socket(void* context, int type)
    : mSocket(nullptr)
{
    CPPEROMQ_ASSERT(context != nullptr);

    mSocket = zmq_socket(context, type);
    if (mSocket == NULL)
    {
        throw Error();
    }
}

inline
Socket::Socket(Socket&& other)
    : mSocket(other.mSocket)
{
    other.mSocket = nullptr;
}

inline
Socket& Socket::operator=(Socket&& other)
{
    using std::swap;
    swap(mSocket, other.mSocket);
    return (*this);
}

inline
auto Socket::getBacklog() const -> int
{
    return (getSocketOption<int>(ZMQ_BACKLOG));
}

inline
auto Socket::getHandshakeInterval() const -> int
{
    return (getSocketOption<int>(ZMQ_HANDSHAKE_IVL));
}

inline
auto Socket::getImmediate() const -> bool
{
    return (getSocketOption<bool>(ZMQ_IMMEDIATE));
}

inline
auto Socket::getIoThreadAffinity() const -> uint64_t
{
    return (getSocketOption<uint64_t>(ZMQ_AFFINITY));
}

inline
auto Socket::getIPv6() const -> bool
{
    return (getSocketOption<bool>(ZMQ_IPV6));
}

inline
auto Socket::getLastEndpoint(size_t length, char* buffer) const -> void
{
    CPPEROMQ_ASSERT(buffer != nullptr);
    memset(buffer, 0, length);
    return (getSocketOption(ZMQ_LAST_ENDPOINT, buffer, &length));
}

inline
auto Socket::getMaxReconnectInterval() const -> int
{
    return (getSocketOption<int>(ZMQ_RECONNECT_IVL_MAX));
}

inline
auto Socket::getMulticastRate() const -> int
{
    return (getSocketOption<int>(ZMQ_RATE));
}

inline
auto Socket::getMulticastRecoveryInterval() const -> int
{
    return (getSocketOption<int>(ZMQ_RECOVERY_IVL));
}

inline
auto Socket::getReconnectInterval() const -> int
{
    return (getSocketOption<int>(ZMQ_RECONNECT_IVL));
}

inline
auto Socket::setBacklog(const int backlog) -> void
{
    setSocketOption(ZMQ_BACKLOG, backlog);
}

inline
auto Socket::setHandshakeInterval(const int milliseconds) -> void
{
    setSocketOption(ZMQ_HANDSHAKE_IVL, milliseconds);
}

inline
auto Socket::setImmediate(const bool immediate) -> void
{
    setSocketOption(ZMQ_IMMEDIATE, (immediate) ? 1 : 0);
}

inline
auto Socket::setIoThreadAffinity(const uint64_t affinity) -> void
{
    setSocketOption(ZMQ_AFFINITY, affinity);
}

inline
auto Socket::setIPv6(const bool ipv6) -> void
{
    setSocketOption(ZMQ_IPV6, (ipv6) ? 1 : 0);
}

inline
auto Socket::setMulticastRate(const int kbps) -> void
{
    setSocketOption(ZMQ_RATE, kbps);
}

inline
auto Socket::setMulticastRecoveryInterval(const int milliseconds) -> void
{
    setSocketOption(ZMQ_RECOVERY_IVL, milliseconds);
}

inline
auto Socket::setMaxReconnectInterval(const int milliseconds) -> void
{
    setSocketOption(ZMQ_RECONNECT_IVL_MAX, milliseconds);
}

inline
auto Socket::setReconnectInterval(const int milliseconds) -> void
{
    setSocketOption(ZMQ_RECONNECT_IVL, milliseconds);
}

inline
Socket::operator void*()
{
    return mSocket;
}

template <typename T>
inline
auto Socket::getSocketOption(const int option) const -> T
{
    T value;
    size_t valueLength = sizeof(T);
    getSocketOption(option, &value, &valueLength);
    return value;
}

inline
auto Socket::getSocketOption( const int option
                            , void* value
                            , size_t* valueLength ) const -> void
{
    if (0 != zmq_getsockopt(mSocket, option, value, valueLength))
    {
        throw Error();
    }
}

template <typename T>
inline
auto Socket::setSocketOption(const int option, const T value) -> void
{
    setSocketOption(option, &value, sizeof(value));
}

inline
auto Socket::setSocketOption( const int option
                            , const void* value
                            , const size_t valueLength ) -> void
{
    if (0 != zmq_setsockopt(mSocket, option, value, valueLength))
    {
        throw Error();
    }
}

}
<commit_msg>FIX: added 'cstring' include needed by 'memset' in Socket.hpp<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Jason Shipman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#pragma once

#include <CpperoMQ/Common.hpp>

#include <algorithm>
#include <cstring>

namespace CpperoMQ
{

class Socket
{
    friend class IncomingMessage;
    friend class OutgoingMessage;

public:
    Socket() = delete;
    virtual ~Socket();
    Socket(const Socket& other) = delete;
    Socket& operator=(Socket& other) = delete;

    auto bind(const char* address) -> void;
    auto unbind(const char* address) -> void;

    auto connect(const char* address) -> void;
    auto disconnect(const char* address) -> void;

    auto getBacklog() const                                 -> int;
    auto getHandshakeInterval() const                       -> int;
    auto getImmediate() const                               -> bool;
    auto getIoThreadAffinity() const                        -> uint64_t;
    auto getIPv6() const                                    -> bool;
    auto getLastEndpoint(size_t length, char* buffer) const -> void;
    auto getMaxReconnectInterval() const                    -> int;
    auto getMulticastRate() const                           -> int;
    auto getMulticastRecoveryInterval() const               -> int;
    auto getReconnectInterval() const                       -> int;

    auto setBacklog(const int backlog)                        -> void;
    auto setHandshakeInterval(const int milliseconds)         -> void;
    auto setImmediate(const bool immediate)                   -> void;
    auto setIoThreadAffinity(const uint64_t affinity)         -> void;
    auto setIPv6(const bool ipv6)                             -> void;
    auto setMaxReconnectInterval(const int milliseconds)      -> void;
    auto setMulticastRate(const int kbps)                     -> void;
    auto setMulticastRecoveryInterval(const int milliseconds) -> void;
    auto setReconnectInterval(const int milliseconds)         -> void;

    explicit operator void*();

protected:
    Socket(void* context, int type);
    Socket(Socket&& other);
    Socket& operator=(Socket&& other);

    template <typename T>
    auto getSocketOption(const int option) const -> T;
    auto getSocketOption( const int option
                        , void* value
                        , size_t* valueLength ) const -> void;

    template <typename T>
    auto setSocketOption(const int option, const T value) -> void;
    auto setSocketOption( const int option
                        , const void* value
                        , const size_t valueLength ) -> void;

private:
    void* mSocket;
};

inline
Socket::~Socket()
{
    if (mSocket != nullptr)
    {
        int result = zmq_close(mSocket);
        CPPEROMQ_ASSERT(result == 0);
        mSocket = 0 ;
    }
}

inline
auto Socket::bind(const char* address) -> void
{
    if (0 != zmq_bind(mSocket, address))
    {
        throw Error();
    }
}

inline
auto Socket::unbind(const char* address) -> void
{
    if (0 != zmq_unbind(mSocket, address))
    {
        throw Error();
    }
}

inline
auto Socket::connect(const char* address) -> void
{
    if (0 != zmq_connect(mSocket, address))
    {
        throw Error();
    }
}

inline
auto Socket::disconnect(const char* address) -> void
{
    if (0 != zmq_disconnect(mSocket, address))
    {
        throw Error();
    }
}

inline
Socket::Socket(void* context, int type)
    : mSocket(nullptr)
{
    CPPEROMQ_ASSERT(context != nullptr);

    mSocket = zmq_socket(context, type);
    if (mSocket == NULL)
    {
        throw Error();
    }
}

inline
Socket::Socket(Socket&& other)
    : mSocket(other.mSocket)
{
    other.mSocket = nullptr;
}

inline
Socket& Socket::operator=(Socket&& other)
{
    using std::swap;
    swap(mSocket, other.mSocket);
    return (*this);
}

inline
auto Socket::getBacklog() const -> int
{
    return (getSocketOption<int>(ZMQ_BACKLOG));
}

inline
auto Socket::getHandshakeInterval() const -> int
{
    return (getSocketOption<int>(ZMQ_HANDSHAKE_IVL));
}

inline
auto Socket::getImmediate() const -> bool
{
    return (getSocketOption<bool>(ZMQ_IMMEDIATE));
}

inline
auto Socket::getIoThreadAffinity() const -> uint64_t
{
    return (getSocketOption<uint64_t>(ZMQ_AFFINITY));
}

inline
auto Socket::getIPv6() const -> bool
{
    return (getSocketOption<bool>(ZMQ_IPV6));
}

inline
auto Socket::getLastEndpoint(size_t length, char* buffer) const -> void
{
    CPPEROMQ_ASSERT(buffer != nullptr);
    memset(buffer, 0, length);
    return (getSocketOption(ZMQ_LAST_ENDPOINT, buffer, &length));
}

inline
auto Socket::getMaxReconnectInterval() const -> int
{
    return (getSocketOption<int>(ZMQ_RECONNECT_IVL_MAX));
}

inline
auto Socket::getMulticastRate() const -> int
{
    return (getSocketOption<int>(ZMQ_RATE));
}

inline
auto Socket::getMulticastRecoveryInterval() const -> int
{
    return (getSocketOption<int>(ZMQ_RECOVERY_IVL));
}

inline
auto Socket::getReconnectInterval() const -> int
{
    return (getSocketOption<int>(ZMQ_RECONNECT_IVL));
}

inline
auto Socket::setBacklog(const int backlog) -> void
{
    setSocketOption(ZMQ_BACKLOG, backlog);
}

inline
auto Socket::setHandshakeInterval(const int milliseconds) -> void
{
    setSocketOption(ZMQ_HANDSHAKE_IVL, milliseconds);
}

inline
auto Socket::setImmediate(const bool immediate) -> void
{
    setSocketOption(ZMQ_IMMEDIATE, (immediate) ? 1 : 0);
}

inline
auto Socket::setIoThreadAffinity(const uint64_t affinity) -> void
{
    setSocketOption(ZMQ_AFFINITY, affinity);
}

inline
auto Socket::setIPv6(const bool ipv6) -> void
{
    setSocketOption(ZMQ_IPV6, (ipv6) ? 1 : 0);
}

inline
auto Socket::setMulticastRate(const int kbps) -> void
{
    setSocketOption(ZMQ_RATE, kbps);
}

inline
auto Socket::setMulticastRecoveryInterval(const int milliseconds) -> void
{
    setSocketOption(ZMQ_RECOVERY_IVL, milliseconds);
}

inline
auto Socket::setMaxReconnectInterval(const int milliseconds) -> void
{
    setSocketOption(ZMQ_RECONNECT_IVL_MAX, milliseconds);
}

inline
auto Socket::setReconnectInterval(const int milliseconds) -> void
{
    setSocketOption(ZMQ_RECONNECT_IVL, milliseconds);
}

inline
Socket::operator void*()
{
    return mSocket;
}

template <typename T>
inline
auto Socket::getSocketOption(const int option) const -> T
{
    T value;
    size_t valueLength = sizeof(T);
    getSocketOption(option, &value, &valueLength);
    return value;
}

inline
auto Socket::getSocketOption( const int option
                            , void* value
                            , size_t* valueLength ) const -> void
{
    if (0 != zmq_getsockopt(mSocket, option, value, valueLength))
    {
        throw Error();
    }
}

template <typename T>
inline
auto Socket::setSocketOption(const int option, const T value) -> void
{
    setSocketOption(option, &value, sizeof(value));
}

inline
auto Socket::setSocketOption( const int option
                            , const void* value
                            , const size_t valueLength ) -> void
{
    if (0 != zmq_setsockopt(mSocket, option, value, valueLength))
    {
        throw Error();
    }
}

}
<|endoftext|>


<commit_before>#ifndef ANIMATED_HPP_
#define ANIMATED_HPP_

#include <memory>
#include "./transition.hpp"

template <typename T>
class Animated
{
public:
    Animated(const Animated&) = delete;

    Animated(const T &value):
        m_value(value),
        m_transition(nullptr)
    {}

    ~Animated()
    {
        if (m_transition != nullptr) {
            delete m_transition;
            m_transition = nullptr;
        }
    }

    T getValue() const
    {
        return value;
    }

    void setTransition(Transition<T> *transition)
    {
        m_transition = transition;
    }

    void tick(sf::Int32 deltaTime)
    {
        if (m_transition != nullptr && !m_transition->isFinished()) {
            m_value = m_transition->nextState(deltaTime);
        }
    }

private:
    T m_value;
    std::unique_ptr<Transition<T>> m_transition;
};

#endif  // ANIMATED_HPP_
<commit_msg>More convenient names for Animated members (#3)<commit_after>#ifndef ANIMATED_HPP_
#define ANIMATED_HPP_

#include <memory>
#include "./transition.hpp"

template <typename T>
class Animated
{
public:
    Animated(const Animated&) = delete;

    Animated(const T &value):
        m_value(value),
        m_transition(nullptr)
    {}

    ~Animated()
    {
        if (m_transition != nullptr) {
            delete m_transition;
            m_transition = nullptr;
        }
    }

    T value() const
    {
        return value;
    }

    void animate(Transition<T> *transition)
    {
        m_transition = transition;
    }

    void tick(sf::Int32 deltaTime)
    {
        if (m_transition != nullptr && !m_transition->isFinished()) {
            m_value = m_transition->nextState(deltaTime);
        }
    }

private:
    T m_value;
    std::unique_ptr<Transition<T>> m_transition;
};

#endif  // ANIMATED_HPP_
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013
 * Alessio Sclocco <a.sclocco@vu.nl>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * 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 <string>
#include <vector>
#include <cmath>
#include <x86intrin.h>
#include <omp.h>
using std::string;
using std::vector;
using std::make_pair;
using std::pow;
using std::ceil;

#include <Observation.hpp>
using AstroData::Observation;

#ifndef DEDISPERSION_CPU_HPP
#define DEDISPERSION_CPU_HPP

namespace PulsarSearch {

// OpenMP + SIMD dedispersion algorithm
template< typename T > void dedispersion(const unsigned int nrSamplesPerChannel, Observation< T > & observation, const T  * const __restrict__ input, T * const __restrict__ output, unsigned int * const __restrict__ shifts);
template< typename T > void dedispersionAVX(const unsigned int nrSamplesPerChannel, Observation< T > & observation, const T  * const __restrict__ input, T * const __restrict__ output, const unsigned int * const __restrict__ shifts);
template< typename T > void dedispersionPhi(const unsigned int nrSamplesPerChannel, const unsigned int nrDMs, const unsigned int nrSamplesPerSecond, const unsigned int nrChannels, const unsigned int nrSamplesPerPaddedSecond, const T  * const __restrict__ input, T * const __restrict__ output, const unsigned int * const __restrict__ shifts);

// Implementation
template< typename T > void dedispersion(const unsigned int nrSamplesPerChannel, Observation< T > & observation, const T * const __restrict__ input, T * const __restrict__ output, unsigned int * const __restrict__ shifts) {
	#pragma omp parallel for
	for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm++ ) {
		#pragma omp parallel for
		for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample++ ) {
			T dedispersedSample = static_cast< T >(0);

			for ( unsigned int channel = 0; channel < observation.getNrChannels(); channel++ ) {
				unsigned int shift = shifts[(dm * observation.getNrChannels()) + channel];

				dedispersedSample += input[(channel * nrSamplesPerChannel) + (sample + shift)];
			}

			output[(dm * observation.getNrSamplesPerPaddedSecond()) + sample] = dedispersedSample;
		}
	}
}

template< typename T > void dedispersionAVX(const unsigned int nrSamplesPerChannel, Observation< T > & observation, const T * const __restrict__ input, T * const __restrict__ output, unsigned int * const __restrict__ shifts) {
	#pragma omp parallel for
	for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm++ ) {
		#pragma omp parallel for
		for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample += 8 ) {
			__m256 dedispersedSample = _mm256_setzero_ps();

			for ( unsigned int channel = 0; channel < observation.getNrChannels(); channel++ ) {
				unsigned int shift = shifts[(dm * observation.getNrChannels()) + channel];
				__m256 dispersedSample = _mm256_loadu_ps(&(input[(channel * nrSamplesPerChannel) + (sample + shift)]));

				dedispersedSample = _mm256_add_ps(dedispersedSample, dispersedSample);
			}

			_mm256_store_ps(&(output[(dm * observation.getNrSamplesPerPaddedSecond()) + sample]), dedispersedSample);
		}
	}
}

template< typename T > void dedispersionPhi(const unsigned int nrSamplesPerChannel, const unsigned int nrDMs, const unsigned int nrSamplesPerSecond, const unsigned int nrChannels, const unsigned int nrSamplesPerPaddedSecond, const T  * const __restrict__ input, T * const __restrict__ output, const unsigned int * const __restrict__ shifts) {
	#pragma offload target(mic) nocopy(input: alloc_if(0) free_if(0)) nocopy(output: alloc_if(0) free_if(0)) nocopy(shifts: alloc_if(0) free_if(0))
	{
		#pragma omp parallel for
		for ( unsigned int dm = 0; dm < nrDMs; dm++ ) {
			#pragma omp parallel for
			for ( unsigned int sample = 0; sample < nrSamplesPerSecond; sample += 16 ) {
				__m512 dedispersedSample = _mm512_setzero_ps();

				for ( unsigned int channel = 0; channel < nrChannels; channel++ ) {
					unsigned int shift = shifts[(dm * nrChannels) + channel];
					__m512 dispersedSample;

					dispersedSample = _mm512_loadunpacklo_ps(dispersedSample, &(input[(channel * nrSamplesPerChannel) + (sample + shift)]));
					dispersedSample = _mm512_loadunpackhi_ps(dispersedSample, &(input[(channel * nrSamplesPerChannel) + (sample + shift)]) + 16);
					dedispersedSample = _mm512_add_ps(dedispersedSample, dispersedSample);
				}

				_mm512_store_ps(&(output[(dm * nrSamplesPerPaddedSecond) + sample]), dedispersedSample);
			}
		}
	}
}

} // PulsarSearch

#endif // DEDISPERSION_CPU_HPP<commit_msg>No more offloading.<commit_after>/*
 * Copyright (C) 2013
 * Alessio Sclocco <a.sclocco@vu.nl>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * 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 <string>
#include <vector>
#include <cmath>
#include <x86intrin.h>
#include <omp.h>
using std::string;
using std::vector;
using std::make_pair;
using std::pow;
using std::ceil;

#include <Observation.hpp>
using AstroData::Observation;

#ifndef DEDISPERSION_CPU_HPP
#define DEDISPERSION_CPU_HPP

namespace PulsarSearch {

// OpenMP + SIMD dedispersion algorithm
template< typename T > void dedispersion(const unsigned int nrSamplesPerChannel, Observation< T > & observation, const T  * const __restrict__ input, T * const __restrict__ output, unsigned int * const __restrict__ shifts);
template< typename T > void dedispersionAVX(const unsigned int nrSamplesPerChannel, Observation< T > & observation, const T  * const __restrict__ input, T * const __restrict__ output, const unsigned int * const __restrict__ shifts);
template< typename T > void dedispersionPhi(const unsigned int nrSamplesPerChannel, const unsigned int nrDMs, const unsigned int nrSamplesPerSecond, const unsigned int nrChannels, const unsigned int nrSamplesPerPaddedSecond, const T  * const __restrict__ input, T * const __restrict__ output, const unsigned int * const __restrict__ shifts);

// Implementation
template< typename T > void dedispersion(const unsigned int nrSamplesPerChannel, Observation< T > & observation, const T * const __restrict__ input, T * const __restrict__ output, unsigned int * const __restrict__ shifts) {
	#pragma omp parallel for
	for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm++ ) {
		#pragma omp parallel for
		for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample++ ) {
			T dedispersedSample = static_cast< T >(0);

			for ( unsigned int channel = 0; channel < observation.getNrChannels(); channel++ ) {
				unsigned int shift = shifts[(dm * observation.getNrChannels()) + channel];

				dedispersedSample += input[(channel * nrSamplesPerChannel) + (sample + shift)];
			}

			output[(dm * observation.getNrSamplesPerPaddedSecond()) + sample] = dedispersedSample;
		}
	}
}

template< typename T > void dedispersionAVX(const unsigned int nrSamplesPerChannel, Observation< T > & observation, const T * const __restrict__ input, T * const __restrict__ output, unsigned int * const __restrict__ shifts) {
	#pragma omp parallel for schedule(static)
	for ( unsigned int dm = 0; dm < observation.getNrDMs(); dm++ ) {
		#pragma omp parallel for schedule(static)
		for ( unsigned int sample = 0; sample < observation.getNrSamplesPerSecond(); sample += 8 ) {
			__m256 dedispersedSample = _mm256_setzero_ps();

			for ( unsigned int channel = 0; channel < observation.getNrChannels(); channel++ ) {
				unsigned int shift = shifts[(dm * observation.getNrChannels()) + channel];
				__m256 dispersedSample = _mm256_loadu_ps(&(input[(channel * nrSamplesPerChannel) + (sample + shift)]));

				dedispersedSample = _mm256_add_ps(dedispersedSample, dispersedSample);
			}

			_mm256_store_ps(&(output[(dm * observation.getNrSamplesPerPaddedSecond()) + sample]), dedispersedSample);
		}
	}
}

template< typename T > void dedispersionPhi(const unsigned int nrSamplesPerChannel, const unsigned int nrDMs, const unsigned int nrSamplesPerSecond, const unsigned int nrChannels, const unsigned int nrSamplesPerPaddedSecond, const T  * const __restrict__ input, T * const __restrict__ output, const unsigned int * const __restrict__ shifts) {
	#pragma omp parallel for schedule(static)
	for ( unsigned int dm = 0; dm < nrDMs; dm++ ) {
		#pragma omp parallel for schedule(static)
		for ( unsigned int sample = 0; sample < nrSamplesPerSecond; sample += 16 ) {
			__m512 dedispersedSample = _mm512_setzero_ps();

			for ( unsigned int channel = 0; channel < nrChannels; channel++ ) {
				unsigned int shift = shifts[(dm * nrChannels) + channel];
				__m512 dispersedSample;

				dispersedSample = _mm512_loadunpacklo_ps(dispersedSample, &(input[(channel * nrSamplesPerChannel) + (sample + shift)]));
				dispersedSample = _mm512_loadunpackhi_ps(dispersedSample, &(input[(channel * nrSamplesPerChannel) + (sample + shift)]) + 16);
				dedispersedSample = _mm512_add_ps(dedispersedSample, dispersedSample);
			}

			_mm512_store_ps(&(output[(dm * nrSamplesPerPaddedSecond) + sample]), dedispersedSample);
		}
	}
}

} // PulsarSearch

#endif // DEDISPERSION_CPU_HPP<|endoftext|>


<commit_before>#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>
#include "SubmatrixCalculator.cpp"

#define BLANK_CHAR '-'

using namespace std;

string final_columns[2];
vector<string> final_rows[2];

const string ALPHABET = "ATGC";
string string_a, string_b;

int submatrix_dim;
int row_num;
int column_num;

void fill_edit_matrix(SubmatrixCalculator subm_calc)
{
    for (int i = 0; i < 2; i++){
        final_rows[i] = vector<string>(column_num+1, "");
    }

    string initial_string = SubmatrixCalculator::stepsToString(vector<int>(submatrix_dim+1, 1));
    for (int submatrix_j=1; submatrix_j<=column_num; submatrix_j++)
        final_rows[0][submatrix_j] = initial_string;

    for (int submatrix_i=1, alti = 1; submatrix_i<=row_num; submatrix_i++, alti = !alti) {
        final_columns[0] = initial_string;
        for (int submatrix_j=1, altj = 1; submatrix_j<=column_num; submatrix_j++, altj = !altj) {

            pair<string, string> final_steps = subm_calc.getFinalSteps(
                                    string_a.substr((submatrix_i-1)*submatrix_dim, submatrix_dim),
                                    string_b.substr((submatrix_j-1)*submatrix_dim, submatrix_dim),
                                    final_columns[!altj].substr(1),
                                    final_rows[!alti][submatrix_j].substr(1));

            final_columns[altj] = final_steps.first;
            final_rows[alti][submatrix_j] = final_steps.second;
            //final_columns[submatrix_i][submatrix_j] = final_steps.first;
            //final_rows[submatrix_i][submatrix_j] = final_steps.second;
        }
    }
}

int calc_edit_distance(SubmatrixCalculator subm_calc)
{
    int edit_distance = string_a.size();

    for (int submatrix_j=1; submatrix_j<=column_num; submatrix_j++) {
        edit_distance += subm_calc.sumSteps(final_rows[row_num % 2][submatrix_j].substr(1));
    }

    return edit_distance;
}

int main() {
    //read strings a and b
    string_a = "ATTACC";
    string_b = "ATTACG";
    // uzmi max od 2 stringa za racunat, jo bolje, zamijeni da je prvi max/min? uvijek?
    //submatrix_dim = ceil(log(string_a.size()) / log(3 * ALPHABET.size()) / 2);
    submatrix_dim = 2;

    cout << "Submatrix dimension: " << submatrix_dim << endl;
    cout << "String A size: " << string_a.size() << endl;
    cout << "String B size: " << string_b.size() << endl;

    // pad strings to fit dimension
    if (string_a.size() % submatrix_dim){
        int cnt = submatrix_dim - string_a.size() % submatrix_dim;
        while (cnt--){
            string_a += BLANK_CHAR;
        }
    }
    if (string_b.size() % submatrix_dim){
        int cnt = submatrix_dim - string_b.size() % submatrix_dim;
        while (cnt--){
            string_b += BLANK_CHAR;
        }
    }

    SubmatrixCalculator subm_calc(submatrix_dim, ALPHABET, BLANK_CHAR);
    subm_calc.calculate();

    row_num = string_a.size() / (submatrix_dim);
    column_num = string_b.size() / (submatrix_dim);
    cout << "Submatrices in edit table: " << row_num << "x" << column_num << endl;

    fill_edit_matrix(subm_calc);

    cout << "Edit distance: " << calc_edit_distance(subm_calc) << endl;

    return 0;
}
<commit_msg>Padding fix<commit_after>#include <cstdio>
#include <iostream>
#include <vector>
#include <cmath>
#include "SubmatrixCalculator.cpp"

#define BLANK_CHAR '-'

using namespace std;

string final_columns[2];
vector<string> final_rows[2];

const string ALPHABET = "ATGC";
string string_a, string_b;

int submatrix_dim;
int row_num;
int column_num;

int string_a_real_size;
int string_b_real_size;

void fill_edit_matrix(SubmatrixCalculator subm_calc)
{
    for (int i = 0; i < 2; i++){
        final_rows[i] = vector<string>(column_num+1, "");
    }

    string initial_string = SubmatrixCalculator::stepsToString(vector<int>(submatrix_dim+1, 1));
    for (int submatrix_j=1; submatrix_j<=column_num; submatrix_j++) {

        if ((submatrix_j*submatrix_dim-1) >= string_b_real_size) {
            vector<int> temp_vec (submatrix_dim+1, 0);
            for (int i=0; i<(string_b_real_size-((submatrix_j-1)*submatrix_dim-1)); i++)
                temp_vec[i] = 1;
            final_rows[0][submatrix_j] = SubmatrixCalculator::stepsToString(temp_vec);
        }
        else {
            final_rows[0][submatrix_j] = initial_string;
        }
    }

    for (int submatrix_i=1, alti = 1; submatrix_i<=row_num; submatrix_i++, alti = !alti) {

        if ((submatrix_i*submatrix_dim-1) >= string_a_real_size) {
            vector<int> temp_vec (submatrix_dim+1, 0);
            for (int i=0; i<(string_a_real_size-((submatrix_i-1)*submatrix_dim-1)); i++)
                temp_vec[i] = 1;
            final_columns[0] = SubmatrixCalculator::stepsToString(temp_vec);
        }
        else {
            final_columns[0] = initial_string;
        }

        for (int submatrix_j=1, altj = 1; submatrix_j<=column_num; submatrix_j++, altj = !altj) {

            pair<string, string> final_steps = subm_calc.getFinalSteps(
                                    string_a.substr((submatrix_i-1)*submatrix_dim, submatrix_dim),
                                    string_b.substr((submatrix_j-1)*submatrix_dim, submatrix_dim),
                                    final_columns[!altj].substr(1),
                                    final_rows[!alti][submatrix_j].substr(1));

            final_columns[altj] = final_steps.first;
            final_rows[alti][submatrix_j] = final_steps.second;
            //final_columns[submatrix_i][submatrix_j] = final_steps.first;
            //final_rows[submatrix_i][submatrix_j] = final_steps.second;
        }
    }
}

int calc_edit_distance(SubmatrixCalculator subm_calc)
{
    int edit_distance = string_a_real_size;

    for (int submatrix_j=1; submatrix_j<=column_num; submatrix_j++) {
        edit_distance += subm_calc.sumSteps(final_rows[row_num % 2][submatrix_j].substr(1));
    }
    return edit_distance;
}

int main() {
    //read strings a and b
    string_a = "AG";
    string_b = "GG";
    // uzmi max od 2 stringa za racunat, jo bolje, zamijeni da je prvi max/min? uvijek?
    //submatrix_dim = ceil(log(string_a.size()) / log(3 * ALPHABET.size()) / 2);
    submatrix_dim = 2;
    string_a_real_size = string_a.size();
    string_b_real_size = string_b.size();

    cout << "Submatrix dimension: " << submatrix_dim << endl;
    cout << "String A size: " << string_a.size() << endl;
    cout << "String B size: " << string_b.size() << endl;

    // pad strings to fit dimension
    if (string_a.size() % submatrix_dim){
        int cnt = submatrix_dim - string_a.size() % submatrix_dim;
        while (cnt--){
            string_a += BLANK_CHAR;
        }
    }
    if (string_b.size() % submatrix_dim){
        int cnt = submatrix_dim - string_b.size() % submatrix_dim;
        while (cnt--){
            string_b += BLANK_CHAR;
        }
    }

    SubmatrixCalculator subm_calc(submatrix_dim, ALPHABET, BLANK_CHAR);
    subm_calc.calculate();

    row_num = string_a.size() / (submatrix_dim);
    column_num = string_b.size() / (submatrix_dim);
    cout << "Submatrices in edit table: " << row_num << "x" << column_num << endl;

    fill_edit_matrix(subm_calc);

    cout << "Edit distance: " << calc_edit_distance(subm_calc) << endl;

    return 0;
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2010, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#ifndef IECORE_LRUCACHE_INL
#define IECORE_LRUCACHE_INL

#include <cassert>

#include "tbb/tbb_thread.h"

#include "boost/format.hpp"

#include "IECore/Exception.h"

namespace IECore
{

template<typename Key, typename Ptr>
LRUCache<Key, Ptr>::CacheEntry::CacheEntry()
	:	cost( 0 ), status( New ), data( 0 )
{
}

template<typename Key, typename Ptr>
LRUCache<Key, Ptr>::LRUCache( GetterFunction getter )
	:	m_getter( getter ), m_maxCost( 500 ), m_currentCost( 0 )
{
}

template<typename Key, typename Ptr>
LRUCache<Key, Ptr>::LRUCache( GetterFunction getter, Cost maxCost )
	:	m_getter( getter ), m_maxCost( maxCost ), m_currentCost( 0 )
{
}

template<typename Key, typename Ptr>
LRUCache<Key, Ptr>::~LRUCache()
{
}

template<typename Key, typename Ptr>
void LRUCache<Key, Ptr>::clear()
{
	Mutex::scoped_lock lock( m_mutex );

	m_currentCost = Cost(0);
	m_list.clear();
	m_cache.clear();
}

template<typename Key, typename Ptr>
void LRUCache<Key, Ptr>::setMaxCost( Cost maxCost )
{
	Mutex::scoped_lock lock( m_mutex );

	assert( maxCost >= Cost(0) );
	m_maxCost = maxCost;

	limitCost( m_maxCost );
}

template<typename Key, typename Ptr>
typename LRUCache<Key, Ptr>::Cost LRUCache<Key, Ptr>::getMaxCost() const
{
	Mutex::scoped_lock lock( m_mutex );
	return m_maxCost;
}

template<typename Key, typename Ptr>
typename LRUCache<Key, Ptr>::Cost LRUCache<Key, Ptr>::currentCost() const
{
	Mutex::scoped_lock lock( m_mutex );
	return m_currentCost;
}

template<typename Key, typename Ptr>
bool LRUCache<Key, Ptr>::cached( const Key &key ) const
{
	Mutex::scoped_lock lock( m_mutex );
	ConstCacheIterator it = m_cache.find( key );
	return ( it != m_cache.end() && it->second.status==Cached );
}

template<typename Key, typename Ptr>
Ptr LRUCache<Key, Ptr>::get( const Key& key )
{
	Mutex::scoped_lock lock( m_mutex );

	CacheEntry &cacheEntry = m_cache[key]; // creates an entry if one doesn't exist yet

	if( cacheEntry.status==Caching )
	{
		// another thread is doing the work. we need to wait
		// until it is done.
		lock.release();
			while( cacheEntry.status==Caching )
			{
				tbb::this_tbb_thread::yield();
			}
		lock.acquire( m_mutex );
	}

	if( cacheEntry.status==New || cacheEntry.status==Erased || cacheEntry.status==TooCostly )
	{
		assert( cacheEntry.data==0 );
		Ptr data = 0;
		Cost cost = 0;
		try
		{
			cacheEntry.status = Caching;
			lock.release(); // allows other threads to do stuff while we're computing the value
				data = m_getter( key, cost );
			lock.acquire( m_mutex );
		}
		catch( const std::exception &e )
		{
			std::cerr << "LRUCACHE CAUGHT " << e.what() << std::endl;
			lock.acquire( m_mutex );
			CacheEntry &cacheEntry = m_cache[key]; // in case some other thread erased our entry while we had released the lock
			cacheEntry.status = Failed;
			throw;
		}
		assert( data );
		assert( cacheEntry.status != Cached ); // this would indicate that another thread somehow
		assert( cacheEntry.status != Failed ); // loaded the same thing as us, which is not the intention.
		set( key, data, cost );
		return data;
	}
	else if( cacheEntry.status==Cached )
	{
		// move the entry to the front of the list
		m_list.erase( cacheEntry.listIterator );
		m_list.push_front( key );
		cacheEntry.listIterator = m_list.begin();
		return cacheEntry.data;
	}
	else
	{
		assert( cacheEntry.status==Failed );
		throw Exception( boost::str( boost::format( "Previous attempt to get \"%1%\" failed." ) % key ) );
	}
}

template<typename Key, typename Ptr>
bool LRUCache<Key, Ptr>::set( const Key &key, const Ptr &data, Cost cost )
{
	Mutex::scoped_lock lock( m_mutex );

	CacheEntry &cacheEntry = m_cache[key]; // creates an entry if one doesn't exist yet

	if( cacheEntry.status==Cached )
	{
		m_currentCost -= cacheEntry.cost;
		cacheEntry.data = 0;
		m_list.erase( cacheEntry.listIterator );
	}

	if( cost > m_maxCost )
	{
		cacheEntry.status = TooCostly;
		return false;
	}

	limitCost( m_maxCost - cost );

	cacheEntry.data = data;
	cacheEntry.cost = cost;
	cacheEntry.status = Cached;
	m_list.push_front( key );
	cacheEntry.listIterator = m_list.begin();

	m_currentCost += cost;

	return true;
}

template<typename Key, typename Ptr>
void LRUCache<Key, Ptr>::limitCost( Cost cost )
{
	Mutex::scoped_lock lock( m_mutex );

	assert( cost >= Cost(0) );

	while( m_currentCost > cost && m_list.size() )
	{
		bool erased = erase( m_list.back() );
		assert( erased ); (void)erased;
	}

	assert( m_currentCost <= cost );
}

template<typename Key, typename Ptr>
bool LRUCache<Key, Ptr>::erase( const Key &key )
{
	Mutex::scoped_lock lock( m_mutex );

	typename Cache::iterator it = m_cache.find( key );

	if( it == m_cache.end() )
	{
		return false;
	}

	m_currentCost -= it->second.cost;
	m_list.erase( it->second.listIterator );
	it->second.data = 0;
	it->second.status = Erased;

	return true;
}

} // namespace IECore

#endif // IECORE_LRUCACHE_INL
<commit_msg>Removing accidentally committed debug code.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2007-2010, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#ifndef IECORE_LRUCACHE_INL
#define IECORE_LRUCACHE_INL

#include <cassert>

#include "tbb/tbb_thread.h"

#include "boost/format.hpp"

#include "IECore/Exception.h"

namespace IECore
{

template<typename Key, typename Ptr>
LRUCache<Key, Ptr>::CacheEntry::CacheEntry()
	:	cost( 0 ), status( New ), data( 0 )
{
}

template<typename Key, typename Ptr>
LRUCache<Key, Ptr>::LRUCache( GetterFunction getter )
	:	m_getter( getter ), m_maxCost( 500 ), m_currentCost( 0 )
{
}

template<typename Key, typename Ptr>
LRUCache<Key, Ptr>::LRUCache( GetterFunction getter, Cost maxCost )
	:	m_getter( getter ), m_maxCost( maxCost ), m_currentCost( 0 )
{
}

template<typename Key, typename Ptr>
LRUCache<Key, Ptr>::~LRUCache()
{
}

template<typename Key, typename Ptr>
void LRUCache<Key, Ptr>::clear()
{
	Mutex::scoped_lock lock( m_mutex );

	m_currentCost = Cost(0);
	m_list.clear();
	m_cache.clear();
}

template<typename Key, typename Ptr>
void LRUCache<Key, Ptr>::setMaxCost( Cost maxCost )
{
	Mutex::scoped_lock lock( m_mutex );

	assert( maxCost >= Cost(0) );
	m_maxCost = maxCost;

	limitCost( m_maxCost );
}

template<typename Key, typename Ptr>
typename LRUCache<Key, Ptr>::Cost LRUCache<Key, Ptr>::getMaxCost() const
{
	Mutex::scoped_lock lock( m_mutex );
	return m_maxCost;
}

template<typename Key, typename Ptr>
typename LRUCache<Key, Ptr>::Cost LRUCache<Key, Ptr>::currentCost() const
{
	Mutex::scoped_lock lock( m_mutex );
	return m_currentCost;
}

template<typename Key, typename Ptr>
bool LRUCache<Key, Ptr>::cached( const Key &key ) const
{
	Mutex::scoped_lock lock( m_mutex );
	ConstCacheIterator it = m_cache.find( key );
	return ( it != m_cache.end() && it->second.status==Cached );
}

template<typename Key, typename Ptr>
Ptr LRUCache<Key, Ptr>::get( const Key& key )
{
	Mutex::scoped_lock lock( m_mutex );

	CacheEntry &cacheEntry = m_cache[key]; // creates an entry if one doesn't exist yet

	if( cacheEntry.status==Caching )
	{
		// another thread is doing the work. we need to wait
		// until it is done.
		lock.release();
			while( cacheEntry.status==Caching )
			{
				tbb::this_tbb_thread::yield();
			}
		lock.acquire( m_mutex );
	}

	if( cacheEntry.status==New || cacheEntry.status==Erased || cacheEntry.status==TooCostly )
	{
		assert( cacheEntry.data==0 );
		Ptr data = 0;
		Cost cost = 0;
		try
		{
			cacheEntry.status = Caching;
			lock.release(); // allows other threads to do stuff while we're computing the value
				data = m_getter( key, cost );
			lock.acquire( m_mutex );
		}
		catch( const std::exception &e )
		{
			lock.acquire( m_mutex );
			CacheEntry &cacheEntry = m_cache[key]; // in case some other thread erased our entry while we had released the lock
			cacheEntry.status = Failed;
			throw;
		}
		assert( data );
		assert( cacheEntry.status != Cached ); // this would indicate that another thread somehow
		assert( cacheEntry.status != Failed ); // loaded the same thing as us, which is not the intention.
		set( key, data, cost );
		return data;
	}
	else if( cacheEntry.status==Cached )
	{
		// move the entry to the front of the list
		m_list.erase( cacheEntry.listIterator );
		m_list.push_front( key );
		cacheEntry.listIterator = m_list.begin();
		return cacheEntry.data;
	}
	else
	{
		assert( cacheEntry.status==Failed );
		throw Exception( boost::str( boost::format( "Previous attempt to get \"%1%\" failed." ) % key ) );
	}
}

template<typename Key, typename Ptr>
bool LRUCache<Key, Ptr>::set( const Key &key, const Ptr &data, Cost cost )
{
	Mutex::scoped_lock lock( m_mutex );

	CacheEntry &cacheEntry = m_cache[key]; // creates an entry if one doesn't exist yet

	if( cacheEntry.status==Cached )
	{
		m_currentCost -= cacheEntry.cost;
		cacheEntry.data = 0;
		m_list.erase( cacheEntry.listIterator );
	}

	if( cost > m_maxCost )
	{
		cacheEntry.status = TooCostly;
		return false;
	}

	limitCost( m_maxCost - cost );

	cacheEntry.data = data;
	cacheEntry.cost = cost;
	cacheEntry.status = Cached;
	m_list.push_front( key );
	cacheEntry.listIterator = m_list.begin();

	m_currentCost += cost;

	return true;
}

template<typename Key, typename Ptr>
void LRUCache<Key, Ptr>::limitCost( Cost cost )
{
	Mutex::scoped_lock lock( m_mutex );

	assert( cost >= Cost(0) );

	while( m_currentCost > cost && m_list.size() )
	{
		bool erased = erase( m_list.back() );
		assert( erased ); (void)erased;
	}

	assert( m_currentCost <= cost );
}

template<typename Key, typename Ptr>
bool LRUCache<Key, Ptr>::erase( const Key &key )
{
	Mutex::scoped_lock lock( m_mutex );

	typename Cache::iterator it = m_cache.find( key );

	if( it == m_cache.end() )
	{
		return false;
	}

	m_currentCost -= it->second.cost;
	m_list.erase( it->second.listIterator );
	it->second.data = 0;
	it->second.status = Erased;

	return true;
}

} // namespace IECore

#endif // IECORE_LRUCACHE_INL
<|endoftext|>


<commit_before>#ifndef OPTIMIZER_HPP
#define OPTIMIZER_HPP

#include <ace-c/AstVisitor.hpp>
#include <ace-c/Module.hpp>
#include <ace-c/ast/AstExpression.hpp>

#include <memory>

class Optimizer : public AstVisitor {
public:
    /** Attemps to reduce a variable that is const literal to the actual value. */
    static void OptimizeExpr(std::shared_ptr<AstExpression> &expr,
        AstVisitor *visitor, Module *mod);

public:
    Optimizer(AstIterator *ast_iterator, CompilationUnit *compilation_unit);
    Optimizer(const Optimizer &other);

    void Optimize(bool expect_module_decl = true);

private:
    void OptimizeInner();
};

#endif
<commit_msg>Delete optimizer.hpp<commit_after><|endoftext|>