<commit_before>//===------------------------- SILValueProjection.cpp ---------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-value-projection"
#include "swift/SIL/SILValueProjection.h"
#include "llvm/Support/Debug.h"

using namespace swift;

//===----------------------------------------------------------------------===//
//                              Utility Functions
//===----------------------------------------------------------------------===//

static inline void removeLSLocations(LSLocationValueMap &Values,
                                     LSLocationList &FirstLevel) {
  for (auto &X : FirstLevel)
    Values.erase(X);
}

//===----------------------------------------------------------------------===//
//                              SILValue Projection
//===----------------------------------------------------------------------===//

void SILValueProjection::print() const {
  llvm::outs() << Base;
  llvm::outs() << Path.getValue();
}

SILValue SILValueProjection::createExtract(SILValue Base,
                                           Optional<ProjectionPath> &Path,
                                           SILInstruction *Inst,
                                           bool IsValExt) {
  // If we found a projection path, but there are no projections, then the two
  // loads must be the same, return PrevLI.
  if (!Path || Path->empty())
    return Base;

  // Ok, at this point we know that we can construct our aggregate projections
  // from our list of address projections.
  SILValue LastExtract = Base;
  SILBuilder Builder(Inst);

  // We use an auto-generated SILLocation for now.
  // TODO: make the sil location more precise.
  SILLocation Loc = RegularLocation::getAutoGeneratedLocation();

  // Construct the path!
  for (auto PI = Path->rbegin(), PE = Path->rend(); PI != PE; ++PI) {
    if (IsValExt) {
      LastExtract =
          PI->createValueProjection(Builder, Loc, LastExtract).get();
      continue;
    }
    LastExtract =
        PI->createAddrProjection(Builder, Loc, LastExtract).get();
  }

  // Return the last extract we created.
  return LastExtract;
}

//===----------------------------------------------------------------------===//
//                              Load Store Value
//===----------------------------------------------------------------------===//

void LSValue::expand(SILValue Base, SILModule *M, LSValueList &Vals,
                     TypeExpansionAnalysis *TE) {
  // To expand a LSValue to its indivisible parts, we first get the
  // address projection paths from the accessed type to each indivisible field,
  // i.e. leaf nodes, then we append these projection paths to the Base.
  for (const auto &P :
       TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TELeaf)) {
    Vals.push_back(LSValue(Base, P.getValue()));
  }
}

SILValue LSValue::reduce(LSLocation &Base, SILModule *M,
                         LSLocationValueMap &Values,
                         SILInstruction *InsertPt,
                         TypeExpansionAnalysis *TE) {
  // Walk bottom up the projection tree, try to reason about how to construct
  // a single SILValue out of all the available values for all the memory
  // locations.
  //
  // First, get a list of all the leaf nodes and intermediate nodes for the
  // Base memory location.
  LSLocationList ALocs;
  ProjectionPath &BasePath = Base.getPath().getValue();
  for (const auto &P :
       TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TENode)) {
    ALocs.push_back(LSLocation(Base.getBase(), P.getValue(), BasePath));
  }

  // Second, go from leaf nodes to their parents. This guarantees that at the
  // point the parent is processed, its children have been processed already.
  for (auto I = ALocs.rbegin(), E = ALocs.rend(); I != E; ++I) {
    // This is a leaf node, we have a value for it.
    //
    // Reached the end of the projection tree, this is a leaf node.
    LSLocationList FirstLevel;
    I->getFirstLevelLSLocations(FirstLevel, M);
    if (FirstLevel.empty())
      continue;

    // If this is a class reference type, we have reached end of the type tree.
    if (I->getType().getClassOrBoundGenericClass())
      continue;

    // This is NOT a leaf node, we need to construct a value for it.

    // There is only 1 children node and its value's projection path is not
    // empty, keep stripping it.
    auto Iter = FirstLevel.begin();
    LSValue &FirstVal = Values[*Iter];
    if (FirstLevel.size() == 1 && !FirstVal.hasEmptyProjectionPath()) {
      Values[*I] = FirstVal.stripLastLevelProjection();
      // We have a value for the parent, remove all the values for children.
      removeLSLocations(Values, FirstLevel);
      continue;
    }

    // If there are more than 1 children and all the children nodes have
    // LSValues with the same base and non-empty projection path. we can get
    // away by not extracting value for every single field.
    //
    // Simply create a new node with all the aggregated base value, i.e.
    // stripping off the last level projection.
    bool HasIdenticalValueBase = true;
    SILValue FirstBase = FirstVal.getBase();
    Iter = std::next(Iter);
    for (auto EndIter = FirstLevel.end(); Iter != EndIter; ++Iter) {
      LSValue &V = Values[*Iter];
      HasIdenticalValueBase &= (FirstBase == V.getBase());
    }

    if (FirstLevel.size() > 1 && HasIdenticalValueBase &&
        !FirstVal.hasEmptyProjectionPath()) {
      Values[*I] = FirstVal.stripLastLevelProjection();
      // We have a value for the parent, remove all the values for children.
      removeLSLocations(Values, FirstLevel);
      continue;
    }

    // In 3 cases do we need aggregation.
    //
    // 1. If there is only 1 child and we cannot strip off any projections,
    // that means we need to create an aggregation.
    //
    // 2. There are multiple children and they have the same base, but empty
    // projection paths.
    //
    // 3. Children have values from different bases, We need to create
    // extractions and aggregation in this case.
    //
    llvm::SmallVector<SILValue, 8> Vals;
    for (auto &X : FirstLevel) {
      Vals.push_back(Values[X].materialize(InsertPt));
    }
    SILBuilder Builder(InsertPt);

    // We use an auto-generated SILLocation for now.
    // TODO: make the sil location more precise.
    NullablePtr<swift::SILInstruction> AI =
        Projection::createAggFromFirstLevelProjections(
            Builder, RegularLocation::getAutoGeneratedLocation(), I->getType(),
            Vals);
    // This is the Value for the current node.
    ProjectionPath P;
    Values[*I] = LSValue(SILValue(AI.get()), P);
    removeLSLocations(Values, FirstLevel);

    // Keep iterating until we have reach the top-most level of the projection
    // tree.
    // i.e. the memory location represented by the Base.
  }

  assert(Values.size() == 1 && "Should have a single location this point");

  // Finally materialize and return the forwarding SILValue.
  return Values.begin()->second.materialize(InsertPt);
}

void LSValue::enumerateLSValue(SILModule *M, SILValue Val,
                               std::vector<LSValue> &Vault,
                               LSValueIndexMap &ValToBit,
                               TypeExpansionAnalysis *TE) {
  // Expand the given Mem into individual fields and add them to the
  // locationvault.
  LSValueList Vals;
  LSValue::expand(Val, M, Vals, TE);
  for (auto &Val : Vals) {
    ValToBit[Val] = Vault.size();
    Vault.push_back(Val);
  }
}

void LSValue::enumerateLSValues(SILFunction &F, std::vector<LSValue> &Vault,
                                LSValueIndexMap &ValToBit,
                                TypeExpansionAnalysis *TE) {
  // Enumerate all LSValues created or used by the loads or stores.
  //
  // TODO: process more instructions as we process more instructions in
  // processInstruction.
  //
  SILValue Op;
  for (auto &B : F) {
    for (auto &I : B) {
      if (auto *LI = dyn_cast<LoadInst>(&I)) {
        enumerateLSValue(&I.getModule(), SILValue(LI), Vault, ValToBit, TE);
      } else if (auto *SI = dyn_cast<StoreInst>(&I)) {
        enumerateLSValue(&I.getModule(), SI->getSrc(), Vault, ValToBit, TE);
      }
    }
  }

  // Lastly, push in the covering value LSValue.
  ValToBit[LSValue(true)] = Vault.size();
  Vault.push_back(LSValue(true));
}

//===----------------------------------------------------------------------===//
//                                  Memory Location
//===----------------------------------------------------------------------===//

void LSLocation::initialize(SILValue Dest) {
  Base = getUnderlyingObject(Dest);
  Path = ProjectionPath::getAddrProjectionPath(Base, Dest);
}

bool LSLocation::isMustAliasLSLocation(const LSLocation &RHS,
                                       AliasAnalysis *AA) {
  // If the bases are not must-alias, the locations may not alias.
  if (!AA->isMustAlias(Base, RHS.getBase()))
    return false;
  // If projection paths are different, then the locations cannot alias.
  if (!hasIdenticalProjectionPath(RHS))
    return false;
  return true;
}

bool LSLocation::isMayAliasLSLocation(const LSLocation &RHS,
                                      AliasAnalysis *AA) {
  // If the bases do not alias, then the locations cannot alias.
  if (AA->isNoAlias(Base, RHS.getBase()))
    return false;
  // If one projection path is a prefix of another, then the locations
  // could alias.
  if (hasNonEmptySymmetricPathDifference(RHS))
    return false;
  return true;
}

bool LSLocation::isNonEscapingLocalLSLocation(SILFunction *Fn,
                                              EscapeAnalysis *EA) {
  auto *ConGraph = EA->getConnectionGraph(Fn);
  // An alloc_stack is definitely dead at the end of the function.
  if (isa<AllocStackInst>(Base))
    return true;
  // For other allocations we ask escape analysis.
  if (isa<AllocationInst>(Base)) {
    auto *Node = ConGraph->getNodeOrNull(Base, EA);
    if (Node && !Node->escapes()) {
      return true;
    }
  }
  return false;
}

void LSLocation::getFirstLevelLSLocations(LSLocationList &Locs,
                                          SILModule *Mod) {
  SILType Ty = getType();
  llvm::SmallVector<Projection, 8> Out;
  Projection::getFirstLevelAddrProjections(Ty, *Mod, Out);
  for (auto &X : Out) {
    ProjectionPath P;
    P.append(X);
    P.append(Path.getValue());
    Locs.push_back(LSLocation(Base, P));
  }
}

void LSLocation::expand(LSLocation &Base, SILModule *M, LSLocationList &Locs,
                        TypeExpansionAnalysis *TE) {
  // To expand a memory location to its indivisible parts, we first get the
  // address projection paths from the accessed type to each indivisible field,
  // i.e. leaf nodes, then we append these projection paths to the Base.
  //
  // Construct the LSLocation by appending the projection path from the
  // accessed node to the leaf nodes.
  ProjectionPath &BasePath = Base.getPath().getValue();
  for (const auto &P :
       TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TELeaf)) {
    Locs.push_back(LSLocation(Base.getBase(), P.getValue(), BasePath));
  }
}

void LSLocation::reduce(LSLocation &Base, SILModule *M, LSLocationSet &Locs,
                        TypeExpansionAnalysis *TE) {
  // First, construct the LSLocation by appending the projection path from the
  // accessed node to the leaf nodes.
  LSLocationList Nodes;
  ProjectionPath &BasePath = Base.getPath().getValue();
  for (const auto &P :
       TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TENode)) {
    Nodes.push_back(LSLocation(Base.getBase(), P.getValue(), BasePath));
  }

  // Second, go from leaf nodes to their parents. This guarantees that at the
  // point the parent is processed, its children have been processed already.
  for (auto I = Nodes.rbegin(), E = Nodes.rend(); I != E; ++I) {
    LSLocationList FirstLevel;
    I->getFirstLevelLSLocations(FirstLevel, M);
    // Reached the end of the projection tree, this is a leaf node.
    if (FirstLevel.empty())
      continue;

    // If this is a class reference type, we have reached end of the type tree.
    if (I->getType().getClassOrBoundGenericClass())
      continue;

    // This is NOT a leaf node, check whether all its first level children are
    // alive.
    bool Alive = true;
    for (auto &X : FirstLevel) {
      Alive &= Locs.find(X) != Locs.end();
    }

    // All first level locations are alive, create the new aggregated location.
    if (Alive) {
      for (auto &X : FirstLevel)
        Locs.erase(X);
      Locs.insert(*I);
    }
  }
}

void LSLocation::enumerateLSLocation(SILModule *M, SILValue Mem,
                                     std::vector<LSLocation> &LV,
                                     LSLocationIndexMap &BM,
                                     TypeExpansionAnalysis *TE) {
  // Construct a Location to represent the memory written by this instruction.
  LSLocation L(Mem);

  // If we cant figure out the Base or Projection Path for the memory location,
  // simply ignore it for now.
  if (!L.isValid())
    return;

  // Expand the given Mem into individual fields and add them to the
  // locationvault.
  LSLocationList Locs;
  LSLocation::expand(L, M, Locs, TE);
  for (auto &Loc : Locs) {
    BM[Loc] = LV.size();
    LV.push_back(Loc);
  }
}

void LSLocation::enumerateLSLocations(SILFunction &F,
                                      std::vector<LSLocation> &LV,
                                      LSLocationIndexMap &BM,
                                      TypeExpansionAnalysis *TE) {
  // Enumerate all locations accessed by the loads or stores.
  //
  // TODO: process more instructions as we process more instructions in
  // processInstruction.
  //
  SILValue Op;
  for (auto &B : F) {
    for (auto &I : B) {
      if (auto *LI = dyn_cast<LoadInst>(&I)) {
        enumerateLSLocation(&I.getModule(), LI->getOperand(), LV, BM, TE);
      } else if (auto *SI = dyn_cast<StoreInst>(&I)) {
        enumerateLSLocation(&I.getModule(), SI->getDest(), LV, BM, TE);
      }
    }
  }
}
<commit_msg>Only compute ConnectionGraph when needed. small compilation time improvement.<commit_after>//===------------------------- SILValueProjection.cpp ---------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-value-projection"
#include "swift/SIL/SILValueProjection.h"
#include "llvm/Support/Debug.h"

using namespace swift;

//===----------------------------------------------------------------------===//
//                              Utility Functions
//===----------------------------------------------------------------------===//

static inline void removeLSLocations(LSLocationValueMap &Values,
                                     LSLocationList &FirstLevel) {
  for (auto &X : FirstLevel)
    Values.erase(X);
}

//===----------------------------------------------------------------------===//
//                              SILValue Projection
//===----------------------------------------------------------------------===//

void SILValueProjection::print() const {
  llvm::outs() << Base;
  llvm::outs() << Path.getValue();
}

SILValue SILValueProjection::createExtract(SILValue Base,
                                           Optional<ProjectionPath> &Path,
                                           SILInstruction *Inst,
                                           bool IsValExt) {
  // If we found a projection path, but there are no projections, then the two
  // loads must be the same, return PrevLI.
  if (!Path || Path->empty())
    return Base;

  // Ok, at this point we know that we can construct our aggregate projections
  // from our list of address projections.
  SILValue LastExtract = Base;
  SILBuilder Builder(Inst);

  // We use an auto-generated SILLocation for now.
  // TODO: make the sil location more precise.
  SILLocation Loc = RegularLocation::getAutoGeneratedLocation();

  // Construct the path!
  for (auto PI = Path->rbegin(), PE = Path->rend(); PI != PE; ++PI) {
    if (IsValExt) {
      LastExtract =
          PI->createValueProjection(Builder, Loc, LastExtract).get();
      continue;
    }
    LastExtract =
        PI->createAddrProjection(Builder, Loc, LastExtract).get();
  }

  // Return the last extract we created.
  return LastExtract;
}

//===----------------------------------------------------------------------===//
//                              Load Store Value
//===----------------------------------------------------------------------===//

void LSValue::expand(SILValue Base, SILModule *M, LSValueList &Vals,
                     TypeExpansionAnalysis *TE) {
  // To expand a LSValue to its indivisible parts, we first get the
  // address projection paths from the accessed type to each indivisible field,
  // i.e. leaf nodes, then we append these projection paths to the Base.
  for (const auto &P :
       TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TELeaf)) {
    Vals.push_back(LSValue(Base, P.getValue()));
  }
}

SILValue LSValue::reduce(LSLocation &Base, SILModule *M,
                         LSLocationValueMap &Values,
                         SILInstruction *InsertPt,
                         TypeExpansionAnalysis *TE) {
  // Walk bottom up the projection tree, try to reason about how to construct
  // a single SILValue out of all the available values for all the memory
  // locations.
  //
  // First, get a list of all the leaf nodes and intermediate nodes for the
  // Base memory location.
  LSLocationList ALocs;
  ProjectionPath &BasePath = Base.getPath().getValue();
  for (const auto &P :
       TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TENode)) {
    ALocs.push_back(LSLocation(Base.getBase(), P.getValue(), BasePath));
  }

  // Second, go from leaf nodes to their parents. This guarantees that at the
  // point the parent is processed, its children have been processed already.
  for (auto I = ALocs.rbegin(), E = ALocs.rend(); I != E; ++I) {
    // This is a leaf node, we have a value for it.
    //
    // Reached the end of the projection tree, this is a leaf node.
    LSLocationList FirstLevel;
    I->getFirstLevelLSLocations(FirstLevel, M);
    if (FirstLevel.empty())
      continue;

    // If this is a class reference type, we have reached end of the type tree.
    if (I->getType().getClassOrBoundGenericClass())
      continue;

    // This is NOT a leaf node, we need to construct a value for it.

    // There is only 1 children node and its value's projection path is not
    // empty, keep stripping it.
    auto Iter = FirstLevel.begin();
    LSValue &FirstVal = Values[*Iter];
    if (FirstLevel.size() == 1 && !FirstVal.hasEmptyProjectionPath()) {
      Values[*I] = FirstVal.stripLastLevelProjection();
      // We have a value for the parent, remove all the values for children.
      removeLSLocations(Values, FirstLevel);
      continue;
    }

    // If there are more than 1 children and all the children nodes have
    // LSValues with the same base and non-empty projection path. we can get
    // away by not extracting value for every single field.
    //
    // Simply create a new node with all the aggregated base value, i.e.
    // stripping off the last level projection.
    bool HasIdenticalValueBase = true;
    SILValue FirstBase = FirstVal.getBase();
    Iter = std::next(Iter);
    for (auto EndIter = FirstLevel.end(); Iter != EndIter; ++Iter) {
      LSValue &V = Values[*Iter];
      HasIdenticalValueBase &= (FirstBase == V.getBase());
    }

    if (FirstLevel.size() > 1 && HasIdenticalValueBase &&
        !FirstVal.hasEmptyProjectionPath()) {
      Values[*I] = FirstVal.stripLastLevelProjection();
      // We have a value for the parent, remove all the values for children.
      removeLSLocations(Values, FirstLevel);
      continue;
    }

    // In 3 cases do we need aggregation.
    //
    // 1. If there is only 1 child and we cannot strip off any projections,
    // that means we need to create an aggregation.
    //
    // 2. There are multiple children and they have the same base, but empty
    // projection paths.
    //
    // 3. Children have values from different bases, We need to create
    // extractions and aggregation in this case.
    //
    llvm::SmallVector<SILValue, 8> Vals;
    for (auto &X : FirstLevel) {
      Vals.push_back(Values[X].materialize(InsertPt));
    }
    SILBuilder Builder(InsertPt);

    // We use an auto-generated SILLocation for now.
    // TODO: make the sil location more precise.
    NullablePtr<swift::SILInstruction> AI =
        Projection::createAggFromFirstLevelProjections(
            Builder, RegularLocation::getAutoGeneratedLocation(), I->getType(),
            Vals);
    // This is the Value for the current node.
    ProjectionPath P;
    Values[*I] = LSValue(SILValue(AI.get()), P);
    removeLSLocations(Values, FirstLevel);

    // Keep iterating until we have reach the top-most level of the projection
    // tree.
    // i.e. the memory location represented by the Base.
  }

  assert(Values.size() == 1 && "Should have a single location this point");

  // Finally materialize and return the forwarding SILValue.
  return Values.begin()->second.materialize(InsertPt);
}

void LSValue::enumerateLSValue(SILModule *M, SILValue Val,
                               std::vector<LSValue> &Vault,
                               LSValueIndexMap &ValToBit,
                               TypeExpansionAnalysis *TE) {
  // Expand the given Mem into individual fields and add them to the
  // locationvault.
  LSValueList Vals;
  LSValue::expand(Val, M, Vals, TE);
  for (auto &Val : Vals) {
    ValToBit[Val] = Vault.size();
    Vault.push_back(Val);
  }
}

void LSValue::enumerateLSValues(SILFunction &F, std::vector<LSValue> &Vault,
                                LSValueIndexMap &ValToBit,
                                TypeExpansionAnalysis *TE) {
  // Enumerate all LSValues created or used by the loads or stores.
  //
  // TODO: process more instructions as we process more instructions in
  // processInstruction.
  //
  SILValue Op;
  for (auto &B : F) {
    for (auto &I : B) {
      if (auto *LI = dyn_cast<LoadInst>(&I)) {
        enumerateLSValue(&I.getModule(), SILValue(LI), Vault, ValToBit, TE);
      } else if (auto *SI = dyn_cast<StoreInst>(&I)) {
        enumerateLSValue(&I.getModule(), SI->getSrc(), Vault, ValToBit, TE);
      }
    }
  }

  // Lastly, push in the covering value LSValue.
  ValToBit[LSValue(true)] = Vault.size();
  Vault.push_back(LSValue(true));
}

//===----------------------------------------------------------------------===//
//                                  Memory Location
//===----------------------------------------------------------------------===//

void LSLocation::initialize(SILValue Dest) {
  Base = getUnderlyingObject(Dest);
  Path = ProjectionPath::getAddrProjectionPath(Base, Dest);
}

bool LSLocation::isMustAliasLSLocation(const LSLocation &RHS,
                                       AliasAnalysis *AA) {
  // If the bases are not must-alias, the locations may not alias.
  if (!AA->isMustAlias(Base, RHS.getBase()))
    return false;
  // If projection paths are different, then the locations cannot alias.
  if (!hasIdenticalProjectionPath(RHS))
    return false;
  return true;
}

bool LSLocation::isMayAliasLSLocation(const LSLocation &RHS,
                                      AliasAnalysis *AA) {
  // If the bases do not alias, then the locations cannot alias.
  if (AA->isNoAlias(Base, RHS.getBase()))
    return false;
  // If one projection path is a prefix of another, then the locations
  // could alias.
  if (hasNonEmptySymmetricPathDifference(RHS))
    return false;
  return true;
}

bool LSLocation::isNonEscapingLocalLSLocation(SILFunction *Fn,
                                              EscapeAnalysis *EA) {
  // An alloc_stack is definitely dead at the end of the function.
  if (isa<AllocStackInst>(Base))
    return true;
  // For other allocations we ask escape analysis.
  auto *ConGraph = EA->getConnectionGraph(Fn);
  if (isa<AllocationInst>(Base)) {
    auto *Node = ConGraph->getNodeOrNull(Base, EA);
    if (Node && !Node->escapes()) {
      return true;
    }
  }
  return false;
}

void LSLocation::getFirstLevelLSLocations(LSLocationList &Locs,
                                          SILModule *Mod) {
  SILType Ty = getType();
  llvm::SmallVector<Projection, 8> Out;
  Projection::getFirstLevelAddrProjections(Ty, *Mod, Out);
  for (auto &X : Out) {
    ProjectionPath P;
    P.append(X);
    P.append(Path.getValue());
    Locs.push_back(LSLocation(Base, P));
  }
}

void LSLocation::expand(LSLocation &Base, SILModule *M, LSLocationList &Locs,
                        TypeExpansionAnalysis *TE) {
  // To expand a memory location to its indivisible parts, we first get the
  // address projection paths from the accessed type to each indivisible field,
  // i.e. leaf nodes, then we append these projection paths to the Base.
  //
  // Construct the LSLocation by appending the projection path from the
  // accessed node to the leaf nodes.
  ProjectionPath &BasePath = Base.getPath().getValue();
  for (const auto &P :
       TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TELeaf)) {
    Locs.push_back(LSLocation(Base.getBase(), P.getValue(), BasePath));
  }
}

void LSLocation::reduce(LSLocation &Base, SILModule *M, LSLocationSet &Locs,
                        TypeExpansionAnalysis *TE) {
  // First, construct the LSLocation by appending the projection path from the
  // accessed node to the leaf nodes.
  LSLocationList Nodes;
  ProjectionPath &BasePath = Base.getPath().getValue();
  for (const auto &P :
       TE->getTypeExpansionProjectionPaths(Base.getType(), M, TEKind::TENode)) {
    Nodes.push_back(LSLocation(Base.getBase(), P.getValue(), BasePath));
  }

  // Second, go from leaf nodes to their parents. This guarantees that at the
  // point the parent is processed, its children have been processed already.
  for (auto I = Nodes.rbegin(), E = Nodes.rend(); I != E; ++I) {
    LSLocationList FirstLevel;
    I->getFirstLevelLSLocations(FirstLevel, M);
    // Reached the end of the projection tree, this is a leaf node.
    if (FirstLevel.empty())
      continue;

    // If this is a class reference type, we have reached end of the type tree.
    if (I->getType().getClassOrBoundGenericClass())
      continue;

    // This is NOT a leaf node, check whether all its first level children are
    // alive.
    bool Alive = true;
    for (auto &X : FirstLevel) {
      Alive &= Locs.find(X) != Locs.end();
    }

    // All first level locations are alive, create the new aggregated location.
    if (Alive) {
      for (auto &X : FirstLevel)
        Locs.erase(X);
      Locs.insert(*I);
    }
  }
}

void LSLocation::enumerateLSLocation(SILModule *M, SILValue Mem,
                                     std::vector<LSLocation> &LV,
                                     LSLocationIndexMap &BM,
                                     TypeExpansionAnalysis *TE) {
  // Construct a Location to represent the memory written by this instruction.
  LSLocation L(Mem);

  // If we cant figure out the Base or Projection Path for the memory location,
  // simply ignore it for now.
  if (!L.isValid())
    return;

  // Expand the given Mem into individual fields and add them to the
  // locationvault.
  LSLocationList Locs;
  LSLocation::expand(L, M, Locs, TE);
  for (auto &Loc : Locs) {
    BM[Loc] = LV.size();
    LV.push_back(Loc);
  }
}

void LSLocation::enumerateLSLocations(SILFunction &F,
                                      std::vector<LSLocation> &LV,
                                      LSLocationIndexMap &BM,
                                      TypeExpansionAnalysis *TE) {
  // Enumerate all locations accessed by the loads or stores.
  //
  // TODO: process more instructions as we process more instructions in
  // processInstruction.
  //
  SILValue Op;
  for (auto &B : F) {
    for (auto &I : B) {
      if (auto *LI = dyn_cast<LoadInst>(&I)) {
        enumerateLSLocation(&I.getModule(), LI->getOperand(), LV, BM, TE);
      } else if (auto *SI = dyn_cast<StoreInst>(&I)) {
        enumerateLSLocation(&I.getModule(), SI->getDest(), LV, BM, TE);
      }
    }
  }
}
<|endoftext|>


<commit_before>//===--- ImageInspectionELF.cpp - ELF image inspection --------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file includes routines that interact with ld*.so on ELF-based platforms
// to extract runtime metadata embedded in dynamically linked ELF images
// generated by the Swift compiler.
//
//===----------------------------------------------------------------------===//

#if defined(__ELF__) || defined(__ANDROID__)

#include "ImageInspection.h"
#include <dlfcn.h>
#include <elf.h>
#include <link.h>
#include <string.h>

using namespace swift;

/// The symbol name in the image that identifies the beginning of the
/// protocol conformances table.
static const char ProtocolConformancesSymbol[] =
  ".swift2_protocol_conformances_start";
/// The symbol name in the image that identifies the beginning of the
/// type metadata record table.
static const char TypeMetadataRecordsSymbol[] =
  ".swift2_type_metadata_start";

/// Context arguments passed down from dl_iterate_phdr to its callback.
struct InspectArgs {
  /// Symbol name to look up.
  const char *symbolName;
  /// Callback function to invoke with the metadata block.
  void (*addBlock)(const void *start, uintptr_t size);
  /// Set to true when initialize*Lookup() is called.
  bool didInitializeLookup;
};

static InspectArgs ProtocolConformanceArgs = {
  ProtocolConformancesSymbol,
  addImageProtocolConformanceBlockCallback,
  false
};

static InspectArgs TypeMetadataRecordArgs = {
  TypeMetadataRecordsSymbol,
  addImageTypeMetadataRecordBlockCallback,
  false
};

// Extract the section information for a named section in an image. imageName
// can be nullptr to specify the main executable.
static SectionInfo getSectionInfo(const char *imageName,
                                  const char *sectionName) {
  SectionInfo sectionInfo = { 0, nullptr };
  void *handle = dlopen(imageName, RTLD_LAZY);
  if (handle) {
    void *symbol = dlsym(handle, sectionName);
    if (symbol) {
      // Extract the size of the section data from the head of the section.
      const char *section = reinterpret_cast<const char *>(symbol);
      memcpy(&sectionInfo.size, section, sizeof(uint64_t));
      sectionInfo.data = section + sizeof(uint64_t);
    }
    dlclose(handle);
  }
  return sectionInfo;
}

static int iteratePHDRCallback(struct dl_phdr_info *info,
                               size_t size, void *data) {
  InspectArgs *inspectArgs = reinterpret_cast<InspectArgs *>(data);
  const char *fname = info->dlpi_name;

  // While dl_iterate_phdr() is in progress it holds a lock to prevent other
  // images being loaded. The initialize flag is set here inside the callback so
  // that addNewDSOImage() sees a consistent state. If it was set outside the
  // dl_interate_phdr() call then it could result in images being missed or
  // added twice.
  inspectArgs->didInitializeLookup = true;

  if (fname == nullptr || fname[0] == '\0') {
    // The filename may be null for both the dynamic loader and main executable.
    // So ignore null image name here and explictly add the main executable
    // in initialize*Lookup() to avoid adding the data twice.
    return 0;
  }

  SectionInfo block = getSectionInfo(fname, inspectArgs->symbolName);
  if (block.size > 0) {
    inspectArgs->addBlock(block.data, block.size);
  }
  return 0;
}

// Add the section information in an image specified by an address in that
// image.
static void addBlockInImage(const InspectArgs *inspectArgs, const void *addr) {
  const char *fname = nullptr;
  if (addr) {
    Dl_info info;
    if (dladdr(addr, &info) == 0 || info.dli_fname == nullptr) {
      return;
    }
    fname = info.dli_fname;
  }
  SectionInfo block = getSectionInfo(fname, inspectArgs->symbolName);
  if (block.size > 0) {
    inspectArgs->addBlock(block.data, block.size);
  }
}

static void initializeSectionLookup(InspectArgs *inspectArgs) {
  // Add section data in the main executable.
  addBlockInImage(inspectArgs, nullptr);
  // Search the loaded dls. This only searches the already
  // loaded ones. Any images loaded after this are processed by
  // addNewDSOImage() below.
  dl_iterate_phdr(iteratePHDRCallback, reinterpret_cast<void *>(inspectArgs));
}

void swift::initializeProtocolConformanceLookup() {
  initializeSectionLookup(&ProtocolConformanceArgs);
}

void swift::initializeTypeMetadataRecordLookup() {
  initializeSectionLookup(&TypeMetadataRecordArgs);
}

// As ELF images are loaded, ImageInspectionInit:sectionDataInit() will call
// addNewDSOImage() with an address in the image that can later be used via
// dladdr() to dlopen() the image after the appropiate initialize*Lookup()
// function has been called.
SWIFT_RUNTIME_EXPORT
void swift_addNewDSOImage(const void *addr) {
  if (ProtocolConformanceArgs.didInitializeLookup) {
    addBlockInImage(&ProtocolConformanceArgs, addr);
  }

  if (TypeMetadataRecordArgs.didInitializeLookup) {
    addBlockInImage(&TypeMetadataRecordArgs, addr);
  }
}

int swift::lookupSymbol(const void *address, SymbolInfo *info) {
  Dl_info dlinfo;
  if (dladdr(address, &dlinfo) == 0) {
    return 0;
  }

  info->fileName = dlinfo.dli_fname;
  info->baseAddress = dlinfo.dli_fbase;
  info->symbolName = dlinfo.dli_sname;
  info->symbolAddress = dlinfo.dli_saddr;
  return 1;
}

#endif // defined(__ELF__) || defined(__ANDROID__)
<commit_msg>[runtime] Abort if dlopen() fails when loading ELF section data<commit_after>//===--- ImageInspectionELF.cpp - ELF image inspection --------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file includes routines that interact with ld*.so on ELF-based platforms
// to extract runtime metadata embedded in dynamically linked ELF images
// generated by the Swift compiler.
//
//===----------------------------------------------------------------------===//

#if defined(__ELF__) || defined(__ANDROID__)

#include "ImageInspection.h"
#include "swift/Runtime/Debug.h"
#include <dlfcn.h>
#include <elf.h>
#include <link.h>
#include <string.h>

using namespace swift;

/// The symbol name in the image that identifies the beginning of the
/// protocol conformances table.
static const char ProtocolConformancesSymbol[] =
  ".swift2_protocol_conformances_start";
/// The symbol name in the image that identifies the beginning of the
/// type metadata record table.
static const char TypeMetadataRecordsSymbol[] =
  ".swift2_type_metadata_start";

/// Context arguments passed down from dl_iterate_phdr to its callback.
struct InspectArgs {
  /// Symbol name to look up.
  const char *symbolName;
  /// Callback function to invoke with the metadata block.
  void (*addBlock)(const void *start, uintptr_t size);
  /// Set to true when initialize*Lookup() is called.
  bool didInitializeLookup;
};

static InspectArgs ProtocolConformanceArgs = {
  ProtocolConformancesSymbol,
  addImageProtocolConformanceBlockCallback,
  false
};

static InspectArgs TypeMetadataRecordArgs = {
  TypeMetadataRecordsSymbol,
  addImageTypeMetadataRecordBlockCallback,
  false
};

// Extract the section information for a named section in an image. imageName
// can be nullptr to specify the main executable.
static SectionInfo getSectionInfo(const char *imageName,
                                  const char *sectionName) {
  SectionInfo sectionInfo = { 0, nullptr };
  void *handle = dlopen(imageName, RTLD_LAZY | RTLD_NOLOAD);
  if (!handle) {
    fatalError(/* flags = */ 0, "dlopen() failed on `%s': %s", imageName,
               dlerror());
  }
  void *symbol = dlsym(handle, sectionName);
  if (symbol) {
    // Extract the size of the section data from the head of the section.
    const char *section = reinterpret_cast<const char *>(symbol);
    memcpy(&sectionInfo.size, section, sizeof(uint64_t));
    sectionInfo.data = section + sizeof(uint64_t);
  }
  dlclose(handle);
  return sectionInfo;
}

static int iteratePHDRCallback(struct dl_phdr_info *info,
                               size_t size, void *data) {
  InspectArgs *inspectArgs = reinterpret_cast<InspectArgs *>(data);
  const char *fname = info->dlpi_name;

  // While dl_iterate_phdr() is in progress it holds a lock to prevent other
  // images being loaded. The initialize flag is set here inside the callback so
  // that addNewDSOImage() sees a consistent state. If it was set outside the
  // dl_interate_phdr() call then it could result in images being missed or
  // added twice.
  inspectArgs->didInitializeLookup = true;

  if (fname == nullptr || fname[0] == '\0') {
    // The filename may be null for both the dynamic loader and main executable.
    // So ignore null image name here and explictly add the main executable
    // in initialize*Lookup() to avoid adding the data twice.
    return 0;
  }

  SectionInfo block = getSectionInfo(fname, inspectArgs->symbolName);
  if (block.size > 0) {
    inspectArgs->addBlock(block.data, block.size);
  }
  return 0;
}

// Add the section information in an image specified by an address in that
// image.
static void addBlockInImage(const InspectArgs *inspectArgs, const void *addr) {
  const char *fname = nullptr;
  if (addr) {
    Dl_info info;
    if (dladdr(addr, &info) == 0 || info.dli_fname == nullptr) {
      return;
    }
    fname = info.dli_fname;
  }
  SectionInfo block = getSectionInfo(fname, inspectArgs->symbolName);
  if (block.size > 0) {
    inspectArgs->addBlock(block.data, block.size);
  }
}

static void initializeSectionLookup(InspectArgs *inspectArgs) {
  // Add section data in the main executable.
  addBlockInImage(inspectArgs, nullptr);
  // Search the loaded dls. This only searches the already
  // loaded ones. Any images loaded after this are processed by
  // addNewDSOImage() below.
  dl_iterate_phdr(iteratePHDRCallback, reinterpret_cast<void *>(inspectArgs));
}

void swift::initializeProtocolConformanceLookup() {
  initializeSectionLookup(&ProtocolConformanceArgs);
}

void swift::initializeTypeMetadataRecordLookup() {
  initializeSectionLookup(&TypeMetadataRecordArgs);
}

// As ELF images are loaded, ImageInspectionInit:sectionDataInit() will call
// addNewDSOImage() with an address in the image that can later be used via
// dladdr() to dlopen() the image after the appropiate initialize*Lookup()
// function has been called.
SWIFT_RUNTIME_EXPORT
void swift_addNewDSOImage(const void *addr) {
  if (ProtocolConformanceArgs.didInitializeLookup) {
    addBlockInImage(&ProtocolConformanceArgs, addr);
  }

  if (TypeMetadataRecordArgs.didInitializeLookup) {
    addBlockInImage(&TypeMetadataRecordArgs, addr);
  }
}

int swift::lookupSymbol(const void *address, SymbolInfo *info) {
  Dl_info dlinfo;
  if (dladdr(address, &dlinfo) == 0) {
    return 0;
  }

  info->fileName = dlinfo.dli_fname;
  info->baseAddress = dlinfo.dli_fbase;
  info->symbolName = dlinfo.dli_sname;
  info->symbolAddress = dlinfo.dli_saddr;
  return 1;
}

#endif // defined(__ELF__) || defined(__ANDROID__)
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
//...
//  Checks the quality assurance.
//  By comparing with reference data
//  Skeleton for T0
//---------------------------------------------
//checkig without reference data:
//for RAW QA all histograms should have approximatly the same
//number of entries as RefPoint
//for Rec Points checks
//  - amplitude measured by 2 methos
//  - online and offline T0 measurements
// for ESD quality of reconstruction ( and measurements):
// RMS of vertex and T0 less than 75ps
//
// Alla.Maevskaya@cern.ch
//...

// --- ROOT system ---
#include <Riostream.h>
#include <TClass.h>
#include <TH1F.h>
#include <TF1.h>
#include <TFitResultPtr.h>
#include <TH2.h>
#include <TIterator.h>
#include <TKey.h>
#include <TFile.h>
#include <TMath.h>
#include <TString.h>
#include <TPaveText.h>

// --- Standard library ---

// --- AliRoot header files ---
#include "AliLog.h"
#include "AliQAv1.h"
#include "AliQAChecker.h"
#include "AliCDBEntry.h"
#include "AliQAManager.h"
#include "AliT0QAChecker.h"

ClassImp(AliT0QAChecker)
//____________________________________________________________________________
AliT0QAChecker::AliT0QAChecker() :
AliQACheckerBase("T0","T0 Quality Assurance Checker")

{
  // Standard constructor

}

//____________________________________________________________________________
AliT0QAChecker::AliT0QAChecker(const AliT0QAChecker& qac):
  AliQACheckerBase(qac.GetName(), qac.GetTitle())
{
  // copy constructor
  AliError("Copy should not be used with this class\n");
}
//____________________________________________________________________________
AliT0QAChecker& AliT0QAChecker::operator=(const AliT0QAChecker& qac){
  // assignment operator
  this->~AliT0QAChecker();
  new(this)AliT0QAChecker(qac);
  return *this;
}

//____________________________________________________________________________
AliT0QAChecker::~AliT0QAChecker(){
  // destructor

}

//__________________________________________________________________
void AliT0QAChecker::Check(Double_t *  test, AliQAv1::ALITASK_t index, TObjArray ** list, const AliDetectorRecoParam * /*recoParam*/)
{

  // Super-basic check on the QA histograms on the input list:
  // look whether they are empty!

 char * detOCDBDir = Form("T0/%s/%s", AliQAv1::GetRefOCDBDirName(), AliQAv1::GetRefDataDirName()) ;

  AliCDBEntry *QARefRec = AliQAManager::QAManager()->Get(detOCDBDir);
  //  QARefRec->Dump();
  if( !QARefRec){
    AliInfo("QA reference data NOT retrieved for Reconstruction check. No T0 reference distribution");
  }

  for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++)
    test[specie]    = 10.0 ;

  for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) {
    //  TString dataType = AliQAv1::GetAliTaskName(index);
    if (!(AliQAv1::Instance()->IsEventSpecieSet(specie) && list[specie]) || list[specie]->GetEntries() == 0) {
      test[specie] = 1. ; // nothing to check
      continue;
    }
    if (index == AliQAv1::kRAW && AliRecoParam::ConvertIndex(specie) == AliRecoParam::kCalib)
      //      if (index == AliQAv1::kRAW )
      {
	test[specie] = CheckRaw(list[specie]);
      }
    if (index == AliQAv1::kESD && AliRecoParam::Convert(specie) != AliRecoParam::kCalib)
      test[specie] = CheckESD(list[specie]);
    //
  }
}

//--------------------------------------------------------------------------
Double_t AliT0QAChecker::CheckRaw(TObjArray *listrec) const
{
   Float_t checkr = 0;

  TString hname[10];
   TH1*hdata;
   const char *cname;
   TH1 *fhRawEff[10];
   Int_t nh=0;

   Int_t nnn[4] = { 420, 458, 459, 460};
   for (Int_t ir=0; ir<4; ir++)
     {
	 hdata = (TH1*) listrec->UncheckedAt(nnn[ir]);
	 if(hdata) {
	   cname = hdata->GetName();
	   hname[ir] = cname;
	   fhRawEff[nh] = hdata;
	   nh++;
	 }
    }

   TLine *linelowyellow = new TLine(0, 0.7, 24, 0.7);
   linelowyellow->SetLineColor(5);
   linelowyellow->SetLineStyle(3);
   linelowyellow->SetLineWidth(4);
   TLine *linelowred = new TLine(0, 0.2, 24, 0.2);
   linelowred->SetLineColor(2);
   linelowred->SetLineStyle(3);
   linelowred->SetLineWidth(4);

   Float_t thryell = 0.7;
   //   TPaveText* text = new TPaveText(0.30,0.50,0.99,0.99,"NDC");
   Float_t thrred = 0.2;
   Float_t chcont =0;
    for (Int_t ih= 0; ih<4; ih++)
     {
       fhRawEff[ih]->SetLineWidth(2);
       fhRawEff[ih]->SetMaximum(2.);
       fhRawEff[ih]->SetMinimum(0.);
       fhRawEff[ih]->GetListOfFunctions()->Add(linelowyellow);
       fhRawEff[ih]->GetListOfFunctions()->Add(linelowred);

       Int_t nbins= fhRawEff[ih]->GetNbinsX();
       Bool_t yell = kFALSE;
       Bool_t red = kFALSE;
       for (Int_t in=1; in<nbins-1; in++)
	 {
	   if(ih==0 && in==5) continue;
	   chcont=fhRawEff[ih]->GetBinContent(in);
	   if (chcont < thryell  ) yell = kTRUE;
	   if (chcont < thrred  ) red = kTRUE;
	 }

       if (! yell && !red) {
	 AliDebug(AliQAv1::GetQADebugLevel(), Form(" efficiency in all channes %s  is good", fhRawEff[ih]->GetName() ));
	 checkr=1.;
	 //	 text->AddText(Form("T0 RUN %d ",AliCDBManager::Instance()->GetRun()));
	 //	 text->AddText(Form(" No problems "));
	 //	 text->SetFillColor(3);
       }

       if(red ) {
	 checkr = 0.;
	 AliDebug(AliQAv1::GetQADebugLevel(), Form(" efficiency in all channes %s  is not so good", fhRawEff[ih]->GetName() ));
	 //	 text->AddText(Form("T0 RUN %d ",AliCDBManager::Instance()->GetRun()));
	 //	 text->AddText(Form("Very serious problem, call expert "));
	 //	 text->SetFillColor(2);
       }

       if ( yell && !red) {
	 AliDebug(AliQAv1::GetQADebugLevel(), Form(" efficiency in all channes %s  is not so good", fhRawEff[ih]->GetName() ));
	 checkr=0.75;
	 //	 text->AddText(Form("T0 RUN %d ",AliCDBManager::Instance()->GetRun()));
	 //	 text->AddText(Form("Some problems "));
	 //	 text->SetFillColor(5);
      }
       // fhRawEff[ih]->GetListOfFunctions()->Add(text);

     }
  return checkr;

}

//--------------------------------------------------------------------------
Double_t AliT0QAChecker::CheckESD(TObjArray *listrec ) const
{
  Float_t checkr = 0;
  TH1 *fhESD;

  fhESD  = (TH1*) listrec->UncheckedAt(2);
  if(fhESD){
    AliDebug(AliQAv1::GetQADebugLevel(), Form("count %s ", fhESD->GetName()) );
     TF1 *f1 = new TF1("f1","gaus",-1,1);
    fhESD->Fit("f1","R","Q", -1,1);
    Double_t par[3];
    f1->GetParameters(&par[0]);

    TPaveText* text = new TPaveText(0.30,0.50,0.99,0.99,"NDC");

    text->AddText(Form("T0 RUN %d ",AliCDBManager::Instance()->GetRun()));

    AliDebug(AliQAv1::GetQADebugLevel(), Form("numentries %d mean %f  #sigma %f", (int)fhESD->GetEntries(),par[1], par[2]));

    if (par[2] > 0.07 && par[2] < 1.) {
      checkr=0.5;
       text->AddText(Form("not good resolution :\n %f ns\n", par[2] ));
       text->SetFillColor(5);
       printf("T0 detector resolution is not good enouph: %f ns\n",par[2] );
    }
    if(TMath::Abs(par[1])>0.05) {
      checkr = 0.5;
      text->AddText(Form(" Check clock shift on %f ns", par[1]));
      text->SetFillColor(5);
    }
    if (par[2] >  1. || TMath::Abs(par[1])>0.1) {
      checkr = 0.25;
      text->AddText(Form(" Bad resolution:\n mean %f ns sigma %f ns", par[1], par[2]));
      text->SetFillColor(2);

      fhESD->GetListOfFunctions()->Add(text);
       AliDebug(AliQAv1::GetQADebugLevel(),
		Form("Please, check calibration: shift= %f resolution %f test=%f\n",
		     par[1], par[2], checkr) ) ;
    }
  }
  else
    {
      AliDebug(AliQAv1::GetQADebugLevel(),
	       Form("No ESD QA histogram found, nothing to check"));
	checkr=0;
    }

  return checkr;
}
<commit_msg>checjer fot new AliT0QADataMakerRec<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
//...
//  Checks the quality assurance.
//  By comparing with reference data
//  Skeleton for T0
//---------------------------------------------
//checkig without reference data:
//for RAW QA all histograms should have approximatly the same
//number of entries as RefPoint
//for Rec Points checks
//  - amplitude measured by 2 methos
//  - online and offline T0 measurements
// for ESD quality of reconstruction ( and measurements):
// RMS of vertex and T0 less than 75ps
//
// Alla.Maevskaya@cern.ch
//...

// --- ROOT system ---
#include <Riostream.h>
#include <TClass.h>
#include <TH1F.h>
#include <TF1.h>
#include <TFitResultPtr.h>
#include <TH2.h>
#include <TIterator.h>
#include <TKey.h>
#include <TFile.h>
#include <TMath.h>
#include <TString.h>
#include <TPaveText.h>

// --- Standard library ---

// --- AliRoot header files ---
#include "AliLog.h"
#include "AliQAv1.h"
#include "AliQAChecker.h"
#include "AliCDBEntry.h"
#include "AliQAManager.h"
#include "AliT0QAChecker.h"

ClassImp(AliT0QAChecker)
//____________________________________________________________________________
AliT0QAChecker::AliT0QAChecker() :
AliQACheckerBase("T0","T0 Quality Assurance Checker")

{
  // Standard constructor

}

//____________________________________________________________________________
AliT0QAChecker::AliT0QAChecker(const AliT0QAChecker& qac):
  AliQACheckerBase(qac.GetName(), qac.GetTitle())
{
  // copy constructor
  AliError("Copy should not be used with this class\n");
}
//____________________________________________________________________________
AliT0QAChecker& AliT0QAChecker::operator=(const AliT0QAChecker& qac){
  // assignment operator
  this->~AliT0QAChecker();
  new(this)AliT0QAChecker(qac);
  return *this;
}

//____________________________________________________________________________
AliT0QAChecker::~AliT0QAChecker(){
  // destructor

}

//__________________________________________________________________
void AliT0QAChecker::Check(Double_t *  test, AliQAv1::ALITASK_t index, TObjArray ** list, const AliDetectorRecoParam * /*recoParam*/)
{

  // Super-basic check on the QA histograms on the input list:
  // look whether they are empty!

 char * detOCDBDir = Form("T0/%s/%s", AliQAv1::GetRefOCDBDirName(), AliQAv1::GetRefDataDirName()) ;

  AliCDBEntry *QARefRec = AliQAManager::QAManager()->Get(detOCDBDir);
  //  QARefRec->Dump();
  if( !QARefRec){
    AliInfo("QA reference data NOT retrieved for Reconstruction check. No T0 reference distribution");
  }

  for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++)
    test[specie]    = 10.0 ;

  for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) {
    //  TString dataType = AliQAv1::GetAliTaskName(index);
    if (!(AliQAv1::Instance()->IsEventSpecieSet(specie) && list[specie]) || list[specie]->GetEntries() == 0) {
      test[specie] = 1. ; // nothing to check
      continue;
    }
    if (index == AliQAv1::kRAW && AliRecoParam::ConvertIndex(specie) == AliRecoParam::kCalib)
      //      if (index == AliQAv1::kRAW )
      {
	test[specie] = CheckRaw(list[specie]);
      }
    if (index == AliQAv1::kESD && AliRecoParam::Convert(specie) != AliRecoParam::kCalib)
      test[specie] = CheckESD(list[specie]);
    //
  }
}

//--------------------------------------------------------------------------
Double_t AliT0QAChecker::CheckRaw(TObjArray *listrec) const
{
   Float_t checkr = 0;

  TString hname[10];
   TH1*hdata;
   const char *cname;
   TH1 *fhRawEff[10];
   Int_t nh=0;

   //   Int_t nnn[4] = { 420, 458, 459, 460};
   Int_t nnn[4] = { 170, 208, 209, 210};
   for (Int_t ir=0; ir<4; ir++)
     {
	 hdata = (TH1*) listrec->UncheckedAt(nnn[ir]);
	 if(hdata) {
	   cname = hdata->GetName();
	   hname[ir] = cname;
	   fhRawEff[nh] = hdata;
	   nh++;
	 }
    }

   TLine *linelowyellow = new TLine(0, 0.7, 24, 0.7);
   linelowyellow->SetLineColor(5);
   linelowyellow->SetLineStyle(3);
   linelowyellow->SetLineWidth(4);
   TLine *linelowred = new TLine(0, 0.2, 24, 0.2);
   linelowred->SetLineColor(2);
   linelowred->SetLineStyle(3);
   linelowred->SetLineWidth(4);

   Float_t thryell = 0.7;
   //   TPaveText* text = new TPaveText(0.30,0.50,0.99,0.99,"NDC");
   Float_t thrred = 0.2;
   Float_t chcont =0;
    for (Int_t ih= 0; ih<4; ih++)
     {
       fhRawEff[ih]->SetLineWidth(2);
       fhRawEff[ih]->SetMaximum(2.);
       fhRawEff[ih]->SetMinimum(0.);
       fhRawEff[ih]->GetListOfFunctions()->Add(linelowyellow);
       fhRawEff[ih]->GetListOfFunctions()->Add(linelowred);

       Int_t nbins= fhRawEff[ih]->GetNbinsX();
       Bool_t yell = kFALSE;
       Bool_t red = kFALSE;
       for (Int_t in=1; in<nbins-1; in++)
	 {
	   if(ih==0 && in==5) continue;
	   chcont=fhRawEff[ih]->GetBinContent(in);
	   if (chcont < thryell  ) yell = kTRUE;
	   if (chcont < thrred  ) red = kTRUE;
	 }

       if (! yell && !red) {
	 AliDebug(AliQAv1::GetQADebugLevel(), Form(" efficiency in all channes %s  is good", fhRawEff[ih]->GetName() ));
	 checkr=1.;
	 //	 text->AddText(Form("T0 RUN %d ",AliCDBManager::Instance()->GetRun()));
	 //	 text->AddText(Form(" No problems "));
	 //	 text->SetFillColor(3);
       }

       if(red ) {
	 checkr = 0.;
	 AliDebug(AliQAv1::GetQADebugLevel(), Form(" efficiency in all channes %s  is not so good", fhRawEff[ih]->GetName() ));
	 //	 text->AddText(Form("T0 RUN %d ",AliCDBManager::Instance()->GetRun()));
	 //	 text->AddText(Form("Very serious problem, call expert "));
	 //	 text->SetFillColor(2);
       }

       if ( yell && !red) {
	 AliDebug(AliQAv1::GetQADebugLevel(), Form(" efficiency in all channes %s  is not so good", fhRawEff[ih]->GetName() ));
	 checkr=0.75;
	 //	 text->AddText(Form("T0 RUN %d ",AliCDBManager::Instance()->GetRun()));
	 //	 text->AddText(Form("Some problems "));
	 //	 text->SetFillColor(5);
      }
       // fhRawEff[ih]->GetListOfFunctions()->Add(text);

     }
  return checkr;

}

//--------------------------------------------------------------------------
Double_t AliT0QAChecker::CheckESD(TObjArray *listrec ) const
{
  Float_t checkr = 0;
  TH1 *fhESD;

  fhESD  = (TH1*) listrec->UncheckedAt(2);
  if(fhESD){
    AliDebug(AliQAv1::GetQADebugLevel(), Form("count %s ", fhESD->GetName()) );
     TF1 *f1 = new TF1("f1","gaus",-1,1);
    fhESD->Fit("f1","R","Q", -1,1);
    Double_t par[3];
    f1->GetParameters(&par[0]);

    TPaveText* text = new TPaveText(0.30,0.50,0.99,0.99,"NDC");

    text->AddText(Form("T0 RUN %d ",AliCDBManager::Instance()->GetRun()));

    AliDebug(AliQAv1::GetQADebugLevel(), Form("numentries %f mean %f  #sigma %f", (int)fhESD->GetEntries(),par[1], par[2]));

    if (par[2] > 0.07 && par[2] < 1.) {
      checkr=0.5;
       text->AddText(Form("not good resolution :\n %f ns\n", par[2] ));
       text->SetFillColor(5);
       printf("T0 detector resolution is not good enouph: %f ns\n",par[2] );
    }
    if(TMath::Abs(par[1])>0.05) {
      checkr = 0.5;
      text->AddText(Form(" Check clock shift on %f ns", par[1]));
      text->SetFillColor(5);
    }
    if (par[2] >  1. || TMath::Abs(par[1])>0.1) {
      checkr = 0.25;
      text->AddText(Form(" Bad resolution:\n mean %f ns sigma %f ns", par[1], par[2]));
      text->SetFillColor(2);

      fhESD->GetListOfFunctions()->Add(text);
       AliDebug(AliQAv1::GetQADebugLevel(),
		Form("Please, check calibration: shift= %f resolution %f test=%f\n",
		     par[1], par[2], checkr) ) ;
    }
  }
  else
    {
      AliDebug(AliQAv1::GetQADebugLevel(),
	       Form("No ESD QA histogram found, nothing to check"));
	checkr=0;
    }

  return checkr;
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2011, 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.
//
//////////////////////////////////////////////////////////////////////////

#include "boost/format.hpp"

#include "IECore/DeepPixel.h"
#include "IECore/Exception.h"
#include "IECore/Interpolator.h"

using namespace IECore;

DeepPixel::DeepPixel( const std::string channelNames, unsigned numSamples )
	: m_channels( channelNames.size() )
{
	m_depthIndices.reserve( numSamples );
	m_samples.reserve( numSamples * ( 1 + channelNames.size() ) );

	unsigned i = 0;
	for ( std::string::const_iterator it = channelNames.begin(); it != channelNames.end(); ++it, ++i )
	{
		m_channels[i] = *it;
	}
}

DeepPixel::DeepPixel( const std::vector<std::string> &channelNames, unsigned numSamples )
{
	m_depthIndices.reserve( numSamples );
	m_samples.reserve( numSamples * ( 1 + channelNames.size() ) );

	m_channels.reserve( channelNames.size() );
	for ( std::vector<std::string>::const_iterator it = channelNames.begin(); it != channelNames.end(); ++it )
	{
		m_channels.push_back( *it );
	}
}

DeepPixel::DeepPixel( const DeepPixel &pixel )
{
	m_channels.reserve( pixel.numChannels() );
	const std::vector<std::string> *names = pixel.channelNames();
	for ( std::vector<std::string>::const_iterator it = names->begin(); it != names->end(); ++it )
	{
		m_channels.push_back( *it );
	}

	merge( &pixel );
}

DeepPixel::~DeepPixel()
{
}

unsigned DeepPixel::numSamples() const
{
	return m_depthIndices.size();
}

float DeepPixel::min() const
{
	if ( !numSamples() )
	{
		return 0.0;
	}

	sort();

	return m_samples[ *m_depthIndices.begin() ];
}

float DeepPixel::max() const
{
	if ( !numSamples() )
	{
		return 0.0;
	}

	sort();

	return m_samples[ *m_depthIndices.rbegin() ];;
}

float DeepPixel::getDepth( unsigned index ) const
{
	sort();

	if( index >= numSamples() )
	{
		throw IECore::InvalidArgumentException( ( boost::format( "DeepPixel::getDepth: Depth index %d does not exist" ) % index ).str() );
	}

	return m_samples[ m_depthIndices[index] ];
}

class DeepPixel::DepthComparison
{
	public :

		DepthComparison( const DeepPixel *pixel ) : m_pixel( pixel )
		{
		}

		bool operator ()( unsigned a, unsigned b )
		{
			return ( m_pixel->m_samples[ a ] < m_pixel->m_samples[ b ] );
		}

	private :

		const DeepPixel *m_pixel;

};

void DeepPixel::setDepth( unsigned index, float depth )
{
	if( index >= numSamples() )
	{
		throw IECore::InvalidArgumentException( ( boost::format( "DeepPixel::setDepth: Depth index %d does not exist" ) % index ).str() );
	}

	sort();

	m_samples[ m_depthIndices[index] ] = depth;

	std::make_heap( m_depthIndices.begin(), m_depthIndices.end(), DepthComparison( this ) );

	m_sorted = false;
}

void DeepPixel::addSample( float depth, const float *channelData )
{
	unsigned sampleIndex = m_samples.size();
	unsigned numChannels = this->numChannels();
	m_samples.reserve( sampleIndex + numChannels + 1 );

	m_samples.push_back( depth );
	for ( unsigned i=0; i < numChannels; ++i )
	{
		m_samples.push_back( channelData[i] );
	}

	m_depthIndices.push_back( sampleIndex );

	if ( m_sorted )
	{
		std::make_heap( m_depthIndices.begin(), m_depthIndices.end(), DepthComparison( this ) );
	}
	else
	{
		std::push_heap( m_depthIndices.begin(), m_depthIndices.end(), DepthComparison( this ) );
	}

	m_sorted = false;
}

void DeepPixel::removeSample( unsigned index )
{
	sort();

	/// \todo: should this also remove the data from m_samples? do we have to worry about the heap?
	m_depthIndices.erase( m_depthIndices.begin() + index );
}

float *DeepPixel::channelData( unsigned index )
{
	sort();

	if( index >= numSamples() )
	{
		throw IECore::InvalidArgumentException( ( boost::format( "DeepPixel::channelData: Depth index %d does not exist" ) % index ).str() );
	}

	return &m_samples[ m_depthIndices[index]+1 ];
}

const float *DeepPixel::channelData( unsigned index ) const
{
	return const_cast<DeepPixel*>( this )->channelData( index );
}

void DeepPixel::interpolatedChannelData( float depth, float *result ) const
{
	sort();

	unsigned numSamples = this->numSamples();
	unsigned numChannels = this->numChannels();

	unsigned i = 0;
	for ( ; i < numSamples; ++i )
	{
		if ( m_samples[ m_depthIndices[i] ] > depth )
		{
			break;
		}
	}

	if ( i == 0 )
	{
		const float *data = channelData( i );
		for ( unsigned c=0; c < numChannels; ++c )
		{
			result[c] = data[c];
		}
	}
	else if ( i == numSamples )
	{
		const float *data = channelData( numSamples - 1 );
		for ( unsigned c=0; c < numChannels; ++c )
		{
			result[c] = data[c];
		}
	}
	else
	{
		float previousDepth = getDepth( i - 1 );
		float nextDepth = getDepth( i );
		float weight = ( depth - previousDepth ) / ( nextDepth - previousDepth );

		const float *previousData = channelData( i - 1 );
		const float *nextData = channelData( i );

		LinearInterpolator<float> lerp;
		for ( unsigned c=0; c < numChannels; ++c )
		{
			lerp( previousData[c], nextData[c], weight, result[c] );
		}
	}
}

unsigned DeepPixel::numChannels() const
{
	return m_channels.size();
}

int DeepPixel::channelIndex( const std::string &name ) const
{
	std::vector<std::string>::const_iterator it = std::find( m_channels.begin(), m_channels.end(), name );
	if ( it == m_channels.end() )
	{
		return -1;
	}

	return it - m_channels.begin();
}

const std::vector<std::string> *DeepPixel::channelNames() const
{
	return &m_channels;
}

void DeepPixel::merge( const DeepPixel *pixel )
{
	unsigned numSamples = pixel->numSamples();
	m_depthIndices.reserve( this->numSamples() + numSamples );
	m_samples.reserve( m_samples.size() + numSamples * ( pixel->numChannels() + 1 ) );

	for ( unsigned i=0; i < numSamples; ++i )
	{
		addSample( pixel->getDepth( i ), pixel->channelData( i ) );
	}
}

void DeepPixel::composite( float *result ) const
{
	unsigned numChannels = this->numChannels();
	int alphaChannel = channelIndex( "A" );
	if ( alphaChannel < 0 )
	{
		const float *data = channelData( 0 );
		for ( unsigned c=0; c < numChannels; ++c )
		{
			result[c] = data[c];
		}

		return;
	}

	for ( unsigned c=0; c < numChannels; ++c )
	{
		result[c] = 0.0;
	}

	float alpha = 1.0;
	unsigned numSamples = this->numSamples();
	for ( unsigned i=0; i < numSamples && result[alphaChannel] < 1.0; ++i )
	{
		const float *data = channelData( i );
		for ( unsigned c=0; c < numChannels; ++c )
		{
			result[c] += data[c] * alpha;
		}

		alpha = std::max( 1 - result[alphaChannel], 0.0f );
	}
}

DeepPixelPtr DeepPixel::average( std::vector<const DeepPixel *> &pixels, std::vector<float> &weights )
{
	unsigned numPixels = pixels.size();
	if ( !numPixels || numPixels != weights.size() )
	{
		throw IECore::InvalidArgumentException( "DeepPixel::average: There must be one weight per pixel" );
	}

	unsigned numChannels = pixels[0]->numChannels();
	for ( unsigned p=0; p < numPixels; ++p )
	{
		if ( numChannels != pixels[p]->numChannels() )
		{
			throw IECore::InvalidArgumentException( "DeepPixel::average: All pixels must have the same number of channels" );
		}
	}

	unsigned numSamples = pixels[0]->numSamples();

	DeepPixelPtr result = new DeepPixel( *pixels[0]->channelNames(), numSamples );

	float averageData[numChannels];
	float currentData[numChannels];

	for ( unsigned i=0; i < numSamples; ++i )
	{
		for ( unsigned c=0; c < numChannels; ++c )
		{
			averageData[c] = 0.0;
		}

		float depth = pixels[0]->getDepth( i );

		for ( unsigned p=0; p < numPixels; ++p )
		{
			pixels[p]->interpolatedChannelData( depth, currentData );
			for ( unsigned c=0; c < numChannels; ++c )
			{
				averageData[c] += weights[p] * currentData[c];
			}
		}

		result->addSample( depth, averageData );
	}

	return result;
}

void DeepPixel::sort()
{
	if ( m_sorted )
	{
		return;
	}

	std::sort_heap( m_depthIndices.begin(), m_depthIndices.end(), DepthComparison( this ) );

	m_sorted = true;
}

void DeepPixel::sort() const
{
	const_cast<DeepPixel*>( this )->sort();
}
<commit_msg>Fixed an uninitialized member in IECore::DeepPixel that could cause undefined behaviour when adding new samples.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2011-2014, 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.
//
//////////////////////////////////////////////////////////////////////////

#include "boost/format.hpp"

#include "IECore/DeepPixel.h"
#include "IECore/Exception.h"
#include "IECore/Interpolator.h"

using namespace IECore;

DeepPixel::DeepPixel( const std::string channelNames, unsigned numSamples )
	: m_sorted( false ),
	m_channels( channelNames.size() )
{
	m_depthIndices.reserve( numSamples );
	m_samples.reserve( numSamples * ( 1 + channelNames.size() ) );

	unsigned i = 0;
	for ( std::string::const_iterator it = channelNames.begin(); it != channelNames.end(); ++it, ++i )
	{
		m_channels[i] = *it;
	}
}

DeepPixel::DeepPixel( const std::vector<std::string> &channelNames, unsigned numSamples )
	: m_sorted( false )
{
	m_depthIndices.reserve( numSamples );
	m_samples.reserve( numSamples * ( 1 + channelNames.size() ) );

	m_channels.reserve( channelNames.size() );
	for ( std::vector<std::string>::const_iterator it = channelNames.begin(); it != channelNames.end(); ++it )
	{
		m_channels.push_back( *it );
	}
}

DeepPixel::DeepPixel( const DeepPixel &pixel )
{
	m_channels.reserve( pixel.numChannels() );
	const std::vector<std::string> *names = pixel.channelNames();
	for ( std::vector<std::string>::const_iterator it = names->begin(); it != names->end(); ++it )
	{
		m_channels.push_back( *it );
	}

	merge( &pixel );
}

DeepPixel::~DeepPixel()
{
}

unsigned DeepPixel::numSamples() const
{
	return m_depthIndices.size();
}

float DeepPixel::min() const
{
	if ( !numSamples() )
	{
		return 0.0;
	}

	sort();

	return m_samples[ *m_depthIndices.begin() ];
}

float DeepPixel::max() const
{
	if ( !numSamples() )
	{
		return 0.0;
	}

	sort();

	return m_samples[ *m_depthIndices.rbegin() ];;
}

float DeepPixel::getDepth( unsigned index ) const
{
	sort();

	if( index >= numSamples() )
	{
		throw IECore::InvalidArgumentException( ( boost::format( "DeepPixel::getDepth: Depth index %d does not exist" ) % index ).str() );
	}

	return m_samples[ m_depthIndices[index] ];
}

class DeepPixel::DepthComparison
{
	public :

		DepthComparison( const DeepPixel *pixel ) : m_pixel( pixel )
		{
		}

		bool operator ()( unsigned a, unsigned b )
		{
			return ( m_pixel->m_samples[ a ] < m_pixel->m_samples[ b ] );
		}

	private :

		const DeepPixel *m_pixel;

};

void DeepPixel::setDepth( unsigned index, float depth )
{
	if( index >= numSamples() )
	{
		throw IECore::InvalidArgumentException( ( boost::format( "DeepPixel::setDepth: Depth index %d does not exist" ) % index ).str() );
	}

	sort();

	m_samples[ m_depthIndices[index] ] = depth;

	std::make_heap( m_depthIndices.begin(), m_depthIndices.end(), DepthComparison( this ) );

	m_sorted = false;
}

void DeepPixel::addSample( float depth, const float *channelData )
{
	unsigned sampleIndex = m_samples.size();
	unsigned numChannels = this->numChannels();
	m_samples.reserve( sampleIndex + numChannels + 1 );

	m_samples.push_back( depth );
	for ( unsigned i=0; i < numChannels; ++i )
	{
		m_samples.push_back( channelData[i] );
	}

	m_depthIndices.push_back( sampleIndex );

	if ( m_sorted )
	{
		std::make_heap( m_depthIndices.begin(), m_depthIndices.end(), DepthComparison( this ) );
	}
	else
	{
		std::push_heap( m_depthIndices.begin(), m_depthIndices.end(), DepthComparison( this ) );
	}

	m_sorted = false;
}

void DeepPixel::removeSample( unsigned index )
{
	sort();

	/// \todo: should this also remove the data from m_samples? do we have to worry about the heap?
	m_depthIndices.erase( m_depthIndices.begin() + index );
}

float *DeepPixel::channelData( unsigned index )
{
	sort();

	if( index >= numSamples() )
	{
		throw IECore::InvalidArgumentException( ( boost::format( "DeepPixel::channelData: Depth index %d does not exist" ) % index ).str() );
	}

	return &m_samples[ m_depthIndices[index]+1 ];
}

const float *DeepPixel::channelData( unsigned index ) const
{
	return const_cast<DeepPixel*>( this )->channelData( index );
}

void DeepPixel::interpolatedChannelData( float depth, float *result ) const
{
	sort();

	unsigned numSamples = this->numSamples();
	unsigned numChannels = this->numChannels();

	unsigned i = 0;
	for ( ; i < numSamples; ++i )
	{
		if ( m_samples[ m_depthIndices[i] ] > depth )
		{
			break;
		}
	}

	if ( i == 0 )
	{
		const float *data = channelData( i );
		for ( unsigned c=0; c < numChannels; ++c )
		{
			result[c] = data[c];
		}
	}
	else if ( i == numSamples )
	{
		const float *data = channelData( numSamples - 1 );
		for ( unsigned c=0; c < numChannels; ++c )
		{
			result[c] = data[c];
		}
	}
	else
	{
		float previousDepth = getDepth( i - 1 );
		float nextDepth = getDepth( i );
		float weight = ( depth - previousDepth ) / ( nextDepth - previousDepth );

		const float *previousData = channelData( i - 1 );
		const float *nextData = channelData( i );

		LinearInterpolator<float> lerp;
		for ( unsigned c=0; c < numChannels; ++c )
		{
			lerp( previousData[c], nextData[c], weight, result[c] );
		}
	}
}

unsigned DeepPixel::numChannels() const
{
	return m_channels.size();
}

int DeepPixel::channelIndex( const std::string &name ) const
{
	std::vector<std::string>::const_iterator it = std::find( m_channels.begin(), m_channels.end(), name );
	if ( it == m_channels.end() )
	{
		return -1;
	}

	return it - m_channels.begin();
}

const std::vector<std::string> *DeepPixel::channelNames() const
{
	return &m_channels;
}

void DeepPixel::merge( const DeepPixel *pixel )
{
	unsigned numSamples = pixel->numSamples();
	m_depthIndices.reserve( this->numSamples() + numSamples );
	m_samples.reserve( m_samples.size() + numSamples * ( pixel->numChannels() + 1 ) );

	for ( unsigned i=0; i < numSamples; ++i )
	{
		addSample( pixel->getDepth( i ), pixel->channelData( i ) );
	}
}

void DeepPixel::composite( float *result ) const
{
	unsigned numChannels = this->numChannels();
	int alphaChannel = channelIndex( "A" );
	if ( alphaChannel < 0 )
	{
		const float *data = channelData( 0 );
		for ( unsigned c=0; c < numChannels; ++c )
		{
			result[c] = data[c];
		}

		return;
	}

	for ( unsigned c=0; c < numChannels; ++c )
	{
		result[c] = 0.0;
	}

	float alpha = 1.0;
	unsigned numSamples = this->numSamples();
	for ( unsigned i=0; i < numSamples && result[alphaChannel] < 1.0; ++i )
	{
		const float *data = channelData( i );
		for ( unsigned c=0; c < numChannels; ++c )
		{
			result[c] += data[c] * alpha;
		}

		alpha = std::max( 1 - result[alphaChannel], 0.0f );
	}
}

DeepPixelPtr DeepPixel::average( std::vector<const DeepPixel *> &pixels, std::vector<float> &weights )
{
	unsigned numPixels = pixels.size();
	if ( !numPixels || numPixels != weights.size() )
	{
		throw IECore::InvalidArgumentException( "DeepPixel::average: There must be one weight per pixel" );
	}

	unsigned numChannels = pixels[0]->numChannels();
	for ( unsigned p=0; p < numPixels; ++p )
	{
		if ( numChannels != pixels[p]->numChannels() )
		{
			throw IECore::InvalidArgumentException( "DeepPixel::average: All pixels must have the same number of channels" );
		}
	}

	unsigned numSamples = pixels[0]->numSamples();

	DeepPixelPtr result = new DeepPixel( *pixels[0]->channelNames(), numSamples );

	float averageData[numChannels];
	float currentData[numChannels];

	for ( unsigned i=0; i < numSamples; ++i )
	{
		for ( unsigned c=0; c < numChannels; ++c )
		{
			averageData[c] = 0.0;
		}

		float depth = pixels[0]->getDepth( i );

		for ( unsigned p=0; p < numPixels; ++p )
		{
			pixels[p]->interpolatedChannelData( depth, currentData );
			for ( unsigned c=0; c < numChannels; ++c )
			{
				averageData[c] += weights[p] * currentData[c];
			}
		}

		result->addSample( depth, averageData );
	}

	return result;
}

void DeepPixel::sort()
{
	if ( m_sorted )
	{
		return;
	}

	std::sort_heap( m_depthIndices.begin(), m_depthIndices.end(), DepthComparison( this ) );

	m_sorted = true;
}

void DeepPixel::sort() const
{
	const_cast<DeepPixel*>( this )->sort();
}
<|endoftext|>


<commit_before>/*
 * %injeqt copyright begin%
 * Copyright 2014 Rafał Malinowski (rafal.przemyslaw.malinowski@gmail.com)
 * %injeqt copyright end%
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "dependency-resolver.h"

#include "object-with-meta.h"
#include "resolved-dependency.h"

namespace injeqt { namespace v1 {

resolve_dependencies_result dependency_resolver::resolve_dependencies(
	const dependencies &to_resolve,
	const objects_with_meta &objects) const
{
	auto match_result = match(to_resolve.content(), objects.content());
	auto resolved = std::vector<resolved_dependency>{};

	for (auto &&match : match_result.matched)
		if (match.second)
			resolved.emplace_back(match.first, *match.second);

	return
	{
		dependencies{match_result.unmatched_1},
		resolved
	};
}

}}
<commit_msg>fix formatting<commit_after>/*
 * %injeqt copyright begin%
 * Copyright 2014 Rafał Malinowski (rafal.przemyslaw.malinowski@gmail.com)
 * %injeqt copyright end%
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "dependency-resolver.h"

#include "object-with-meta.h"
#include "resolved-dependency.h"

namespace injeqt { namespace v1 {

resolve_dependencies_result dependency_resolver::resolve_dependencies(
	const dependencies &to_resolve,
	const objects_with_meta &objects) const
{
	auto match_result = match(to_resolve.content(), objects.content());
	auto resolved = std::vector<resolved_dependency>{};

	for (auto &&match : match_result.matched)
		if (match.second)
			resolved.emplace_back(match.first, *match.second);

	return
	{
		dependencies{match_result.unmatched_1},
		resolved
	};
}

}}
<|endoftext|>


<commit_before>//===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This header file implements the operating system DynamicLibrary concept.
//
// FIXME: This file leaks ExplicitSymbols and OpenedHandles!
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Mutex.h"
#include "llvm-c/Core.h"
#include <cstdio>
#include <cstring>

// Collection of symbol name/value pairs to be searched prior to any libraries.
static llvm::ManagedStatic<llvm::StringMap<void *> > ExplicitSymbols;
static llvm::ManagedStatic<llvm::sys::SmartMutex<true> > SymbolsMutex;

void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName,
                                          void *symbolValue) {
  SmartScopedLock<true> lock(*SymbolsMutex);
  (*ExplicitSymbols)[symbolName] = symbolValue;
}

char llvm::sys::DynamicLibrary::Invalid = 0;

#ifdef LLVM_ON_WIN32

#include "Windows/DynamicLibrary.inc"

#else

#if HAVE_DLFCN_H
#include <dlfcn.h>
using namespace llvm;
using namespace llvm::sys;

//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only TRULY operating system
//===          independent code.
//===----------------------------------------------------------------------===//

static DenseSet<void *> *OpenedHandles = 0;

DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
                                                   std::string *errMsg) {
  SmartScopedLock<true> lock(*SymbolsMutex);

  void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL);
  if (handle == 0) {
    if (errMsg) *errMsg = dlerror();
    return DynamicLibrary();
  }

#ifdef __CYGWIN__
  // Cygwin searches symbols only in the main
  // with the handle of dlopen(NULL, RTLD_GLOBAL).
  if (filename == NULL)
    handle = RTLD_DEFAULT;
#endif

  if (OpenedHandles == 0)
    OpenedHandles = new DenseSet<void *>();

  // If we've already loaded this library, dlclose() the handle in order to
  // keep the internal refcount at +1.
  if (!OpenedHandles->insert(handle).second)
    dlclose(handle);

  return DynamicLibrary(handle);
}

void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
  if (!isValid())
    return NULL;
  return dlsym(Data, symbolName);
}

#else

using namespace llvm;
using namespace llvm::sys;

DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
                                                   std::string *errMsg) {
  if (errMsg) *errMsg = "dlopen() not supported on this platform";
  return DynamicLibrary();
}

void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
  return NULL;
}

#endif

namespace llvm {
void *SearchForAddressOfSpecialSymbol(const char* symbolName);
}

void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
  SmartScopedLock<true> Lock(*SymbolsMutex);

  // First check symbols added via AddSymbol().
  if (ExplicitSymbols.isConstructed()) {
    StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName);

    if (i != ExplicitSymbols->end())
      return i->second;
  }

#if HAVE_DLFCN_H
  // Now search the libraries.
  if (OpenedHandles) {
    for (DenseSet<void *>::iterator I = OpenedHandles->begin(),
         E = OpenedHandles->end(); I != E; ++I) {
      //lt_ptr ptr = lt_dlsym(*I, symbolName);
      void *ptr = dlsym(*I, symbolName);
      if (ptr) {
        return ptr;
      }
    }
  }
#endif

  if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName))
    return Result;

// This macro returns the address of a well-known, explicit symbol
#define EXPLICIT_SYMBOL(SYM) \
   if (!strcmp(symbolName, #SYM)) return &SYM

// On linux we have a weird situation. The stderr/out/in symbols are both
// macros and global variables because of standards requirements. So, we
// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
#if defined(__linux__) and !defined(__ANDROID__)
  {
    EXPLICIT_SYMBOL(stderr);
    EXPLICIT_SYMBOL(stdout);
    EXPLICIT_SYMBOL(stdin);
  }
#else
  // For everything else, we want to check to make sure the symbol isn't defined
  // as a macro before using EXPLICIT_SYMBOL.
  {
#ifndef stdin
    EXPLICIT_SYMBOL(stdin);
#endif
#ifndef stdout
    EXPLICIT_SYMBOL(stdout);
#endif
#ifndef stderr
    EXPLICIT_SYMBOL(stderr);
#endif
  }
#endif
#undef EXPLICIT_SYMBOL

  return 0;
}

#endif // LLVM_ON_WIN32

//===----------------------------------------------------------------------===//
// C API.
//===----------------------------------------------------------------------===//

LLVMBool LLVMLoadLibraryPermanently(const char* Filename) {
  return sys::DynamicLibrary::LoadLibraryPermanently(Filename);
}<commit_msg>[llvm-c] Specify explicit namespace in LLVMLoadLibraryPermanently<commit_after>//===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This header file implements the operating system DynamicLibrary concept.
//
// FIXME: This file leaks ExplicitSymbols and OpenedHandles!
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Mutex.h"
#include "llvm-c/Core.h"
#include <cstdio>
#include <cstring>

// Collection of symbol name/value pairs to be searched prior to any libraries.
static llvm::ManagedStatic<llvm::StringMap<void *> > ExplicitSymbols;
static llvm::ManagedStatic<llvm::sys::SmartMutex<true> > SymbolsMutex;

void llvm::sys::DynamicLibrary::AddSymbol(StringRef symbolName,
                                          void *symbolValue) {
  SmartScopedLock<true> lock(*SymbolsMutex);
  (*ExplicitSymbols)[symbolName] = symbolValue;
}

char llvm::sys::DynamicLibrary::Invalid = 0;

#ifdef LLVM_ON_WIN32

#include "Windows/DynamicLibrary.inc"

#else

#if HAVE_DLFCN_H
#include <dlfcn.h>
using namespace llvm;
using namespace llvm::sys;

//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only TRULY operating system
//===          independent code.
//===----------------------------------------------------------------------===//

static DenseSet<void *> *OpenedHandles = 0;

DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
                                                   std::string *errMsg) {
  SmartScopedLock<true> lock(*SymbolsMutex);

  void *handle = dlopen(filename, RTLD_LAZY|RTLD_GLOBAL);
  if (handle == 0) {
    if (errMsg) *errMsg = dlerror();
    return DynamicLibrary();
  }

#ifdef __CYGWIN__
  // Cygwin searches symbols only in the main
  // with the handle of dlopen(NULL, RTLD_GLOBAL).
  if (filename == NULL)
    handle = RTLD_DEFAULT;
#endif

  if (OpenedHandles == 0)
    OpenedHandles = new DenseSet<void *>();

  // If we've already loaded this library, dlclose() the handle in order to
  // keep the internal refcount at +1.
  if (!OpenedHandles->insert(handle).second)
    dlclose(handle);

  return DynamicLibrary(handle);
}

void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
  if (!isValid())
    return NULL;
  return dlsym(Data, symbolName);
}

#else

using namespace llvm;
using namespace llvm::sys;

DynamicLibrary DynamicLibrary::getPermanentLibrary(const char *filename,
                                                   std::string *errMsg) {
  if (errMsg) *errMsg = "dlopen() not supported on this platform";
  return DynamicLibrary();
}

void *DynamicLibrary::getAddressOfSymbol(const char *symbolName) {
  return NULL;
}

#endif

namespace llvm {
void *SearchForAddressOfSpecialSymbol(const char* symbolName);
}

void* DynamicLibrary::SearchForAddressOfSymbol(const char *symbolName) {
  SmartScopedLock<true> Lock(*SymbolsMutex);

  // First check symbols added via AddSymbol().
  if (ExplicitSymbols.isConstructed()) {
    StringMap<void *>::iterator i = ExplicitSymbols->find(symbolName);

    if (i != ExplicitSymbols->end())
      return i->second;
  }

#if HAVE_DLFCN_H
  // Now search the libraries.
  if (OpenedHandles) {
    for (DenseSet<void *>::iterator I = OpenedHandles->begin(),
         E = OpenedHandles->end(); I != E; ++I) {
      //lt_ptr ptr = lt_dlsym(*I, symbolName);
      void *ptr = dlsym(*I, symbolName);
      if (ptr) {
        return ptr;
      }
    }
  }
#endif

  if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName))
    return Result;

// This macro returns the address of a well-known, explicit symbol
#define EXPLICIT_SYMBOL(SYM) \
   if (!strcmp(symbolName, #SYM)) return &SYM

// On linux we have a weird situation. The stderr/out/in symbols are both
// macros and global variables because of standards requirements. So, we
// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first.
#if defined(__linux__) and !defined(__ANDROID__)
  {
    EXPLICIT_SYMBOL(stderr);
    EXPLICIT_SYMBOL(stdout);
    EXPLICIT_SYMBOL(stdin);
  }
#else
  // For everything else, we want to check to make sure the symbol isn't defined
  // as a macro before using EXPLICIT_SYMBOL.
  {
#ifndef stdin
    EXPLICIT_SYMBOL(stdin);
#endif
#ifndef stdout
    EXPLICIT_SYMBOL(stdout);
#endif
#ifndef stderr
    EXPLICIT_SYMBOL(stderr);
#endif
  }
#endif
#undef EXPLICIT_SYMBOL

  return 0;
}

#endif // LLVM_ON_WIN32

//===----------------------------------------------------------------------===//
// C API.
//===----------------------------------------------------------------------===//

LLVMBool LLVMLoadLibraryPermanently(const char* Filename) {
  return llvm::sys::DynamicLibrary::LoadLibraryPermanently(Filename);
}<|endoftext|>


<commit_before>namespace mant {
  namespace bbob2009 {
    class SharpRidgeFunction : public BlackBoxOptimisationBenchmark2009 {
      public:
        using BlackBoxOptimisationBenchmark2009::BlackBoxOptimisationBenchmark2009;

        inline std::string toString() const noexcept override;

      protected:
        const arma::Col<double> delta_ = getScaling(std::sqrt(10.0));

        inline double getObjectiveValueImplementation(
            const arma::Col<double>& parameter) const noexcept override;

#if defined(MANTELLA_USE_PARALLEL)
        friend class cereal::access;

        template <typename Archive>
        void serialize(
            Archive& archive) noexcept {
          archive(cereal::make_nvp("BlackBoxOptimisationBenchmark2009", cereal::base_class<BlackBoxOptimisationBenchmark2009>(this)));
          archive(cereal::make_nvp("numberOfDimensions", numberOfDimensions_));;
          archive(cereal::make_nvp("translation", translation_));
          archive(cereal::make_nvp("rotationR", rotationR_));
          archive(cereal::make_nvp("rotationQ", rotationQ_));
        }

        template <typename Archive>
        static void load_and_construct(
            Archive& archive,
            cereal::construct<SharpRidgeFunction>& construct) noexcept {
          unsigned int numberOfDimensions;
          archive(cereal::make_nvp("numberOfDimensions", numberOfDimensions));
          construct(numberOfDimensions);

          archive(cereal::make_nvp("BlackBoxOptimisationBenchmark2009", cereal::base_class<BlackBoxOptimisationBenchmark2009>(construct.ptr())));
          archive(cereal::make_nvp("translation", construct->translation_));
          archive(cereal::make_nvp("rotationR", construct->rotationR_));
          archive(cereal::make_nvp("rotationQ", construct->rotationQ_));
        }
#endif
    };

    //
    // Implementation
    //

    inline double SharpRidgeFunction::getObjectiveValueImplementation(
        const arma::Col<double>& parameter) const noexcept {
      const arma::Col<double>& z = rotationQ_ * (delta_ % (rotationR_ * (parameter - translation_)));
      return std::pow(z(0), 2.0) + 100.0 * arma::norm(z.tail(z.n_elem - 1));
    }

    inline std::string SharpRidgeFunction::toString() const noexcept {
      return "SharpRidgeFunction";
    }
  }
}

#if defined(MANTELLA_USE_PARALLEL)
// CEREAL_REGISTER_TYPE(mant::bbob2009::SharpRidgeFunction);
#endif
<commit_msg>Moved parameterisation into the sharp ridge function<commit_after>namespace mant {
  namespace bbob2009 {
    class SharpRidgeFunction : public BlackBoxOptimisationBenchmark2009 {
      public:
        inline explicit SharpRidgeFunction(
            const unsigned int& numberOfDimensions) noexcept;

        inline virtual void setLocalTranslation(
            const arma::Col<double>& localTranslation);

        inline virtual void setRotationR(
            const arma::Mat<double>& rotationR);

        inline virtual void setRotationQ(
            const arma::Mat<double>& rotationQ);

        inline std::string toString() const noexcept override;

      protected:
        arma::Col<double> localTranslation_;
        arma::Mat<double> rotationR_;
        arma::Mat<double> rotationQ_;

        inline double getObjectiveValueImplementation(
            const arma::Col<double>& parameter) const noexcept override;

#if defined(MANTELLA_USE_PARALLEL)
        friend class cereal::access;

        template <typename Archive>
        void serialize(
            Archive& archive) noexcept {
          archive(cereal::make_nvp("BlackBoxOptimisationBenchmark2009", cereal::base_class<BlackBoxOptimisationBenchmark2009>(this)));
          archive(cereal::make_nvp("numberOfDimensions", numberOfDimensions_));;
          archive(cereal::make_nvp("localTranslation", localTranslation_));
          archive(cereal::make_nvp("rotationR", rotationR_));
          archive(cereal::make_nvp("rotationQ", rotationQ_));
        }

        template <typename Archive>
        static void load_and_construct(
            Archive& archive,
            cereal::construct<SharpRidgeFunction>& construct) noexcept {
          unsigned int numberOfDimensions;
          archive(cereal::make_nvp("numberOfDimensions", numberOfDimensions));
          construct(numberOfDimensions);

          archive(cereal::make_nvp("BlackBoxOptimisationBenchmark2009", cereal::base_class<BlackBoxOptimisationBenchmark2009>(construct.ptr())));
          archive(cereal::make_nvp("localTranslation", construct->localTranslation_));
          archive(cereal::make_nvp("rotationR", construct->rotationR_));
          archive(cereal::make_nvp("rotationQ", construct->rotationQ_));
        }
#endif
    };

    //
    // Implementation
    //

    inline SharpRidgeFunction::SharpRidgeFunction(
        const unsigned int& numberOfDimensions) noexcept
      : BlackBoxOptimisationBenchmark2009(numberOfDimensions),
        scaling_(getScaling(std::sqrt(0.01))) {

      setLocalTranslation(getRandomLocalTranslation());
      setRotationR(getRandomRotationMatrix(numberOfDimensions_));
      setRotationQ(getRandomRotationMatrix(numberOfDimensions_));
    }

    inline void SharpRidgeFunction::setLocalTranslation(
        const arma::Col<double> localTranslation) {
      if (localTranslation.n_elem != numberOfDimensions_) {
        throw std::logic_error("The number of dimensions of the local translation (" + std::to_string(localTranslation.n_elem) + ") must match the number of dimensions of the optimisation problem (" + std::to_string(numberOfDimensions_) + ").");
      }

      localTranslation_ = localTranslation;
    }

    inline void SharpRidgeFunction::setRotationR(
        const arma::Mat<double> rotationR) {
      if (!rotationR.is_square()) {
        throw std::logic_error("The rotation matrix's shape (" + std::to_string(rotationR.n_rows) + ", " + std::to_string(rotationR.n_cols) + ") must be square.");
      } else if (rotationR.n_rows != numberOfDimensions_) {
        throw std::logic_error("The number of dimensions of the parameter rotation maxtrix (" + std::to_string(rotationR.n_rows) + ", " + std::to_string(rotationR.n_cols) + ") must match the number of dimensions of the optimisation problem (" + std::to_string(numberOfDimensions_) + ").");
      } else if(arma::any(arma::vectorise(arma::abs(rotationR.i() - rotationR.t()) > 1.0e-12 * std::max(1.0, std::abs(arma::median(arma::vectorise(rotationR))))))) {
        throw std::logic_error("The rotation matrix must be orthonormal.");
      } else if(std::abs(std::abs(arma::det(rotationR)) - 1.0) > 1.0e-12) {
        throw std::logic_error("The rotation matrix's determinant (" + std::to_string(arma::det(rotationR)) + ") must be either 1 or -1.");
      }

      rotationR_ = rotationR;
    }

    inline void SharpRidgeFunction::setRotationQ(
        const arma::Mat<double> rotationQ) {
      if (!rotationQ.is_square()) {
        throw std::logic_error("The rotation matrix's shape (" + std::to_string(rotationQ.n_rows) + ", " + std::to_string(rotationQ.n_cols) + ") must be square.");
      } else if (rotationQ.n_rows != numberOfDimensions_) {
        throw std::logic_error("The number of dimensions of the parameter rotation maxtrix (" + std::to_string(rotationQ.n_rows) + ", " + std::to_string(rotationQ.n_cols) + ") must match the number of dimensions of the optimisation problem (" + std::to_string(numberOfDimensions_) + ").");
      } else if(arma::any(arma::vectorise(arma::abs(rotationQ.i() - rotationQ.t()) > 1.0e-12 * std::max(1.0, std::abs(arma::median(arma::vectorise(rotationQ))))))) {
        throw std::logic_error("The rotation matrix must be orthonormal.");
      } else if(std::abs(std::abs(arma::det(rotationQ)) - 1.0) > 1.0e-12) {
        throw std::logic_error("The rotation matrix's determinant (" + std::to_string(arma::det(rotationQ)) + ") must be either 1 or -1.");
      }

      rotationQ_ = rotationQ;
    }

    inline double SharpRidgeFunction::getObjectiveValueImplementation(
        const arma::Col<double>& parameter) const noexcept {
      const arma::Col<double>& z = rotationQ_ * (scaling_ % (rotationR_ * (parameter - localTranslation_)));
      return std::pow(z(0), 2.0) + 100.0 * arma::norm(z.tail(z.n_elem - 1));
    }

    inline std::string SharpRidgeFunction::toString() const noexcept {
      return "SharpRidgeFunction";
    }
  }
}

#if defined(MANTELLA_USE_PARALLEL)
// CEREAL_REGISTER_TYPE(mant::bbob2009::SharpRidgeFunction);
#endif
<|endoftext|>