<commit_before>// Copyright 2019 Intel Corporation.

#include "pmlc/dialect/tile/gradient.h"

#include "llvm/ADT/SetVector.h"
#include "llvm/Support/FormatVariadic.h"

#include "mlir/Support/DebugStringHelper.h"

#include "base/util/logging.h"
#include "pmlc/dialect/tile/builder.h"
#include "pmlc/dialect/tile/ops.h"
#include "pmlc/util/slice.h"

namespace pmlc::dialect::tile {

Gradient::Gradient(mlir::Value* loss, TileBuilder* builder) : builder_(builder) {
  IVLOG(3, "Gradient::Gradient> loss: " << mlir::debugString(*loss));
  grads_[loss] = builder_->MakeScalarConstantOp(1.0);
  llvm::SetVector<mlir::Value*> loss_setvec;
  loss_setvec.insert(loss);
  auto defs = util::getBackwardSlice(loss_setvec, false, std::function<bool(mlir::Value*)>{[](mlir::Value* val) {
                                       auto op = val->getDefiningOp();
                                       // TODO: This is an ad hoc list of what to filter out; make it principled
                                       return !mlir::isa<AffineConstraintsOp>(op) && !mlir::isa<AffineMapOp>(op) &&
                                              !mlir::isa<AffineIndexOp>(op) && !mlir::isa<DimOp>(op) &&
                                              !mlir::isa<AffineConstantOp>(op) && !mlir::isa<AffineAddOp>(op) &&
                                              !mlir::isa<AffineDivOp>(op) && !mlir::isa<AffineMulOp>(op) &&
                                              !mlir::isa<AffineNegOp>(op) && !mlir::isa<AffineSubOp>(op) &&
                                              !mlir::isa<AffineMaxOp>(op) && !mlir::isa<AffineMinOp>(op) &&
                                              !mlir::isa<eltwise::ScalarConstantOp>(op);
                                     }});
  for (auto def = defs.rbegin(); def != defs.rend(); def++) {
    ComputeOperandDerivs(*def);
  }
  if (VLOG_IS_ON(5)) {
    IVLOG(5, "Gradient::Gradient> Computed the following gradients: ");
    for (auto [key, value] : grads_) {
      IVLOG(5, "  key is " << mlir::debugString(*key) << "\n    for val " << mlir::debugString(*value));
    }
  }
}

void Gradient::AddToGradient(Value* source_op, Value* deriv) {
  // Adds the gradient `deriv` computed for one use of `source_op` to the overall gradient of `source_op`
  if (!grads_.count(source_op)) {
    grads_[source_op] = deriv;
  } else {
    grads_[source_op] = builder_->MakePrimitiveOp("add", {grads_[source_op], deriv});
  }
}

void Gradient::ComputeOperandDerivs(mlir::Value* val) {
  IVLOG(4, "Gradient::ComputeDerivative> " << mlir::debugString(*val));
  // TODO: Throw on ops with multiple results?
  auto op = val->getDefiningOp();
  if (mlir::isa<AffineConstraintsOp>(op) || mlir::isa<AffineMapOp>(op) || mlir::isa<AffineIndexOp>(op) ||
      mlir::isa<PrngOp>(op) || mlir::isa<ShapeOp>(op)) {
    // TODO: Make the list of which ops these are more principled. Also, should these all be caught in the backwards
    // slice filter? If so, probably throw here.
    IVLOG(6, "Gradient::ComputeDerivative> Skipping computing derivatives for op "
                 << mlir::debugString(*op) << ", as it is not a type of op for which gradients apply");
    return;
  }
  if (!grads_.count(val)) {
    IVLOG(1, "Gradient::ComputeOperandDerivs> Called on Value which has not itself been differentiated: "
                 << mlir::debugString(*val));
    throw std::runtime_error("Unexpected missing derivative in ComputeOperandDerivs");
  }
  if (mlir::isa<eltwise::EltwiseOp>(op)) {
    size_t idx = 0;  // Need to track which operand we're at
    for (const auto& operand : op->getOperands()) {
      auto dop = DeriveEltwise(grads_[val], val, idx);
      AddToGradient(operand, dop);
      idx++;
    }
    // TODO: if grads_[operand] has rank > 0, call a simple_reduce
  } else if (auto cion_op = mlir::dyn_cast<SymbolicContractionOp>(op)) {
    {
      // TODO: I discussed this with Jeremy and I think the below notes are wrong, but we need another discussion.
      // TODO: Do `init` deriv right: we should passthrough on plus, conditional against result on max/min, throw on
      // product
      // TODO: This is a temporary hack!
      AddToGradient(cion_op.init(), grads_[val]);
    }
    size_t idx = 0;  // Need to track which operand we're at
    for (auto src : cion_op.srcs()) {
      auto dop = DeriveContraction(grads_[val], val, idx);
      AddToGradient(src, dop);
      idx++;
    }
  } else if (auto gather_op = mlir::dyn_cast<GatherOp>(op)) {
    auto tensor_input = gather_op.tensor();
    auto dims_input = gather_op.dims();
    auto dop = builder_->MakePrimitiveOp("scatter", {grads_[val], dims_input, tensor_input});
    auto zero_op = builder_->MakeScalarConstantOp(0.);
    AddToGradient(tensor_input, dop);
    AddToGradient(dims_input, zero_op);
  } else if (mlir::isa<ScatterOp>(op)) {
    // TODO
    throw std::runtime_error("TODO: Derivs of Scatter not yet implemented");
  } else if (auto reshape_op = mlir::dyn_cast<ReshapeOp>(op)) {
    auto tensor_input = reshape_op.tensor();
    std::vector<mlir::Value*> args{grads_[val]};
    for (size_t i = 0; i < tensor_input->getType().dyn_cast<RankedTensorType>().getRank(); ++i) {
      args.push_back(builder_->MakeDimOp(tensor_input, i));
    }
    auto dop = builder_->MakePrimitiveOp("reshape", args);
    AddToGradient(tensor_input, dop);
  } else if (mlir::isa<SpecialOp>(op)) {
    throw std::runtime_error("Unrecognized special operation, unable to differentiate");
  } else if (mlir::isa<DimOp>(op) || mlir::isa<eltwise::ScalarConstantOp>(op)) {
    auto dop = builder_->MakeScalarConstantOp(0.);
    for (const auto& operand : op->getOperands()) {
      AddToGradient(operand, dop);
    }
  } else if (auto tmap_op = mlir::dyn_cast<AffineTensorMapOp>(op)) {
    // Just forward the gradient in a tmap to the tensor
    AddToGradient(tmap_op.tensor(), grads_[val]);
  } else {
    if (op->getNumOperands()) {
      throw std::runtime_error("Unexpected Operation type in ComputeOperandDerivs! Operation is " +
                               mlir::debugString(*op));
    }
    // If it has no operands, it doesn't matter whether we can differentiate it, so we do nothing
  }
}

mlir::Value* Gradient::GetDerivative(mlir::Value* val) {
  IVLOG(5, "Gradient::GetDerivative> " << mlir::debugString(*val));
  auto it = grads_.find(val);
  if (it != grads_.end()) {
    IVLOG(6, "  Gradient::GetDerivative> Derivative retrieved: " << mlir::debugString(*it->second));
    return it->second;
  }
  // TODO:
  // In the long run, this should probably just return 0 or otherwise indicate a continuation
  // For now, I want to know if we hit this (as we shouldn't in most cases)
  IVLOG(1, "Gradient::GetDerivative> The requested derivative of " << mlir::debugString(*val) << " was not computed!");
  throw std::runtime_error("TODO: requested derivative not from getBackwardSlice");
}

mlir::Value* Gradient::DeriveEltwise(mlir::Value* dout, mlir::Value* out, size_t idx) {
  auto op = out->getDefiningOp();
  IVLOG(5, "Gradient::DeriveEltwise> dout=" << mlir::debugString(*dout) << ", op=" << mlir::debugString(*op)
                                            << ", idx=" << idx);
  auto deriv = DerivRegistry::Instance()->Resolve(op->getName().getStringRef());
  llvm::SmallVector<mlir::Value*, 3> operands{op->getOperands()};  // TODO: Size
  // TODO: Need to add simple_reduce here, unless done in the "if isa EltwiseOp" block above
  return deriv.fn(out, dout, operands, deriv.user_fn, deriv.user_ctx)[idx];
}

mlir::Value* Gradient::DeriveContraction(mlir::Value* dout, mlir::Value* out, size_t idx) {
  IVLOG(5, "Gradient::DeriveContraction> dout=" << mlir::debugString(*dout) << ", out=" << mlir::debugString(*out)
                                                << ", idx=" << idx);
  auto op = llvm::dyn_cast_or_null<SymbolicContractionOp>(out->getDefiningOp());
  if (!op) {
    throw std::runtime_error("DeriveContraction called on non-contraction");
  }
  if (op.combo() == util::CombinationKind::eq) {
    // TODO: What type should this 0 be?
    return builder_->MakeScalarConstantOp(0.);
  }

  auto combo_kind = util::CombinationKind::none;  // This may be reset later if necessary
  std::vector<Value*> new_srcs;
  Value* target_src = nullptr;
  switch (op.agg()) {
    case util::AggregationKind::max:
    case util::AggregationKind::min: {
      size_t i = 0;
      // TODO: Is there a better option to do "Get the unique src (or throw if not unique)"?
      for (auto src : op.srcs()) {
        if (i == idx) {
          combo_kind = util::CombinationKind::cond;
          auto src_op = mlir::dyn_cast_or_null<AffineTensorMapOp>(src->getDefiningOp());
          if (!src_op) {
            throw std::runtime_error("src_op as cast is null");
          }
          new_srcs.push_back(src_op);
          std::vector<Value*> dout_idxs;
          for (const auto& dim : llvm::cast<AffineMapOp>(op.sink()->getDefiningOp()).dims()) {
            dout_idxs.push_back(dim);
          }
          new_srcs.push_back(builder_->MakeAffineSourceIndexMapOp(op, dout_idxs));
          new_srcs.push_back(builder_->MakeAffineSourceIndexMapOp(dout, dout_idxs));
          // Also track that this is the differentiated source for later use
          target_src = src;
        } else {
          throw std::runtime_error("Cannot differentiate max/min contractions with multiple input tensors");
        }
        i++;
      }
    } break;
    case util::AggregationKind::add:
    case util::AggregationKind::assign: {
      size_t i = 0;
      for (auto src : op.srcs()) {
        if (i == idx) {
          // This is the differentiated input; so swap in dout here to create the new op
          std::vector<Value*> dout_idxs;
          for (const auto& dim : llvm::cast<AffineMapOp>(op.sink()->getDefiningOp()).dims()) {
            dout_idxs.push_back(dim);
          }
          new_srcs.push_back(builder_->MakeAffineSourceIndexMapOp(dout, dout_idxs));
          // Also track that this is the differentiated source for later use
          target_src = src;
        } else {
          // This is the non-differentiated input; behavior depends on combo op
          switch (op.combo()) {
            case util::CombinationKind::none:
              IVLOG(1, "About to fail on a NONE combo, with idx==" << idx << ", and i==" << i);
              throw std::runtime_error(
                  "Unexpected multiple inputs found when differentiating contraction with NONE combination op");
              break;
            case util::CombinationKind::add:
              // For +, we ignore the non-differentiated input
              combo_kind = util::CombinationKind::none;
              break;
            case util::CombinationKind::cond:
              throw std::runtime_error("Gradient of sum of conditionals not supported");
              break;
            case util::CombinationKind::eq:
              throw std::logic_error("Gradient unexpectedly failed to detect combo op as equality");
              break;
            case util::CombinationKind::mul:
              // For *, we multiply by the non-differentiated input
              new_srcs.push_back(src);
              combo_kind = util::CombinationKind::mul;
              break;
            default:
              throw std::runtime_error("Failed to recognize combination op during differentiation");
          }
        }
        i++;
      }
    } break;
    case util::AggregationKind::mul:
      throw std::runtime_error("Cannot differentiate multiplication aggregations");
      break;
    default:
      throw std::runtime_error("Did not recognize aggregation operation when differentiating " +
                               mlir::debugString(*out));
  }
  if (!target_src) {
    throw std::runtime_error(
        llvm::formatv("Trying to derive contraction at out of range index (requested source operand {0})", idx).str());
  }
  auto target_src_op = llvm::cast<AffineTensorMapOp>(target_src->getDefiningOp());
  std::vector<mlir::Value*> sizes;
  for (size_t i = 0; i < target_src_op.tensor()->getType().dyn_cast<RankedTensorType>().getRank(); ++i) {
    sizes.push_back(builder_->MakeDimOp(target_src_op.tensor(), i));
  }
  std::vector<mlir::Value*> dsrc_idxs;
  for (const auto& dim : target_src_op.dims()) {
    dsrc_idxs.push_back(dim);
  }

  std::string new_name;
  // TODO: Currently names are broken
  // auto src_name = op.name();
  // if (src_name) {
  //   new_name = llvm::formatv("d{0}", op.name()).str();
  // } // else use the empty string (already initialized by default ctor)
  auto dop_val = builder_->MakeContractionOp(         //
      util::AggregationKind::add,                     //
      combo_kind,                                     //
      new_srcs,                                       //
      builder_->MakeAffineSinkIndexMapOp(dsrc_idxs),  //
      builder_->MakeAffineSizeMapOp(sizes),           //
      new_name);
  // Copy the constraints from the forward pass contraction
  auto src_cons = llvm::dyn_cast<AffineConstraintsOp>(op.cons()->getDefiningOp());
  auto dop = llvm::dyn_cast<SymbolicContractionOp>(dop_val->getDefiningOp());
  auto dst_cons = llvm::dyn_cast<AffineConstraintsOp>(dop.cons()->getDefiningOp());
  mlir::SmallVector<mlir::Value*, 6> pairs{src_cons.pairs()};
  for (const auto& pair : src_cons.pairs()) {
    pairs.emplace_back(pair);
  }
  dst_cons.getOperation()->setOperands(pairs);
  return dop_val;
}

mlir::Value* Gradient::DeriveSpecial(const mlir::Value* dout, SpecialOp* op, size_t idx) {
  throw std::runtime_error("Made it to DeriveSpecial!");
}

}  // namespace pmlc::dialect::tile
<commit_msg>Fix signedness for compiler<commit_after>// Copyright 2019 Intel Corporation.

#include "pmlc/dialect/tile/gradient.h"

#include "llvm/ADT/SetVector.h"
#include "llvm/Support/FormatVariadic.h"

#include "mlir/Support/DebugStringHelper.h"

#include "base/util/logging.h"
#include "pmlc/dialect/tile/builder.h"
#include "pmlc/dialect/tile/ops.h"
#include "pmlc/util/slice.h"

namespace pmlc::dialect::tile {

Gradient::Gradient(mlir::Value* loss, TileBuilder* builder) : builder_(builder) {
  IVLOG(3, "Gradient::Gradient> loss: " << mlir::debugString(*loss));
  grads_[loss] = builder_->MakeScalarConstantOp(1.0);
  llvm::SetVector<mlir::Value*> loss_setvec;
  loss_setvec.insert(loss);
  auto defs = util::getBackwardSlice(loss_setvec, false, std::function<bool(mlir::Value*)>{[](mlir::Value* val) {
                                       auto op = val->getDefiningOp();
                                       // TODO: This is an ad hoc list of what to filter out; make it principled
                                       return !mlir::isa<AffineConstraintsOp>(op) && !mlir::isa<AffineMapOp>(op) &&
                                              !mlir::isa<AffineIndexOp>(op) && !mlir::isa<DimOp>(op) &&
                                              !mlir::isa<AffineConstantOp>(op) && !mlir::isa<AffineAddOp>(op) &&
                                              !mlir::isa<AffineDivOp>(op) && !mlir::isa<AffineMulOp>(op) &&
                                              !mlir::isa<AffineNegOp>(op) && !mlir::isa<AffineSubOp>(op) &&
                                              !mlir::isa<AffineMaxOp>(op) && !mlir::isa<AffineMinOp>(op) &&
                                              !mlir::isa<eltwise::ScalarConstantOp>(op);
                                     }});
  for (auto def = defs.rbegin(); def != defs.rend(); def++) {
    ComputeOperandDerivs(*def);
  }
  if (VLOG_IS_ON(5)) {
    IVLOG(5, "Gradient::Gradient> Computed the following gradients: ");
    for (auto [key, value] : grads_) {
      IVLOG(5, "  key is " << mlir::debugString(*key) << "\n    for val " << mlir::debugString(*value));
    }
  }
}

void Gradient::AddToGradient(Value* source_op, Value* deriv) {
  // Adds the gradient `deriv` computed for one use of `source_op` to the overall gradient of `source_op`
  if (!grads_.count(source_op)) {
    grads_[source_op] = deriv;
  } else {
    grads_[source_op] = builder_->MakePrimitiveOp("add", {grads_[source_op], deriv});
  }
}

void Gradient::ComputeOperandDerivs(mlir::Value* val) {
  IVLOG(4, "Gradient::ComputeDerivative> " << mlir::debugString(*val));
  // TODO: Throw on ops with multiple results?
  auto op = val->getDefiningOp();
  if (mlir::isa<AffineConstraintsOp>(op) || mlir::isa<AffineMapOp>(op) || mlir::isa<AffineIndexOp>(op) ||
      mlir::isa<PrngOp>(op) || mlir::isa<ShapeOp>(op)) {
    // TODO: Make the list of which ops these are more principled. Also, should these all be caught in the backwards
    // slice filter? If so, probably throw here.
    IVLOG(6, "Gradient::ComputeDerivative> Skipping computing derivatives for op "
                 << mlir::debugString(*op) << ", as it is not a type of op for which gradients apply");
    return;
  }
  if (!grads_.count(val)) {
    IVLOG(1, "Gradient::ComputeOperandDerivs> Called on Value which has not itself been differentiated: "
                 << mlir::debugString(*val));
    throw std::runtime_error("Unexpected missing derivative in ComputeOperandDerivs");
  }
  if (mlir::isa<eltwise::EltwiseOp>(op)) {
    size_t idx = 0;  // Need to track which operand we're at
    for (const auto& operand : op->getOperands()) {
      auto dop = DeriveEltwise(grads_[val], val, idx);
      AddToGradient(operand, dop);
      idx++;
    }
    // TODO: if grads_[operand] has rank > 0, call a simple_reduce
  } else if (auto cion_op = mlir::dyn_cast<SymbolicContractionOp>(op)) {
    {
      // TODO: I discussed this with Jeremy and I think the below notes are wrong, but we need another discussion.
      // TODO: Do `init` deriv right: we should passthrough on plus, conditional against result on max/min, throw on
      // product
      // TODO: This is a temporary hack!
      AddToGradient(cion_op.init(), grads_[val]);
    }
    size_t idx = 0;  // Need to track which operand we're at
    for (auto src : cion_op.srcs()) {
      auto dop = DeriveContraction(grads_[val], val, idx);
      AddToGradient(src, dop);
      idx++;
    }
  } else if (auto gather_op = mlir::dyn_cast<GatherOp>(op)) {
    auto tensor_input = gather_op.tensor();
    auto dims_input = gather_op.dims();
    auto dop = builder_->MakePrimitiveOp("scatter", {grads_[val], dims_input, tensor_input});
    auto zero_op = builder_->MakeScalarConstantOp(0.);
    AddToGradient(tensor_input, dop);
    AddToGradient(dims_input, zero_op);
  } else if (mlir::isa<ScatterOp>(op)) {
    // TODO
    throw std::runtime_error("TODO: Derivs of Scatter not yet implemented");
  } else if (auto reshape_op = mlir::dyn_cast<ReshapeOp>(op)) {
    auto tensor_input = reshape_op.tensor();
    std::vector<mlir::Value*> args{grads_[val]};
    for (int i = 0; i < tensor_input->getType().dyn_cast<RankedTensorType>().getRank(); ++i) {
      args.push_back(builder_->MakeDimOp(tensor_input, i));
    }
    auto dop = builder_->MakePrimitiveOp("reshape", args);
    AddToGradient(tensor_input, dop);
  } else if (mlir::isa<SpecialOp>(op)) {
    throw std::runtime_error("Unrecognized special operation, unable to differentiate");
  } else if (mlir::isa<DimOp>(op) || mlir::isa<eltwise::ScalarConstantOp>(op)) {
    auto dop = builder_->MakeScalarConstantOp(0.);
    for (const auto& operand : op->getOperands()) {
      AddToGradient(operand, dop);
    }
  } else if (auto tmap_op = mlir::dyn_cast<AffineTensorMapOp>(op)) {
    // Just forward the gradient in a tmap to the tensor
    AddToGradient(tmap_op.tensor(), grads_[val]);
  } else {
    if (op->getNumOperands()) {
      throw std::runtime_error("Unexpected Operation type in ComputeOperandDerivs! Operation is " +
                               mlir::debugString(*op));
    }
    // If it has no operands, it doesn't matter whether we can differentiate it, so we do nothing
  }
}

mlir::Value* Gradient::GetDerivative(mlir::Value* val) {
  IVLOG(5, "Gradient::GetDerivative> " << mlir::debugString(*val));
  auto it = grads_.find(val);
  if (it != grads_.end()) {
    IVLOG(6, "  Gradient::GetDerivative> Derivative retrieved: " << mlir::debugString(*it->second));
    return it->second;
  }
  // TODO:
  // In the long run, this should probably just return 0 or otherwise indicate a continuation
  // For now, I want to know if we hit this (as we shouldn't in most cases)
  IVLOG(1, "Gradient::GetDerivative> The requested derivative of " << mlir::debugString(*val) << " was not computed!");
  throw std::runtime_error("TODO: requested derivative not from getBackwardSlice");
}

mlir::Value* Gradient::DeriveEltwise(mlir::Value* dout, mlir::Value* out, size_t idx) {
  auto op = out->getDefiningOp();
  IVLOG(5, "Gradient::DeriveEltwise> dout=" << mlir::debugString(*dout) << ", op=" << mlir::debugString(*op)
                                            << ", idx=" << idx);
  auto deriv = DerivRegistry::Instance()->Resolve(op->getName().getStringRef());
  llvm::SmallVector<mlir::Value*, 3> operands{op->getOperands()};  // TODO: Size
  // TODO: Need to add simple_reduce here, unless done in the "if isa EltwiseOp" block above
  return deriv.fn(out, dout, operands, deriv.user_fn, deriv.user_ctx)[idx];
}

mlir::Value* Gradient::DeriveContraction(mlir::Value* dout, mlir::Value* out, size_t idx) {
  IVLOG(5, "Gradient::DeriveContraction> dout=" << mlir::debugString(*dout) << ", out=" << mlir::debugString(*out)
                                                << ", idx=" << idx);
  auto op = llvm::dyn_cast_or_null<SymbolicContractionOp>(out->getDefiningOp());
  if (!op) {
    throw std::runtime_error("DeriveContraction called on non-contraction");
  }
  if (op.combo() == util::CombinationKind::eq) {
    // TODO: What type should this 0 be?
    return builder_->MakeScalarConstantOp(0.);
  }

  auto combo_kind = util::CombinationKind::none;  // This may be reset later if necessary
  std::vector<Value*> new_srcs;
  Value* target_src = nullptr;
  switch (op.agg()) {
    case util::AggregationKind::max:
    case util::AggregationKind::min: {
      size_t i = 0;
      // TODO: Is there a better option to do "Get the unique src (or throw if not unique)"?
      for (auto src : op.srcs()) {
        if (i == idx) {
          combo_kind = util::CombinationKind::cond;
          auto src_op = mlir::dyn_cast_or_null<AffineTensorMapOp>(src->getDefiningOp());
          if (!src_op) {
            throw std::runtime_error("src_op as cast is null");
          }
          new_srcs.push_back(src_op);
          std::vector<Value*> dout_idxs;
          for (const auto& dim : llvm::cast<AffineMapOp>(op.sink()->getDefiningOp()).dims()) {
            dout_idxs.push_back(dim);
          }
          new_srcs.push_back(builder_->MakeAffineSourceIndexMapOp(op, dout_idxs));
          new_srcs.push_back(builder_->MakeAffineSourceIndexMapOp(dout, dout_idxs));
          // Also track that this is the differentiated source for later use
          target_src = src;
        } else {
          throw std::runtime_error("Cannot differentiate max/min contractions with multiple input tensors");
        }
        i++;
      }
    } break;
    case util::AggregationKind::add:
    case util::AggregationKind::assign: {
      size_t i = 0;
      for (auto src : op.srcs()) {
        if (i == idx) {
          // This is the differentiated input; so swap in dout here to create the new op
          std::vector<Value*> dout_idxs;
          for (const auto& dim : llvm::cast<AffineMapOp>(op.sink()->getDefiningOp()).dims()) {
            dout_idxs.push_back(dim);
          }
          new_srcs.push_back(builder_->MakeAffineSourceIndexMapOp(dout, dout_idxs));
          // Also track that this is the differentiated source for later use
          target_src = src;
        } else {
          // This is the non-differentiated input; behavior depends on combo op
          switch (op.combo()) {
            case util::CombinationKind::none:
              IVLOG(1, "About to fail on a NONE combo, with idx==" << idx << ", and i==" << i);
              throw std::runtime_error(
                  "Unexpected multiple inputs found when differentiating contraction with NONE combination op");
              break;
            case util::CombinationKind::add:
              // For +, we ignore the non-differentiated input
              combo_kind = util::CombinationKind::none;
              break;
            case util::CombinationKind::cond:
              throw std::runtime_error("Gradient of sum of conditionals not supported");
              break;
            case util::CombinationKind::eq:
              throw std::logic_error("Gradient unexpectedly failed to detect combo op as equality");
              break;
            case util::CombinationKind::mul:
              // For *, we multiply by the non-differentiated input
              new_srcs.push_back(src);
              combo_kind = util::CombinationKind::mul;
              break;
            default:
              throw std::runtime_error("Failed to recognize combination op during differentiation");
          }
        }
        i++;
      }
    } break;
    case util::AggregationKind::mul:
      throw std::runtime_error("Cannot differentiate multiplication aggregations");
      break;
    default:
      throw std::runtime_error("Did not recognize aggregation operation when differentiating " +
                               mlir::debugString(*out));
  }
  if (!target_src) {
    throw std::runtime_error(
        llvm::formatv("Trying to derive contraction at out of range index (requested source operand {0})", idx).str());
  }
  auto target_src_op = llvm::cast<AffineTensorMapOp>(target_src->getDefiningOp());
  std::vector<mlir::Value*> sizes;
  for (int i = 0; i < target_src_op.tensor()->getType().dyn_cast<RankedTensorType>().getRank(); ++i) {
    sizes.push_back(builder_->MakeDimOp(target_src_op.tensor(), i));
  }
  std::vector<mlir::Value*> dsrc_idxs;
  for (const auto& dim : target_src_op.dims()) {
    dsrc_idxs.push_back(dim);
  }

  std::string new_name;
  // TODO: Currently names are broken
  // auto src_name = op.name();
  // if (src_name) {
  //   new_name = llvm::formatv("d{0}", op.name()).str();
  // } // else use the empty string (already initialized by default ctor)
  auto dop_val = builder_->MakeContractionOp(         //
      util::AggregationKind::add,                     //
      combo_kind,                                     //
      new_srcs,                                       //
      builder_->MakeAffineSinkIndexMapOp(dsrc_idxs),  //
      builder_->MakeAffineSizeMapOp(sizes),           //
      new_name);
  // Copy the constraints from the forward pass contraction
  auto src_cons = llvm::dyn_cast<AffineConstraintsOp>(op.cons()->getDefiningOp());
  auto dop = llvm::dyn_cast<SymbolicContractionOp>(dop_val->getDefiningOp());
  auto dst_cons = llvm::dyn_cast<AffineConstraintsOp>(dop.cons()->getDefiningOp());
  mlir::SmallVector<mlir::Value*, 6> pairs{src_cons.pairs()};
  for (const auto& pair : src_cons.pairs()) {
    pairs.emplace_back(pair);
  }
  dst_cons.getOperation()->setOperands(pairs);
  return dop_val;
}

mlir::Value* Gradient::DeriveSpecial(const mlir::Value* dout, SpecialOp* op, size_t idx) {
  throw std::runtime_error("Made it to DeriveSpecial!");
}

}  // namespace pmlc::dialect::tile
<|endoftext|>


<commit_before>// DeceiverPlayer by Sxntk
// PPCG: http://codegolf.stackexchange.com/a/104972/11933

// DeceiverPlayer.hpp
// If we have two shoots, better shoot one by one

#ifndef __DECEPTIVE_PLAYER_HPP__
#define __DECEPTIVE_PLAYER_HPP__

#include "Player.hpp"

class DeceptivePlayer final : public Player
{
public:
	DeceptivePlayer(size_t opponent = -1) : Player(opponent) {}

public:
	virtual Action fight()
	{
		int ammo = getAmmo();
		int opponentAmmo = getAmmoOpponent();
		int turn = getTurn();

		// Without ammo, always load
		if (ammo == 0)
		{
			return load();
		}

		// Every 10 turns the Deceiver goes crazy
		if (turn % 10)
		{
			// Generate random integer in [0, 5)
			int random = GetRandomInteger() % 5;
			switch (random)
			{
			case 0:
				return bullet();
			case 1:
				return metal();
			case 2:
				if (ammo == 1)
				{
					return bullet();
				}

				return plasma();
			case 3:
				return thermal();
			case 4:
				return load();
			}
		}

		// The Deceiver shoots one bullet
		if (ammo == 2)
		{
			return bullet();
		}

		// Protect until we can get bullet 2
		if (opponentAmmo == 0)
		{
			return load();
		}

		if (opponentAmmo == 1)
		{
			return metal();
		}

		if (opponentAmmo == 2)
		{
			return thermal();
		}
	}
};

#endif // !__DECEPTIVE_PLAYER_HPP__<commit_msg>Update DeceptivePlayer according to main post.<commit_after>// DeceiverPlayer by Sxntk
// PPCG: http://codegolf.stackexchange.com/a/104972/11933

// DeceiverPlayer.hpp
// If we have two shoots, better shoot one by one

#ifndef __DECEIVER_PLAYER_HPP__
#define __DECEPTIVE_PLAYER_HPP__

#include "Player.hpp"

class DeceptivePlayer final : public Player
{
public:
	DeceptivePlayer(size_t opponent = -1) : Player(opponent) {}

public:
	virtual Action fight()
	{
		int ammo = getAmmo();
		int opponentAmmo = getAmmoOpponent();
		int turn = getTurn();

		// Without ammo, always load
		if (ammo == 0)
		{
			return load();
		}

		// Every 10 turns the Deceiver goes crazy
		if (turn % 10 || opponentAmmo >= 3)
		{
			// Generate random integer in [0, 5)
			int random = GetRandomInteger() % 5;
			switch (random)
			{
			case 0:
				return bullet();
			case 1:
				return metal();
			case 2:
				if (ammo == 1)
				{
					return bullet();
				}

				return plasma();
			case 3:
				return thermal();
			case 4:
				return load();
			}
		}

		// The Deceiver shoots one bullet
		if (ammo == 2)
		{
			return bullet();
		}

		// Protect until we can get bullet 2
		if (opponentAmmo == 0)
		{
			return load();
		}

		if (opponentAmmo == 1)
		{
			return metal();
		}

		if (opponentAmmo == 2)
		{
			return thermal();
		}
	}
};

#endif // !__DECEPTIVE_PLAYER_HPP__<|endoftext|>


<commit_before>#include <iostream>
#include <cstdio>
#include <QApplication>
#include <QtUiTools>

#include "med.hpp"

using namespace std;

class MainUi : public QObject {
  Q_OBJECT

public:
  MainUi() {
    loadUiFiles();
  }
  Med med;

private slots:
  void onProcessClicked() {
    med.listProcesses();

    processDialog->show();

    //Get the tree widget
    QTreeWidget* procTreeWidget = chooseProc->findChild<QTreeWidget*>("procTreeWidget");

    procTreeWidget->clear(); //Remove all items

    //Add all the process into the tree widget
    for(int i=med.processes.size()-1;i>=0;i--) {
      QTreeWidgetItem* item = new QTreeWidgetItem(procTreeWidget);
      item->setText(0, med.processes[i].pid.c_str());
      item->setText(1, med.processes[i].cmdline.c_str());
    }
  }

  void onProcItemDblClicked(QTreeWidgetItem* item, int column) {
    int index = item->treeWidget()->indexOfTopLevelItem(item); //Get the current row index
    med.selectedProcess = med.processes[med.processes.size() -1 - index];

    //Make changes to the selectedProc and hide the window
    QLineEdit* line = this->mainWindow->findChild<QLineEdit*>("selectedProc");
    line->setText(QString::fromLatin1((med.selectedProcess.pid + " " + med.selectedProcess.cmdline).c_str())); //Do not use fromStdString(), it will append with some unknown characters

    processDialog->hide();
  }

  void onScanClicked() {
    QTreeWidget* scanTreeWidget = mainWindow->findChild<QTreeWidget*>("scanTreeWidget");
    scanTreeWidget->clear();

    //Get scanned type
    string scanType = mainWindow->findChild<QComboBox*>("scanType")->currentText().toStdString();

    string scanValue = mainWindow->findChild<QLineEdit*>("scanEntry")->text().toStdString();

    if(med.selectedProcess.pid == "") {
      cerr << "No process seelcted " <<endl;
      return;
    }
    try {
      med.scanEqual(scanValue, scanType);
    } catch(string e) {
      cerr << "scan: "<<e<<endl;
    }

    if(med.scanAddresses.size() <= 800) {
      addressToScanTreeWidget(med, scanType, scanTreeWidget);
    }

    updateNumberOfAddresses(mainWindow);
  }

  void onFilterClicked() {
    QTreeWidget* scanTreeWidget = mainWindow->findChild<QTreeWidget*>("scanTreeWidget");
    scanTreeWidget->clear();

    //Get scanned type
    string scanType = mainWindow->findChild<QComboBox*>("scanType")->currentText().toStdString();

    string scanValue = mainWindow->findChild<QLineEdit*>("scanEntry")->text().toStdString();

    med.scanFilter(scanValue, scanType);

    if(med.scanAddresses.size() <= 800)
      addressToScanTreeWidget(med, scanType, scanTreeWidget);

    updateNumberOfAddresses(mainWindow);
  }

  void onClearClicked() {
    mainWindow->findChild<QTreeWidget*>("scanTreeWidget")->clear();
    med.scanAddresses.clear();
    mainWindow->findChild<QStatusBar*>("statusbar")->showMessage("Scan cleared");
  }

private:
  QWidget* mainWindow;
  QWidget* chooseProc;
  QDialog* processDialog;

  void loadUiFiles() {
    QUiLoader loader;

    QFile file("./main-qt.ui");
    file.open(QFile::ReadOnly);
    mainWindow = loader.load(&file);
    file.close();

    //Cannot put the followings to another method
    processDialog = new QDialog(mainWindow); //If put this to another method, then I cannot set the mainWindow as the parent
    QFile processFile("./process.ui");
    processFile.open(QFile::ReadOnly);

    chooseProc = loader.load(&processFile, processDialog);
    processFile.close();

    QVBoxLayout* layout = new QVBoxLayout();
    layout->addWidget(chooseProc);
    processDialog->setLayout(layout);
    processDialog->setModal(true);
    processDialog->resize(400, 400);

    //Statusbar meesage
    QStatusBar* statusBar = mainWindow->findChild<QStatusBar*>("statusbar");
    statusBar->showMessage("Tips: Left panel is scanned address. Right panel is stored address.");

    //Add signal
    QTreeWidget* procTreeWidget = chooseProc->findChild<QTreeWidget*>("procTreeWidget");
    QObject::connect(procTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(onProcItemDblClicked(QTreeWidgetItem*, int)));

    procTreeWidget->installEventFilter(this);

    //TODO: center
    mainWindow->show();

    //Add signal to the process
    QWidget* process = mainWindow->findChild<QWidget*>("process");
    QObject::connect(process, SIGNAL(clicked()), this, SLOT(onProcessClicked()));

    //Add signal to scan
    QWidget* scanButton = mainWindow->findChild<QWidget*>("scanButton");
    QObject::connect(scanButton, SIGNAL(clicked()), this, SLOT(onScanClicked()));

    QWidget* filterButton = mainWindow->findChild<QWidget*>("filterButton");
    QObject::connect(filterButton, SIGNAL(clicked()), this, SLOT(onFilterClicked()));

    QObject::connect(
                     mainWindow->findChild<QWidget*>("scanClear"),
                     SIGNAL(clicked()),
                     this,
                     SLOT(onClearClicked())
                     );
  }

  bool eventFilter(QObject* obj, QEvent* ev) {
    QTreeWidget* procTreeWidget = chooseProc->findChild<QTreeWidget*>("procTreeWidget");
    if(obj == procTreeWidget && ev->type() == QEvent::KeyRelease) {
      if(static_cast<QKeyEvent*>(ev)->key() == Qt::Key_Return) { //Use Return instead of Enter
        onProcItemDblClicked(procTreeWidget->currentItem(), 0); //Just use the first column
      }
    }
  }

  void addressToScanTreeWidget(Med med, string scanType, QTreeWidget* scanTreeWidget) {
    for(int i=0;i<med.scanAddresses.size();i++) {
      char address[32];
      sprintf(address, "%p", (void*)(med.scanAddresses[i].address));

      //Get the value from address and type
      string value = med.getScanAddressValueByIndex(i, scanType);

      QTreeWidgetItem* item = new QTreeWidgetItem(scanTreeWidget);
      item->setText(0, address);
      item->setText(1, scanType.c_str());
      item->setText(2, value.c_str());
    }
  }

  void updateNumberOfAddresses(QWidget* mainWindow) {
    char message[128];
    sprintf(message, "%ld addresses found", med.scanAddresses.size());
    mainWindow->findChild<QStatusBar*>("statusbar")->showMessage(message);
  }

};

int main(int argc, char **argv) {
  QApplication app(argc, argv);
  MainUi* mainUi = new MainUi();
  return app.exec();
}

#include "main-qt.moc"
<commit_msg>Edit scan value<commit_after>#include <iostream>
#include <cstdio>
#include <QApplication>
#include <QtUiTools>

#include "med.hpp"

using namespace std;

class MainUi : public QObject {
  Q_OBJECT

public:
  MainUi() {
    loadUiFiles();
  }
  Med med;

private slots:
  void onProcessClicked() {
    med.listProcesses();

    processDialog->show();

    //Get the tree widget
    QTreeWidget* procTreeWidget = chooseProc->findChild<QTreeWidget*>("procTreeWidget");

    procTreeWidget->clear(); //Remove all items

    //Add all the process into the tree widget
    for(int i=med.processes.size()-1;i>=0;i--) {
      QTreeWidgetItem* item = new QTreeWidgetItem(procTreeWidget);
      item->setText(0, med.processes[i].pid.c_str());
      item->setText(1, med.processes[i].cmdline.c_str());
    }
  }

  void onProcItemDblClicked(QTreeWidgetItem* item, int column) {
    int index = item->treeWidget()->indexOfTopLevelItem(item); //Get the current row index
    med.selectedProcess = med.processes[med.processes.size() -1 - index];

    //Make changes to the selectedProc and hide the window
    QLineEdit* line = this->mainWindow->findChild<QLineEdit*>("selectedProc");
    line->setText(QString::fromLatin1((med.selectedProcess.pid + " " + med.selectedProcess.cmdline).c_str())); //Do not use fromStdString(), it will append with some unknown characters

    processDialog->hide();
  }

  void onScanClicked() {
    QTreeWidget* scanTreeWidget = mainWindow->findChild<QTreeWidget*>("scanTreeWidget");
    scanTreeWidget->clear();

    //Get scanned type
    string scanType = mainWindow->findChild<QComboBox*>("scanType")->currentText().toStdString();

    string scanValue = mainWindow->findChild<QLineEdit*>("scanEntry")->text().toStdString();

    if(med.selectedProcess.pid == "") {
      cerr << "No process seelcted " <<endl;
      return;
    }
    try {
      med.scanEqual(scanValue, scanType);
    } catch(string e) {
      cerr << "scan: "<<e<<endl;
    }

    if(med.scanAddresses.size() <= 800) {
      addressToScanTreeWidget(med, scanType, scanTreeWidget);
    }

    updateNumberOfAddresses(mainWindow);
  }

  void onFilterClicked() {
    QTreeWidget* scanTreeWidget = mainWindow->findChild<QTreeWidget*>("scanTreeWidget");
    scanTreeWidget->clear();

    //Get scanned type
    string scanType = mainWindow->findChild<QComboBox*>("scanType")->currentText().toStdString();

    string scanValue = mainWindow->findChild<QLineEdit*>("scanEntry")->text().toStdString();

    med.scanFilter(scanValue, scanType);

    if(med.scanAddresses.size() <= 800)
      addressToScanTreeWidget(med, scanType, scanTreeWidget);

    updateNumberOfAddresses(mainWindow);
  }

  void onClearClicked() {
    mainWindow->findChild<QTreeWidget*>("scanTreeWidget")->clear();
    med.scanAddresses.clear();
    mainWindow->findChild<QStatusBar*>("statusbar")->showMessage("Scan cleared");
  }

  void onScanItemChanged(QTreeWidgetItem* item, int column) {
    switch(column) {
    case 2:
      editScanValue(item, column);
      break;
    }
  }

private:
  QWidget* mainWindow;
  QWidget* chooseProc;
  QDialog* processDialog;

  void loadUiFiles() {
    QUiLoader loader;

    QFile file("./main-qt.ui");
    file.open(QFile::ReadOnly);
    mainWindow = loader.load(&file);
    file.close();

    //Cannot put the followings to another method
    processDialog = new QDialog(mainWindow); //If put this to another method, then I cannot set the mainWindow as the parent
    QFile processFile("./process.ui");
    processFile.open(QFile::ReadOnly);

    chooseProc = loader.load(&processFile, processDialog);
    processFile.close();

    QVBoxLayout* layout = new QVBoxLayout();
    layout->addWidget(chooseProc);
    processDialog->setLayout(layout);
    processDialog->setModal(true);
    processDialog->resize(400, 400);

    //Statusbar meesage
    QStatusBar* statusBar = mainWindow->findChild<QStatusBar*>("statusbar");
    statusBar->showMessage("Tips: Left panel is scanned address. Right panel is stored address.");

    //Add signal
    QTreeWidget* procTreeWidget = chooseProc->findChild<QTreeWidget*>("procTreeWidget");
    QObject::connect(procTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(onProcItemDblClicked(QTreeWidgetItem*, int)));

    procTreeWidget->installEventFilter(this);

    //TODO: center
    mainWindow->show();

    //Add signal to the process
    QWidget* process = mainWindow->findChild<QWidget*>("process");
    QObject::connect(process, SIGNAL(clicked()), this, SLOT(onProcessClicked()));

    //Add signal to scan
    QWidget* scanButton = mainWindow->findChild<QWidget*>("scanButton");
    QObject::connect(scanButton, SIGNAL(clicked()), this, SLOT(onScanClicked()));

    QWidget* filterButton = mainWindow->findChild<QWidget*>("filterButton");
    QObject::connect(filterButton, SIGNAL(clicked()), this, SLOT(onFilterClicked()));

    QObject::connect(mainWindow->findChild<QWidget*>("scanClear"),
                     SIGNAL(clicked()),
                     this,
                     SLOT(onClearClicked())
                     );

    //Add signal
    QObject::connect(mainWindow->findChild<QTreeWidget*>("scanTreeWidget"),
                     SIGNAL(itemChanged(QTreeWidgetItem*, int)),
                     this,
                     SLOT(onScanItemChanged(QTreeWidgetItem*, int))
                     );

  }

  bool eventFilter(QObject* obj, QEvent* ev) {
    QTreeWidget* procTreeWidget = chooseProc->findChild<QTreeWidget*>("procTreeWidget");
    if(obj == procTreeWidget && ev->type() == QEvent::KeyRelease) {
      if(static_cast<QKeyEvent*>(ev)->key() == Qt::Key_Return) { //Use Return instead of Enter
        onProcItemDblClicked(procTreeWidget->currentItem(), 0); //Just use the first column
      }
    }
  }

  void addressToScanTreeWidget(Med med, string scanType, QTreeWidget* scanTreeWidget) {
    for(int i=0;i<med.scanAddresses.size();i++) {
      char address[32];
      sprintf(address, "%p", (void*)(med.scanAddresses[i].address));

      //Get the value from address and type
      string value = med.getScanAddressValueByIndex(i, scanType);

      QTreeWidgetItem* item = new QTreeWidgetItem(scanTreeWidget);
      item->setText(0, address);
      item->setText(1, scanType.c_str());
      item->setText(2, value.c_str());

      item->setFlags(item->flags() | (Qt::ItemIsEditable));
    }
  }

  void updateNumberOfAddresses(QWidget* mainWindow) {
    char message[128];
    sprintf(message, "%ld addresses found", med.scanAddresses.size());
    mainWindow->findChild<QStatusBar*>("statusbar")->showMessage(message);
  }

  void editScanValue(QTreeWidgetItem* item, int column) {
    int index = item->treeWidget()->indexOfTopLevelItem(item);
    string text = item->text(column).toStdString();
    if(med.selectedProcess.pid == "") {
      cerr<< "No PID" <<endl;
      return;
    }

    try {
      med.setValueByAddress(med.scanAddresses[index].address,
                            text,
                            med.scanAddresses[index].getScanType());
    } catch(string e) {
      cerr << "editScanValue: "<<e<<endl;
    }
  }

};

int main(int argc, char **argv) {
  QApplication app(argc, argv);
  MainUi* mainUi = new MainUi();
  return app.exec();
}

#include "main-qt.moc"
<|endoftext|>


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

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "classifierio.hpp"

using namespace std;

ClassifierIO::ClassifierIO(int dirNum, int stageNum)
{
   _dirNum   = dirNum;
   _stageNum = stageNum;
}

// given a directory number generate a filename for that dir
// if it exists - if it doesnt, return an empty string
string ClassifierIO::getClassifierDir() const
{
   struct stat fileStat;
   stringstream ss;
   ss << "/cygdrive/a/2015VisionCode/cascade_training/classifier_bin_";
   ss << _dirNum;
   if ((stat(ss.str().c_str(), &fileStat) == 0) && S_ISDIR(fileStat.st_mode))
      return string(ss.str());
   return string();
}

// given a directory number and stage within that directory
// generate a filename to load the cascade from.  Check that
// the file exists - if it doesnt, return an empty string
string ClassifierIO::getClassifierName() const
{
   struct stat fileStat;
   stringstream ss;
   string dirName = getClassifierDir();
   if (!dirName.length())
      return string();

   ss << dirName;
   ss << "/cascade_oldformat_";
   ss << _stageNum;
   ss << ".xml";

   if ((stat(ss.str().c_str(), &fileStat) == 0) && (fileStat.st_size > 5000))
      return string(ss.str());

   // Try the non-oldformat one next
   ss.str(string());
   ss.clear();
   ss << dirName;
   ss << "/cascade_";
   ss << _stageNum;
   ss << ".xml";

   if ((stat(ss.str().c_str(), &fileStat) == 0) && (fileStat.st_size > 5000))
      return string(ss.str());

   // Found neither?  Return an empty string
   return string();
}

// Find the next valid classifier. Since some .xml input
// files crash the GPU we've deleted them. Skip over missing
// files in the sequence
bool ClassifierIO::findNextClassifierStage(bool increment)
{
   int adder = increment ? 1 : -1;
   int num = _stageNum + adder;
   bool found;

   for (found = false; !found && ((num > 0) && (num < 100)); num += adder)
   {
      ClassifierIO tempClassifier(_dirNum, num);
      if (tempClassifier.getClassifierName().length())
      {
	 *this = tempClassifier;
	 found = true;
      }
   }

   return found;
}

// Find the next valid classifier dir. Start with current stage in that
// directory and work down until a classifier is found
bool ClassifierIO::findNextClassifierDir(bool increment)
{
   int adder = increment ? 1 : -1;
   int dnum = _dirNum + adder;
   bool found;

   for (found = false; !found && ((dnum > 0) && (dnum < 100)); dnum += adder)
   {
      ClassifierIO tempClassifier(dnum, _stageNum+1);
      if (tempClassifier.getClassifierDir().length())
      {
	 // Try to find a valid classifier in this dir, counting
	 // down from the current stage number
	 if (tempClassifier.findNextClassifierStage(false))
	 {
	    *this = tempClassifier;
	    found = true;
	 }
      }
   }

   return found;
}

int ClassifierIO::dirNum(void) const
{
   return _dirNum;
}

int ClassifierIO::stageNum(void) const
{
   return _stageNum;
}
<commit_msg>Fix path to classifier info<commit_after>#include <iostream>
#include <sstream>
#include <string>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "classifierio.hpp"

using namespace std;

ClassifierIO::ClassifierIO(int dirNum, int stageNum)
{
   _dirNum   = dirNum;
   _stageNum = stageNum;
}

// given a directory number generate a filename for that dir
// if it exists - if it doesnt, return an empty string
string ClassifierIO::getClassifierDir() const
{
   struct stat fileStat;
   stringstream ss;
   ss << "/home/ubuntu/2015VisionCode/cascade_training/classifier_bin_";
   ss << _dirNum;
   if ((stat(ss.str().c_str(), &fileStat) == 0) && S_ISDIR(fileStat.st_mode))
      return string(ss.str());
   return string();
}

// given a directory number and stage within that directory
// generate a filename to load the cascade from.  Check that
// the file exists - if it doesnt, return an empty string
string ClassifierIO::getClassifierName() const
{
   struct stat fileStat;
   stringstream ss;
   string dirName = getClassifierDir();
   if (!dirName.length())
      return string();

   ss << dirName;
   ss << "/cascade_oldformat_";
   ss << _stageNum;
   ss << ".xml";

   if ((stat(ss.str().c_str(), &fileStat) == 0) && (fileStat.st_size > 5000))
      return string(ss.str());

   // Try the non-oldformat one next
   ss.str(string());
   ss.clear();
   ss << dirName;
   ss << "/cascade_";
   ss << _stageNum;
   ss << ".xml";

   if ((stat(ss.str().c_str(), &fileStat) == 0) && (fileStat.st_size > 5000))
      return string(ss.str());

   // Found neither?  Return an empty string
   return string();
}

// Find the next valid classifier. Since some .xml input
// files crash the GPU we've deleted them. Skip over missing
// files in the sequence
bool ClassifierIO::findNextClassifierStage(bool increment)
{
   int adder = increment ? 1 : -1;
   int num = _stageNum + adder;
   bool found;

   for (found = false; !found && ((num > 0) && (num < 100)); num += adder)
   {
      ClassifierIO tempClassifier(_dirNum, num);
      if (tempClassifier.getClassifierName().length())
      {
	 *this = tempClassifier;
	 found = true;
      }
   }

   return found;
}

// Find the next valid classifier dir. Start with current stage in that
// directory and work down until a classifier is found
bool ClassifierIO::findNextClassifierDir(bool increment)
{
   int adder = increment ? 1 : -1;
   int dnum = _dirNum + adder;
   bool found;

   for (found = false; !found && ((dnum > 0) && (dnum < 100)); dnum += adder)
   {
      ClassifierIO tempClassifier(dnum, _stageNum+1);
      if (tempClassifier.getClassifierDir().length())
      {
	 // Try to find a valid classifier in this dir, counting
	 // down from the current stage number
	 if (tempClassifier.findNextClassifierStage(false))
	 {
	    *this = tempClassifier;
	    found = true;
	 }
      }
   }

   return found;
}

int ClassifierIO::dirNum(void) const
{
   return _dirNum;
}

int ClassifierIO::stageNum(void) const
{
   return _stageNum;
}
<|endoftext|>


<commit_before>// =================================================================== //
// Copyright (C) 2021-2022 Kimura Ryo                                  //
//                                                                     //
// This Source Code Form is subject to the terms of the Mozilla Public //
// License, v. 2.0. If a copy of the MPL was not distributed with this //
// file, You can obtain one at http://mozilla.org/MPL/2.0/.            //
// =================================================================== //

#include <libbsdf/Fitter/BrdfFitter.h>

#include <ceres/ceres.h>

#include <libbsdf/Common/SpectrumUtility.h>
#include <libbsdf/Common/Utility.h>
#include <libbsdf/Common/Xorshift.h>

using namespace lb;

BrdfFitter::Data::Data(const Brdf& brdf, int numSampling, const Vec3::Scalar& maxTheta)
{
    const SampleSet* ss = brdf.getSampleSet();

    const Vec3::Scalar threshold = std::cos(maxTheta);

    if (numSampling <= 0 || maxTheta < toRadian(Vec3::Scalar(EPSILON_F))) {
        for (int i0 = 0; i0 < ss->getNumAngles0(); ++i0) {
        for (int i1 = 0; i1 < ss->getNumAngles1(); ++i1) {
        for (int i2 = 0; i2 < ss->getNumAngles2(); ++i2) {
        for (int i3 = 0; i3 < ss->getNumAngles3(); ++i3) {
            Vec3 inDir, outDir;
            brdf.toXyz(ss->getAngle0(i0),
                       ss->getAngle1(i1),
                       ss->getAngle2(i2),
                       ss->getAngle3(i3),
                       &inDir, &outDir);

            if (inDir[2] < threshold || outDir[2] < threshold) continue;

            Sample sample;
            sample.inDir = inDir;
            sample.outDir = outDir;
            sample.value =
                toSrgb<Vec3, SampleSet>(brdf.getSpectrum(sample.inDir, sample.outDir), *ss);

            samples_.push_back(sample);
        }}}}
    }
    else {
        int count = 0;
        Xorshift rnd;
        while (count < numSampling) {
            Sample sample;
            sample.inDir = rnd.nextOnHemisphere<Vec3>();
            sample.outDir = rnd.nextOnHemisphere<Vec3>();

            if (sample.inDir[2] < threshold || sample.outDir[2] < threshold) continue;

            sample.value =
                toSrgb<Vec3, SampleSet>(brdf.getSpectrum(sample.inDir, sample.outDir), *ss);

            samples_.push_back(sample);
            ++count;
        }
    }
}

bool BrdfFitter::setParameterBounds(ceres::Problem*                    problem,
                                    double*                            parameter,
                                    const ReflectanceModel::Parameter& bounds)
{
    switch (bounds.getType()) {
        case ReflectanceModel::Parameter::FLOAT_PARAMETER:
            problem->SetParameterLowerBound(parameter, 0, *bounds.getMinFloat());
            problem->SetParameterUpperBound(parameter, 0, *bounds.getMaxFloat());
            break;
        case ReflectanceModel::Parameter::VEC3_PARAMETER: {
            const Vec3* minVec3 = bounds.getMinVec3();
            const Vec3* maxVec3 = bounds.getMaxVec3();
            problem->SetParameterLowerBound(parameter, 0, (*minVec3)[0]);
            problem->SetParameterLowerBound(parameter, 1, (*minVec3)[1]);
            problem->SetParameterLowerBound(parameter, 2, (*minVec3)[2]);
            problem->SetParameterUpperBound(parameter, 0, (*maxVec3)[0]);
            problem->SetParameterUpperBound(parameter, 1, (*maxVec3)[1]);
            problem->SetParameterUpperBound(parameter, 2, (*maxVec3)[2]);
            break;
        }
        case ReflectanceModel::Parameter::INT_PARAMETER:
            break;
        default:
            lbError << "[BrdfFitter::setParameterBounds] Invalid parameter type: " << bounds.getType();
            return false;
    }

    return true;
}

//Vec3::Scalar BrdfFitter::computeRmse(const ReflectanceModel& model, const Data& data)
//{
//    Vec3d sum = Vec3d::Zero();
//    for (auto& s : data.getSamples()) {
//        Vec3 diff = model.getBrdfValue(s.inDir, s.outDir) - s.value;
//        sum += diff.cwiseProduct(diff);
//    }
//
//    Vec3d avg = sum / data.getSamples().size();
//    Vec3d rmse = avg.cwiseSqrt();
//    return rmse.sum();
//}

Vec3::Scalar BrdfFitter::computeError(const ReflectanceModel& model, const Data& data)
{
    Vec3d sum = Vec3d::Zero();
    for (auto& s : data.getSamples()) {
        Vec3 diff = toLogScale(model.getBrdfValue(s.inDir, s.outDir)) - toLogScale(s.value);
        sum += diff.cwiseAbs();
    }

    Vec3d avg = sum / data.getSamples().size();

    return avg.sum();
}
<commit_msg>Fixed function location issues<commit_after>// =================================================================== //
// Copyright (C) 2021-2022 Kimura Ryo                                  //
//                                                                     //
// This Source Code Form is subject to the terms of the Mozilla Public //
// License, v. 2.0. If a copy of the MPL was not distributed with this //
// file, You can obtain one at http://mozilla.org/MPL/2.0/.            //
// =================================================================== //

#include <libbsdf/Fitter/BrdfFitter.h>

#include <ceres/ceres.h>

#include <libbsdf/Common/SpectrumUtility.h>
#include <libbsdf/Common/Utility.h>
#include <libbsdf/Common/Xorshift.h>

using namespace lb;

BrdfFitter::Data::Data(const Brdf& brdf, int numSampling, const Vec3::Scalar& maxTheta)
{
    const SampleSet* ss = brdf.getSampleSet();

    const Vec3::Scalar threshold = std::cos(maxTheta);

    if (numSampling <= 0 || maxTheta < toRadian(Vec3::Scalar(EPSILON_F))) {
        for (int i0 = 0; i0 < ss->getNumAngles0(); ++i0) {
        for (int i1 = 0; i1 < ss->getNumAngles1(); ++i1) {
        for (int i2 = 0; i2 < ss->getNumAngles2(); ++i2) {
        for (int i3 = 0; i3 < ss->getNumAngles3(); ++i3) {
            Vec3 inDir, outDir;
            brdf.toXyz(ss->getAngle0(i0),
                       ss->getAngle1(i1),
                       ss->getAngle2(i2),
                       ss->getAngle3(i3),
                       &inDir, &outDir);

            if (inDir[2] < threshold || outDir[2] < threshold) continue;

            Sample sample;
            sample.inDir = inDir;
            sample.outDir = outDir;
            sample.value = SpectrumUtility::toSrgb<Vec3, SampleSet>(
                brdf.getSpectrum(sample.inDir, sample.outDir), *ss);

            samples_.push_back(sample);
        }}}}
    }
    else {
        int count = 0;
        Xorshift rnd;
        while (count < numSampling) {
            Sample sample;
            sample.inDir = rnd.nextOnHemisphere<Vec3>();
            sample.outDir = rnd.nextOnHemisphere<Vec3>();

            if (sample.inDir[2] < threshold || sample.outDir[2] < threshold) continue;

            sample.value = SpectrumUtility::toSrgb<Vec3, SampleSet>(
                brdf.getSpectrum(sample.inDir, sample.outDir), *ss);

            samples_.push_back(sample);
            ++count;
        }
    }
}

bool BrdfFitter::setParameterBounds(ceres::Problem*                    problem,
                                    double*                            parameter,
                                    const ReflectanceModel::Parameter& bounds)
{
    switch (bounds.getType()) {
        case ReflectanceModel::Parameter::FLOAT_PARAMETER:
            problem->SetParameterLowerBound(parameter, 0, *bounds.getMinFloat());
            problem->SetParameterUpperBound(parameter, 0, *bounds.getMaxFloat());
            break;
        case ReflectanceModel::Parameter::VEC3_PARAMETER: {
            const Vec3* minVec3 = bounds.getMinVec3();
            const Vec3* maxVec3 = bounds.getMaxVec3();
            problem->SetParameterLowerBound(parameter, 0, (*minVec3)[0]);
            problem->SetParameterLowerBound(parameter, 1, (*minVec3)[1]);
            problem->SetParameterLowerBound(parameter, 2, (*minVec3)[2]);
            problem->SetParameterUpperBound(parameter, 0, (*maxVec3)[0]);
            problem->SetParameterUpperBound(parameter, 1, (*maxVec3)[1]);
            problem->SetParameterUpperBound(parameter, 2, (*maxVec3)[2]);
            break;
        }
        case ReflectanceModel::Parameter::INT_PARAMETER:
            break;
        default:
            lbError << "[BrdfFitter::setParameterBounds] Invalid parameter type: " << bounds.getType();
            return false;
    }

    return true;
}

//Vec3::Scalar BrdfFitter::computeRmse(const ReflectanceModel& model, const Data& data)
//{
//    Vec3d sum = Vec3d::Zero();
//    for (auto& s : data.getSamples()) {
//        Vec3 diff = model.getBrdfValue(s.inDir, s.outDir) - s.value;
//        sum += diff.cwiseProduct(diff);
//    }
//
//    Vec3d avg = sum / data.getSamples().size();
//    Vec3d rmse = avg.cwiseSqrt();
//    return rmse.sum();
//}

Vec3::Scalar BrdfFitter::computeError(const ReflectanceModel& model, const Data& data)
{
    Vec3d sum = Vec3d::Zero();
    for (auto& s : data.getSamples()) {
        Vec3 diff = toLogScale(model.getBrdfValue(s.inDir, s.outDir)) - toLogScale(s.value);
        sum += diff.cwiseAbs();
    }

    Vec3d avg = sum / data.getSamples().size();

    return avg.sum();
}
<|endoftext|>


<commit_before>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <libtorrent/alert.hpp>
#include <libtorrent/alert_types.hpp>
#include <boost/python.hpp>

using namespace boost::python;
using namespace libtorrent;

extern char const* alert_doc;
extern char const* alert_msg_doc;
extern char const* alert_severity_doc;
extern char const* torrent_alert_doc;
extern char const* tracker_alert_doc;
extern char const* tracker_error_alert_doc;
extern char const* tracker_warning_alert_doc;
extern char const* tracker_reply_alert_doc;
extern char const* tracker_announce_alert_doc;
extern char const* hash_failed_alert_doc;
extern char const* peer_ban_alert_doc;
extern char const* peer_error_alert_doc;
extern char const* invalid_request_alert_doc;
extern char const* peer_request_doc;
extern char const* torrent_finished_alert_doc;
extern char const* piece_finished_alert_doc;
extern char const* block_finished_alert_doc;
extern char const* block_downloading_alert_doc;
extern char const* storage_moved_alert_doc;
extern char const* torrent_deleted_alert_doc;
extern char const* torrent_paused_alert_doc;
extern char const* torrent_checked_alert_doc;
extern char const* url_seed_alert_doc;
extern char const* file_error_alert_doc;
extern char const* metadata_failed_alert_doc;
extern char const* metadata_received_alert_doc;
extern char const* listen_failed_alert_doc;
extern char const* listen_succeeded_alert_doc;
extern char const* portmap_error_alert_doc;
extern char const* portmap_alert_doc;
extern char const* fastresume_rejected_alert_doc;
extern char const* peer_blocked_alert_doc;
extern char const* scrape_reply_alert_doc;
extern char const* scrape_failed_alert_doc;
extern char const* udp_error_alert_doc;
extern char const* external_ip_alert_doc;
extern char const* save_resume_data_alert_doc;

void bind_alert()
{
    using boost::noncopyable;

    {
        scope alert_scope = class_<alert, noncopyable>("alert", alert_doc, no_init)
            .def(
                "msg", &alert::msg, return_value_policy<copy_const_reference>()
              , alert_msg_doc
            )
            .def("severity", &alert::severity, alert_severity_doc)
            .def(
                "__str__", &alert::msg, return_value_policy<copy_const_reference>()
              , alert_msg_doc
            )
            ;

        enum_<alert::severity_t>("severity_levels")
            .value("debug", alert::debug)
            .value("info", alert::info)
            .value("warning", alert::warning)
            .value("critical", alert::critical)
            .value("fatal", alert::fatal)
            .value("none", alert::none)
            ;
    }

    class_<torrent_alert, bases<alert>, noncopyable>(
        "torrent_alert", torrent_alert_doc, no_init
    )
        .def_readonly("handle", &torrent_alert::handle)
        ;

    class_<tracker_alert, bases<torrent_alert>, noncopyable>(
        "tracker_alert", tracker_alert_doc, no_init
    )
        .def_readonly("url", &tracker_alert::url)
        ;

    class_<tracker_error_alert, bases<tracker_alert>, noncopyable>(
        "tracker_error_alert", tracker_error_alert_doc, no_init
    )
        .def_readonly("times_in_row", &tracker_error_alert::times_in_row)
        .def_readonly("status_code", &tracker_error_alert::status_code)
        ;

    class_<tracker_warning_alert, bases<tracker_alert>, noncopyable>(
        "tracker_warning_alert", tracker_warning_alert_doc, no_init
    );

    class_<tracker_reply_alert, bases<tracker_alert>, noncopyable>(
        "tracker_reply_alert", tracker_reply_alert_doc, no_init
    )
        .def_readonly("num_peers", &tracker_reply_alert::num_peers)
        ;

    class_<tracker_announce_alert, bases<tracker_alert>, noncopyable>(
        "tracker_announce_alert", tracker_announce_alert_doc, no_init
    );

    class_<hash_failed_alert, bases<torrent_alert>, noncopyable>(
        "hash_failed_alert", hash_failed_alert_doc, no_init
    )
        .def_readonly("piece_index", &hash_failed_alert::piece_index)
        ;

    class_<peer_ban_alert, bases<torrent_alert>, noncopyable>(
        "peer_ban_alert", peer_ban_alert_doc, no_init
    )
        .def_readonly("ip", &peer_ban_alert::ip)
        ;

    class_<peer_error_alert, bases<alert>, noncopyable>(
        "peer_error_alert", peer_error_alert_doc, no_init
    )
        .def_readonly("ip", &peer_error_alert::ip)
        .def_readonly("pid", &peer_error_alert::pid)
        ;

    class_<invalid_request_alert, bases<torrent_alert>, noncopyable>(
        "invalid_request_alert", invalid_request_alert_doc, no_init
    )
        .def_readonly("ip", &invalid_request_alert::ip)
        .def_readonly("request", &invalid_request_alert::request)
        .def_readonly("pid", &invalid_request_alert::pid)
        ;

    class_<peer_request>("peer_request", peer_request_doc)
        .def_readonly("piece", &peer_request::piece)
        .def_readonly("start", &peer_request::start)
        .def_readonly("length", &peer_request::length)
        .def(self == self)
        ;

    class_<torrent_finished_alert, bases<torrent_alert>, noncopyable>(
        "torrent_finished_alert", torrent_finished_alert_doc, no_init
    );

    class_<piece_finished_alert, bases<torrent_alert>, noncopyable>(
        "piece_finished_alert", piece_finished_alert_doc, no_init
    )
        .def_readonly("piece_index", &piece_finished_alert::piece_index)
        ;

    class_<block_finished_alert, bases<torrent_alert>, noncopyable>(
        "block_finished_alert", block_finished_alert_doc, no_init
    )
        .def_readonly("block_index", &block_finished_alert::block_index)
        .def_readonly("piece_index", &block_finished_alert::piece_index)
        ;

    class_<block_downloading_alert, bases<torrent_alert>, noncopyable>(
        "block_downloading_alert", block_downloading_alert_doc, no_init
    )
        .def_readonly("peer_speedmsg", &block_downloading_alert::peer_speedmsg)
        .def_readonly("block_index", &block_downloading_alert::block_index)
        .def_readonly("piece_index", &block_downloading_alert::piece_index)
        ;

    class_<storage_moved_alert, bases<torrent_alert>, noncopyable>(
        "storage_moved_alert", storage_moved_alert_doc, no_init
    );

    class_<torrent_deleted_alert, bases<torrent_alert>, noncopyable>(
        "torrent_deleted_alert", torrent_deleted_alert_doc, no_init
    );

    class_<torrent_paused_alert, bases<torrent_alert>, noncopyable>(
        "torrent_paused_alert", torrent_paused_alert_doc, no_init
    );

    class_<torrent_checked_alert, bases<torrent_alert>, noncopyable>(
        "torrent_checked_alert", torrent_checked_alert_doc, no_init
    );

    class_<url_seed_alert, bases<torrent_alert>, noncopyable>(
        "url_seed_alert", url_seed_alert_doc, no_init
    )
        .def_readonly("url", &url_seed_alert::url)
        ;

    class_<file_error_alert, bases<torrent_alert>, noncopyable>(
        "file_error_alert", file_error_alert_doc, no_init
    )
        .def_readonly("file", &file_error_alert::file)
        ;

    class_<metadata_failed_alert, bases<torrent_alert>, noncopyable>(
        "metadata_failed_alert", metadata_failed_alert_doc, no_init
    );

    class_<metadata_received_alert, bases<torrent_alert>, noncopyable>(
        "metadata_received_alert", metadata_received_alert_doc, no_init
    );

    class_<listen_failed_alert, bases<alert>, noncopyable>(
        "listen_failed_alert", listen_failed_alert_doc, no_init
    );

    class_<listen_succeeded_alert, bases<alert>, noncopyable>(
        "listen_succeeded_alert", listen_succeeded_alert_doc, no_init
    )
        .def_readonly("endpoint", &listen_succeeded_alert::endpoint)
        ;

    class_<portmap_error_alert, bases<alert>, noncopyable>(
        "portmap_error_alert", portmap_error_alert_doc, no_init
    )
        .def_readonly("mapping", &portmap_error_alert::mapping)
        .def_readonly("type", &portmap_error_alert::type)
        ;

    class_<portmap_alert, bases<alert>, noncopyable>(
        "portmap_alert", portmap_alert_doc, no_init
    )
        .def_readonly("mapping", &portmap_alert::mapping)
        .def_readonly("external_port", &portmap_alert::external_port)
        .def_readonly("type", &portmap_alert::type)
        ;

    class_<fastresume_rejected_alert, bases<torrent_alert>, noncopyable>(
        "fastresume_rejected_alert", fastresume_rejected_alert_doc, no_init
    );

    class_<peer_blocked_alert, bases<alert>, noncopyable>(
        "peer_blocked_alert", peer_blocked_alert_doc, no_init
    )
        .def_readonly("ip", &peer_blocked_alert::ip)
        ;

    class_<scrape_reply_alert, bases<tracker_alert>, noncopyable>(
        "scrape_reply_alert", scrape_reply_alert_doc, no_init
    )
        .def_readonly("incomplete", &scrape_reply_alert::incomplete)
        .def_readonly("complete", &scrape_reply_alert::complete)
        ;

    class_<scrape_failed_alert, bases<tracker_alert>, noncopyable>(
        "scrape_failed_alert", scrape_failed_alert_doc, no_init
    );

    class_<udp_error_alert, bases<alert>, noncopyable>(
        "udp_error_alert", udp_error_alert_doc, no_init
    )
        .def_readonly("endpoint", &udp_error_alert::endpoint)
        ;

    class_<external_ip_alert, bases<alert>, noncopyable>(
        "external_ip_alert", external_ip_alert_doc, no_init
    )
        .def_readonly("external_address", &external_ip_alert::external_address)
        ;

    class_<save_resume_data_alert, bases<torrent_alert>, noncopyable>(
        "save_resume_data_alert", save_resume_data_alert_doc, no_init
    )
        .def_readonly("resume_data", &save_resume_data_alert::resume_data)
        ;

    class_<file_renamed_alert, bases<torrent_alert>, noncopyable>(
        "file_renamed_alert", no_init
    )
        .def_readonly("name", &file_renamed_alert::name)
        ;

    class_<torrent_resumed_alert, bases<torrent_alert>, noncopyable>(
        "torrent_resumed_alert", no_init
	);
}
<commit_msg>Add state_changed_alert to python bindings<commit_after>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <libtorrent/alert.hpp>
#include <libtorrent/alert_types.hpp>
#include <boost/python.hpp>

using namespace boost::python;
using namespace libtorrent;

extern char const* alert_doc;
extern char const* alert_msg_doc;
extern char const* alert_severity_doc;
extern char const* torrent_alert_doc;
extern char const* tracker_alert_doc;
extern char const* tracker_error_alert_doc;
extern char const* tracker_warning_alert_doc;
extern char const* tracker_reply_alert_doc;
extern char const* tracker_announce_alert_doc;
extern char const* hash_failed_alert_doc;
extern char const* peer_ban_alert_doc;
extern char const* peer_error_alert_doc;
extern char const* invalid_request_alert_doc;
extern char const* peer_request_doc;
extern char const* torrent_finished_alert_doc;
extern char const* piece_finished_alert_doc;
extern char const* block_finished_alert_doc;
extern char const* block_downloading_alert_doc;
extern char const* storage_moved_alert_doc;
extern char const* torrent_deleted_alert_doc;
extern char const* torrent_paused_alert_doc;
extern char const* torrent_checked_alert_doc;
extern char const* url_seed_alert_doc;
extern char const* file_error_alert_doc;
extern char const* metadata_failed_alert_doc;
extern char const* metadata_received_alert_doc;
extern char const* listen_failed_alert_doc;
extern char const* listen_succeeded_alert_doc;
extern char const* portmap_error_alert_doc;
extern char const* portmap_alert_doc;
extern char const* fastresume_rejected_alert_doc;
extern char const* peer_blocked_alert_doc;
extern char const* scrape_reply_alert_doc;
extern char const* scrape_failed_alert_doc;
extern char const* udp_error_alert_doc;
extern char const* external_ip_alert_doc;
extern char const* save_resume_data_alert_doc;

void bind_alert()
{
    using boost::noncopyable;

    {
        scope alert_scope = class_<alert, noncopyable>("alert", alert_doc, no_init)
            .def(
                "msg", &alert::msg, return_value_policy<copy_const_reference>()
              , alert_msg_doc
            )
            .def("severity", &alert::severity, alert_severity_doc)
            .def(
                "__str__", &alert::msg, return_value_policy<copy_const_reference>()
              , alert_msg_doc
            )
            ;

        enum_<alert::severity_t>("severity_levels")
            .value("debug", alert::debug)
            .value("info", alert::info)
            .value("warning", alert::warning)
            .value("critical", alert::critical)
            .value("fatal", alert::fatal)
            .value("none", alert::none)
            ;
    }

    class_<torrent_alert, bases<alert>, noncopyable>(
        "torrent_alert", torrent_alert_doc, no_init
    )
        .def_readonly("handle", &torrent_alert::handle)
        ;

    class_<tracker_alert, bases<torrent_alert>, noncopyable>(
        "tracker_alert", tracker_alert_doc, no_init
    )
        .def_readonly("url", &tracker_alert::url)
        ;

    class_<tracker_error_alert, bases<tracker_alert>, noncopyable>(
        "tracker_error_alert", tracker_error_alert_doc, no_init
    )
        .def_readonly("times_in_row", &tracker_error_alert::times_in_row)
        .def_readonly("status_code", &tracker_error_alert::status_code)
        ;

    class_<tracker_warning_alert, bases<tracker_alert>, noncopyable>(
        "tracker_warning_alert", tracker_warning_alert_doc, no_init
    );

    class_<tracker_reply_alert, bases<tracker_alert>, noncopyable>(
        "tracker_reply_alert", tracker_reply_alert_doc, no_init
    )
        .def_readonly("num_peers", &tracker_reply_alert::num_peers)
        ;

    class_<tracker_announce_alert, bases<tracker_alert>, noncopyable>(
        "tracker_announce_alert", tracker_announce_alert_doc, no_init
    );

    class_<hash_failed_alert, bases<torrent_alert>, noncopyable>(
        "hash_failed_alert", hash_failed_alert_doc, no_init
    )
        .def_readonly("piece_index", &hash_failed_alert::piece_index)
        ;

    class_<peer_ban_alert, bases<torrent_alert>, noncopyable>(
        "peer_ban_alert", peer_ban_alert_doc, no_init
    )
        .def_readonly("ip", &peer_ban_alert::ip)
        ;

    class_<peer_error_alert, bases<alert>, noncopyable>(
        "peer_error_alert", peer_error_alert_doc, no_init
    )
        .def_readonly("ip", &peer_error_alert::ip)
        .def_readonly("pid", &peer_error_alert::pid)
        ;

    class_<invalid_request_alert, bases<torrent_alert>, noncopyable>(
        "invalid_request_alert", invalid_request_alert_doc, no_init
    )
        .def_readonly("ip", &invalid_request_alert::ip)
        .def_readonly("request", &invalid_request_alert::request)
        .def_readonly("pid", &invalid_request_alert::pid)
        ;

    class_<peer_request>("peer_request", peer_request_doc)
        .def_readonly("piece", &peer_request::piece)
        .def_readonly("start", &peer_request::start)
        .def_readonly("length", &peer_request::length)
        .def(self == self)
        ;

    class_<torrent_finished_alert, bases<torrent_alert>, noncopyable>(
        "torrent_finished_alert", torrent_finished_alert_doc, no_init
    );

    class_<piece_finished_alert, bases<torrent_alert>, noncopyable>(
        "piece_finished_alert", piece_finished_alert_doc, no_init
    )
        .def_readonly("piece_index", &piece_finished_alert::piece_index)
        ;

    class_<block_finished_alert, bases<torrent_alert>, noncopyable>(
        "block_finished_alert", block_finished_alert_doc, no_init
    )
        .def_readonly("block_index", &block_finished_alert::block_index)
        .def_readonly("piece_index", &block_finished_alert::piece_index)
        ;

    class_<block_downloading_alert, bases<torrent_alert>, noncopyable>(
        "block_downloading_alert", block_downloading_alert_doc, no_init
    )
        .def_readonly("peer_speedmsg", &block_downloading_alert::peer_speedmsg)
        .def_readonly("block_index", &block_downloading_alert::block_index)
        .def_readonly("piece_index", &block_downloading_alert::piece_index)
        ;

    class_<storage_moved_alert, bases<torrent_alert>, noncopyable>(
        "storage_moved_alert", storage_moved_alert_doc, no_init
    );

    class_<torrent_deleted_alert, bases<torrent_alert>, noncopyable>(
        "torrent_deleted_alert", torrent_deleted_alert_doc, no_init
    );

    class_<torrent_paused_alert, bases<torrent_alert>, noncopyable>(
        "torrent_paused_alert", torrent_paused_alert_doc, no_init
    );

    class_<torrent_checked_alert, bases<torrent_alert>, noncopyable>(
        "torrent_checked_alert", torrent_checked_alert_doc, no_init
    );

    class_<url_seed_alert, bases<torrent_alert>, noncopyable>(
        "url_seed_alert", url_seed_alert_doc, no_init
    )
        .def_readonly("url", &url_seed_alert::url)
        ;

    class_<file_error_alert, bases<torrent_alert>, noncopyable>(
        "file_error_alert", file_error_alert_doc, no_init
    )
        .def_readonly("file", &file_error_alert::file)
        ;

    class_<metadata_failed_alert, bases<torrent_alert>, noncopyable>(
        "metadata_failed_alert", metadata_failed_alert_doc, no_init
    );

    class_<metadata_received_alert, bases<torrent_alert>, noncopyable>(
        "metadata_received_alert", metadata_received_alert_doc, no_init
    );

    class_<listen_failed_alert, bases<alert>, noncopyable>(
        "listen_failed_alert", listen_failed_alert_doc, no_init
    );

    class_<listen_succeeded_alert, bases<alert>, noncopyable>(
        "listen_succeeded_alert", listen_succeeded_alert_doc, no_init
    )
        .def_readonly("endpoint", &listen_succeeded_alert::endpoint)
        ;

    class_<portmap_error_alert, bases<alert>, noncopyable>(
        "portmap_error_alert", portmap_error_alert_doc, no_init
    )
        .def_readonly("mapping", &portmap_error_alert::mapping)
        .def_readonly("type", &portmap_error_alert::type)
        ;

    class_<portmap_alert, bases<alert>, noncopyable>(
        "portmap_alert", portmap_alert_doc, no_init
    )
        .def_readonly("mapping", &portmap_alert::mapping)
        .def_readonly("external_port", &portmap_alert::external_port)
        .def_readonly("type", &portmap_alert::type)
        ;

    class_<fastresume_rejected_alert, bases<torrent_alert>, noncopyable>(
        "fastresume_rejected_alert", fastresume_rejected_alert_doc, no_init
    );

    class_<peer_blocked_alert, bases<alert>, noncopyable>(
        "peer_blocked_alert", peer_blocked_alert_doc, no_init
    )
        .def_readonly("ip", &peer_blocked_alert::ip)
        ;

    class_<scrape_reply_alert, bases<tracker_alert>, noncopyable>(
        "scrape_reply_alert", scrape_reply_alert_doc, no_init
    )
        .def_readonly("incomplete", &scrape_reply_alert::incomplete)
        .def_readonly("complete", &scrape_reply_alert::complete)
        ;

    class_<scrape_failed_alert, bases<tracker_alert>, noncopyable>(
        "scrape_failed_alert", scrape_failed_alert_doc, no_init
    );

    class_<udp_error_alert, bases<alert>, noncopyable>(
        "udp_error_alert", udp_error_alert_doc, no_init
    )
        .def_readonly("endpoint", &udp_error_alert::endpoint)
        ;

    class_<external_ip_alert, bases<alert>, noncopyable>(
        "external_ip_alert", external_ip_alert_doc, no_init
    )
        .def_readonly("external_address", &external_ip_alert::external_address)
        ;

    class_<save_resume_data_alert, bases<torrent_alert>, noncopyable>(
        "save_resume_data_alert", save_resume_data_alert_doc, no_init
    )
        .def_readonly("resume_data", &save_resume_data_alert::resume_data)
        ;

    class_<file_renamed_alert, bases<torrent_alert>, noncopyable>(
        "file_renamed_alert", no_init
    )
        .def_readonly("name", &file_renamed_alert::name)
        ;

    class_<torrent_resumed_alert, bases<torrent_alert>, noncopyable>(
        "torrent_resumed_alert", no_init
	);

	class_<state_changed_alert, bases<torrent_alert>, noncopyable>(
	    "state_changed_alert", no_init
	)
	    .def_readonly("state", &state_changed_alert::state)
	    ;
}
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2011 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or 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
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "menudiskitem.h"
#include "popup.h"

#include <QDesktopServices>
#include <QEvent>
#include <QHBoxLayout>
#include <QUrl>
#include <QTimer>
#include <XdgIcon>
#include <Solid/StorageAccess>
#include <Solid/OpticalDrive>
#include <LXQt/Notification>
#include <QDebug>

MenuDiskItem::MenuDiskItem(Solid::Device device, Popup *popup):
    QFrame(popup),
    mPopup(popup),
    mDevice(device),
    mDiskButton(nullptr),
    mEjectButton(nullptr),
    mDiskButtonClicked(false),
    mEjectButtonClicked(false)
{
    Solid::StorageAccess * const iface = device.as<Solid::StorageAccess>();
    Q_ASSERT(nullptr != iface);

    mDiskButton = new QToolButton(this);
    mDiskButton->setObjectName("DiskButton");
    mDiskButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    mDiskButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
    connect(mDiskButton, &QToolButton::clicked, this, &MenuDiskItem::diskButtonClicked);

    mEjectButton = new QToolButton(this);
    mEjectButton->setObjectName("EjectButton");
    mEjectButton->setIcon(XdgIcon::fromTheme("media-eject"));
    connect(mEjectButton, &QToolButton::clicked, this, &MenuDiskItem::ejectButtonClicked);

    QHBoxLayout *layout = new QHBoxLayout(this);
    layout->addWidget(mDiskButton);
    layout->addWidget(mEjectButton);
    layout->setMargin(0);
    layout->setSpacing(0);
    setLayout(layout);

    connect(device.as<Solid::StorageAccess>(), &Solid::StorageAccess::setupDone,
            this, &MenuDiskItem::onMounted);

    connect(iface, &Solid::StorageAccess::setupDone, this, &MenuDiskItem::onMounted);
    connect(iface, &Solid::StorageAccess::teardownDone, this, &MenuDiskItem::onUnmounted);
    connect(iface, &Solid::StorageAccess::accessibilityChanged, [this] (bool accessible, QString const &) {
        updateMountStatus();
    });

    updateMountStatus();
}

MenuDiskItem::~MenuDiskItem()
{
}

void MenuDiskItem::setMountStatus(bool mounted)
{
    mEjectButton->setEnabled(mounted);
}

void MenuDiskItem::updateMountStatus()
{
    static const QIcon icon = XdgIcon::fromTheme(mDevice.icon(), QStringLiteral("drive-removable-media"));

    if (mDevice.isValid())
    {
        mDiskButton->setIcon(icon);
        mDiskButton->setText(mDevice.description());

        setMountStatus(mDevice.as<Solid::StorageAccess>()->isAccessible() || !opticalParent().udi().isEmpty());
    }
    else
        emit invalid(mDevice.udi());
}

Solid::Device MenuDiskItem::opticalParent() const
{
    Solid::Device it;
    if (mDevice.isValid())
    {
        it = mDevice;
        // search for parent drive
        for (; !it.udi().isEmpty(); it = it.parent())
            if (it.is<Solid::OpticalDrive>())
                break;
    }
    return it;
}

void MenuDiskItem::diskButtonClicked()
{
    mDiskButtonClicked = true;
    Solid::StorageAccess* di = mDevice.as<Solid::StorageAccess>();
    if (!di->isAccessible())
        di->setup();
    else
        onMounted(Solid::NoError, QString(), mDevice.udi());

    mPopup->hide();
}

void MenuDiskItem::ejectButtonClicked()
{
    mEjectButtonClicked = true;
    Solid::StorageAccess* di = mDevice.as<Solid::StorageAccess>();
    if (di->isAccessible())
        di->teardown();
    else
        onUnmounted(Solid::NoError, QString(), mDevice.udi());

    mPopup->hide();
}

void MenuDiskItem::onMounted(Solid::ErrorType error, QVariant resultData, const QString &udi)
{
    if (mDiskButtonClicked)
    {
        mDiskButtonClicked = false;

        if (Solid::NoError == error)
            QDesktopServices::openUrl(QUrl(mDevice.as<Solid::StorageAccess>()->filePath()));
        else
        {
            QString errorMsg = tr("Mounting of <nobr>\"%1\"</nobr> failed: %2");
            errorMsg = errorMsg.arg(mDevice.description()).arg(resultData.toString());
            LxQt::Notification::notify(tr("Removable media/devices manager"), errorMsg, mDevice.icon());
        }
    }
}

void MenuDiskItem::onUnmounted(Solid::ErrorType error, QVariant resultData, const QString &udi)
{
    if (mEjectButtonClicked)
    {
        mEjectButtonClicked = false;

        if (Solid::NoError == error)
        {
            Solid::Device opt_parent = opticalParent();
            if (!opt_parent.udi().isEmpty())
                opt_parent.as<Solid::OpticalDrive>()->eject();
        }
        else
        {
            QString errorMsg = tr("Unmounting of <nobr>\"%1\"</nobr> failed: %2");
            errorMsg = errorMsg.arg(mDevice.description()).arg(resultData.toString());
            LxQt::Notification::notify(tr("Removable media/devices manager"), errorMsg, mDevice.icon());
        }
    }
}
<commit_msg>plugin-mount: remove of doubled signal connection<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2011 Razor team
 * Authors:
 *   Petr Vanek <petr@scribus.info>
 *
 * This program or 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
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "menudiskitem.h"
#include "popup.h"

#include <QDesktopServices>
#include <QEvent>
#include <QHBoxLayout>
#include <QUrl>
#include <QTimer>
#include <XdgIcon>
#include <Solid/StorageAccess>
#include <Solid/OpticalDrive>
#include <LXQt/Notification>
#include <QDebug>

MenuDiskItem::MenuDiskItem(Solid::Device device, Popup *popup):
    QFrame(popup),
    mPopup(popup),
    mDevice(device),
    mDiskButton(nullptr),
    mEjectButton(nullptr),
    mDiskButtonClicked(false),
    mEjectButtonClicked(false)
{
    Solid::StorageAccess * const iface = device.as<Solid::StorageAccess>();
    Q_ASSERT(nullptr != iface);

    mDiskButton = new QToolButton(this);
    mDiskButton->setObjectName("DiskButton");
    mDiskButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    mDiskButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
    connect(mDiskButton, &QToolButton::clicked, this, &MenuDiskItem::diskButtonClicked);

    mEjectButton = new QToolButton(this);
    mEjectButton->setObjectName("EjectButton");
    mEjectButton->setIcon(XdgIcon::fromTheme("media-eject"));
    connect(mEjectButton, &QToolButton::clicked, this, &MenuDiskItem::ejectButtonClicked);

    QHBoxLayout *layout = new QHBoxLayout(this);
    layout->addWidget(mDiskButton);
    layout->addWidget(mEjectButton);
    layout->setMargin(0);
    layout->setSpacing(0);
    setLayout(layout);

    connect(iface, &Solid::StorageAccess::setupDone, this, &MenuDiskItem::onMounted);
    connect(iface, &Solid::StorageAccess::teardownDone, this, &MenuDiskItem::onUnmounted);
    connect(iface, &Solid::StorageAccess::accessibilityChanged, [this] (bool accessible, QString const &) {
        updateMountStatus();
    });

    updateMountStatus();
}

MenuDiskItem::~MenuDiskItem()
{
}

void MenuDiskItem::setMountStatus(bool mounted)
{
    mEjectButton->setEnabled(mounted);
}

void MenuDiskItem::updateMountStatus()
{
    static const QIcon icon = XdgIcon::fromTheme(mDevice.icon(), QStringLiteral("drive-removable-media"));

    if (mDevice.isValid())
    {
        mDiskButton->setIcon(icon);
        mDiskButton->setText(mDevice.description());

        setMountStatus(mDevice.as<Solid::StorageAccess>()->isAccessible() || !opticalParent().udi().isEmpty());
    }
    else
        emit invalid(mDevice.udi());
}

Solid::Device MenuDiskItem::opticalParent() const
{
    Solid::Device it;
    if (mDevice.isValid())
    {
        it = mDevice;
        // search for parent drive
        for (; !it.udi().isEmpty(); it = it.parent())
            if (it.is<Solid::OpticalDrive>())
                break;
    }
    return it;
}

void MenuDiskItem::diskButtonClicked()
{
    mDiskButtonClicked = true;
    Solid::StorageAccess* di = mDevice.as<Solid::StorageAccess>();
    if (!di->isAccessible())
        di->setup();
    else
        onMounted(Solid::NoError, QString(), mDevice.udi());

    mPopup->hide();
}

void MenuDiskItem::ejectButtonClicked()
{
    mEjectButtonClicked = true;
    Solid::StorageAccess* di = mDevice.as<Solid::StorageAccess>();
    if (di->isAccessible())
        di->teardown();
    else
        onUnmounted(Solid::NoError, QString(), mDevice.udi());

    mPopup->hide();
}

void MenuDiskItem::onMounted(Solid::ErrorType error, QVariant resultData, const QString &udi)
{
    if (mDiskButtonClicked)
    {
        mDiskButtonClicked = false;

        if (Solid::NoError == error)
            QDesktopServices::openUrl(QUrl(mDevice.as<Solid::StorageAccess>()->filePath()));
        else
        {
            QString errorMsg = tr("Mounting of <nobr>\"%1\"</nobr> failed: %2");
            errorMsg = errorMsg.arg(mDevice.description()).arg(resultData.toString());
            LxQt::Notification::notify(tr("Removable media/devices manager"), errorMsg, mDevice.icon());
        }
    }
}

void MenuDiskItem::onUnmounted(Solid::ErrorType error, QVariant resultData, const QString &udi)
{
    if (mEjectButtonClicked)
    {
        mEjectButtonClicked = false;

        if (Solid::NoError == error)
        {
            Solid::Device opt_parent = opticalParent();
            if (!opt_parent.udi().isEmpty())
                opt_parent.as<Solid::OpticalDrive>()->eject();
        }
        else
        {
            QString errorMsg = tr("Unmounting of <nobr>\"%1\"</nobr> failed: %2");
            errorMsg = errorMsg.arg(mDevice.description()).arg(resultData.toString());
            LxQt::Notification::notify(tr("Removable media/devices manager"), errorMsg, mDevice.icon());
        }
    }
}
<|endoftext|>