<commit_before>// Copyright (c) 2015-2016 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "validate.h"

#include <cassert>
#include <cstdio>

#include <algorithm>
#include <functional>
#include <iterator>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

#include "binary.h"
#include "diagnostic.h"
#include "enum_string_mapping.h"
#include "extensions.h"
#include "instruction.h"
#include "opcode.h"
#include "operand.h"
#include "spirv-tools/libspirv.h"
#include "spirv_constant.h"
#include "spirv_endian.h"
#include "spirv_validator_options.h"
#include "val/construct.h"
#include "val/function.h"
#include "val/validation_state.h"

using std::function;
using std::ostream_iterator;
using std::placeholders::_1;
using std::string;
using std::stringstream;
using std::transform;
using std::vector;

using libspirv::CfgPass;
using libspirv::Extension;
using libspirv::InstructionPass;
using libspirv::ModuleLayoutPass;
using libspirv::DataRulesPass;
using libspirv::IdPass;
using libspirv::ValidationState_t;

spv_result_t spvValidateIDs(const spv_instruction_t* pInsts,
                            const uint64_t count,
                            const spv_opcode_table opcodeTable,
                            const spv_operand_table operandTable,
                            const spv_ext_inst_table extInstTable,
                            const ValidationState_t& state,
                            spv_position position) {
  position->index = SPV_INDEX_INSTRUCTION;
  if (auto error =
          spvValidateInstructionIDs(pInsts, count, opcodeTable, operandTable,
                                    extInstTable, state, position))
    return error;
  return SPV_SUCCESS;
}

namespace {

// TODO(umar): Validate header
// TODO(umar): The binary parser validates the magic word, and the length of the
// header, but nothing else.
spv_result_t setHeader(void* user_data, spv_endianness_t endian, uint32_t magic,
                       uint32_t version, uint32_t generator, uint32_t id_bound,
                       uint32_t reserved) {
  // Record the ID bound so that the validator can ensure no ID is out of bound.
  ValidationState_t& _ = *(reinterpret_cast<ValidationState_t*>(user_data));
  _.setIdBound(id_bound);

  (void)endian;
  (void)magic;
  (void)version;
  (void)generator;
  (void)id_bound;
  (void)reserved;
  return SPV_SUCCESS;
}

// Improves diagnostic messages by collecting names of IDs
// NOTE: This function returns void and is not involved in validation
void DebugInstructionPass(ValidationState_t& _,
                          const spv_parsed_instruction_t* inst) {
  switch (inst->opcode) {
    case SpvOpName: {
      const uint32_t target = *(inst->words + inst->operands[0].offset);
      const char* str =
          reinterpret_cast<const char*>(inst->words + inst->operands[1].offset);
      _.AssignNameToId(target, str);
    } break;
    case SpvOpMemberName: {
      const uint32_t target = *(inst->words + inst->operands[0].offset);
      const char* str =
          reinterpret_cast<const char*>(inst->words + inst->operands[2].offset);
      _.AssignNameToId(target, str);
    } break;
    case SpvOpSourceContinued:
    case SpvOpSource:
    case SpvOpSourceExtension:
    case SpvOpString:
    case SpvOpLine:
    case SpvOpNoLine:

    default:
      break;
  }
}

// Parses OpExtension instruction and registers extension.
void RegisterExtension(ValidationState_t& _,
                       const spv_parsed_instruction_t* inst) {
  const std::string extension_str = libspirv::GetExtensionString(inst);
  Extension extension;
  if (!GetExtensionFromString(extension_str, &extension)) {
    // The error will be logged in the ProcessInstruction pass.
    return;
  }

  _.RegisterExtension(extension);
}

// Parses the beginning of the module searching for OpExtension instructions.
// Registers extensions if recognized. Returns SPV_REQUESTED_TERMINATION
// once an instruction which is not SpvOpCapability and SpvOpExtension is
// encountered. According to the SPIR-V spec extensions are declared after
// capabilities and before everything else.
spv_result_t ProcessExtensions(
    void* user_data, const spv_parsed_instruction_t* inst) {
  const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
  if (opcode == SpvOpCapability)
    return SPV_SUCCESS;

  if (opcode == SpvOpExtension) {
    ValidationState_t& _ = *(reinterpret_cast<ValidationState_t*>(user_data));
    RegisterExtension(_, inst);
    return SPV_SUCCESS;
  }

  // OpExtension block is finished, requesting termination.
  return SPV_REQUESTED_TERMINATION;
}

spv_result_t ProcessInstruction(void* user_data,
                                const spv_parsed_instruction_t* inst) {
  ValidationState_t& _ = *(reinterpret_cast<ValidationState_t*>(user_data));
  _.increment_instruction_count();
  if (static_cast<SpvOp>(inst->opcode) == SpvOpEntryPoint) {
    const auto entry_point = inst->words[2];
    _.RegisterEntryPointId(entry_point);
    // Operand 3 and later are the <id> of interfaces for the entry point.
    for (int i = 3; i < inst->num_operands; ++i) {
      _.RegisterInterfaceForEntryPoint(entry_point,
                                       inst->words[inst->operands[i].offset]);
    }
  }
  if (static_cast<SpvOp>(inst->opcode) == SpvOpFunctionCall) {
    _.AddFunctionCallTarget(inst->words[3]);
  }

  DebugInstructionPass(_, inst);
  if (auto error = CapabilityPass(_, inst)) return error;
  if (auto error = DataRulesPass(_, inst)) return error;
  if (auto error = IdPass(_, inst)) return error;
  if (auto error = ModuleLayoutPass(_, inst)) return error;
  if (auto error = CfgPass(_, inst)) return error;
  if (auto error = InstructionPass(_, inst)) return error;
  if (auto error = TypeUniquePass(_, inst)) return error;

  return SPV_SUCCESS;
}

void printDot(const ValidationState_t& _, const libspirv::BasicBlock& other) {
  string block_string;
  if (other.successors()->empty()) {
    block_string += "end ";
  } else {
    for (auto block : *other.successors()) {
      block_string += _.getIdOrName(block->id()) + " ";
    }
  }
  printf("%10s -> {%s\b}\n", _.getIdOrName(other.id()).c_str(),
         block_string.c_str());
}

void PrintBlocks(ValidationState_t& _, libspirv::Function func) {
  assert(func.first_block());

  printf("%10s -> %s\n", _.getIdOrName(func.id()).c_str(),
         _.getIdOrName(func.first_block()->id()).c_str());
  for (const auto& block : func.ordered_blocks()) {
    printDot(_, *block);
  }
}

#ifdef __clang__
#define UNUSED(func) [[gnu::unused]] func
#elif defined(__GNUC__)
#define UNUSED(func)            \
  func __attribute__((unused)); \
  func
#elif defined(_MSC_VER)
#define UNUSED(func) func
#endif

UNUSED(void PrintDotGraph(ValidationState_t& _, libspirv::Function func)) {
  if (func.first_block()) {
    string func_name(_.getIdOrName(func.id()));
    printf("digraph %s {\n", func_name.c_str());
    PrintBlocks(_, func);
    printf("}\n");
  }
}
}  // anonymous namespace

spv_result_t spvValidate(const spv_const_context context,
                         const spv_const_binary binary,
                         spv_diagnostic* pDiagnostic) {
  return spvValidateBinary(context, binary->code, binary->wordCount,
                           pDiagnostic);
}

spv_result_t ValidateBinaryUsingContextAndValidationState(
    const spv_context_t& context, const uint32_t* words, const size_t num_words,
    spv_diagnostic* pDiagnostic, ValidationState_t* vstate) {
  auto binary = std::unique_ptr<spv_const_binary_t>(
    new spv_const_binary_t{words, num_words});

  spv_endianness_t endian;
  spv_position_t position = {};
  if (spvBinaryEndianness(binary.get(), &endian)) {
    return libspirv::DiagnosticStream(position, context.consumer,
                                      SPV_ERROR_INVALID_BINARY)
           << "Invalid SPIR-V magic number.";
  }

  spv_header_t header;
  if (spvBinaryHeaderGet(binary.get(), endian, &header)) {
    return libspirv::DiagnosticStream(position, context.consumer,
                                      SPV_ERROR_INVALID_BINARY)
           << "Invalid SPIR-V header.";
  }

  // Look for OpExtension instructions and register extensions.
  // Diagnostics if any will be produced in the next pass (ProcessInstruction).
  spvBinaryParse(&context, vstate, words, num_words,
                 /* parsed_header = */ nullptr, ProcessExtensions,
                 /* diagnostic = */ nullptr);

  // NOTE: Parse the module and perform inline validation checks. These
  // checks do not require the the knowledge of the whole module.
  if (auto error = spvBinaryParse(&context, vstate, words, num_words,
                                  setHeader, ProcessInstruction, pDiagnostic))
    return error;

  if (vstate->in_function_body())
    return vstate->diag(SPV_ERROR_INVALID_LAYOUT)
           << "Missing OpFunctionEnd at end of module.";

  // TODO(umar): Add validation checks which require the parsing of the entire
  // module. Use the information from the ProcessInstruction pass to make the
  // checks.
  if (vstate->unresolved_forward_id_count() > 0) {
    stringstream ss;
    vector<uint32_t> ids = vstate->UnresolvedForwardIds();

    transform(begin(ids), end(ids), ostream_iterator<string>(ss, " "),
              bind(&ValidationState_t::getIdName, std::ref(*vstate), _1));

    auto id_str = ss.str();
    return vstate->diag(SPV_ERROR_INVALID_ID)
           << "The following forward referenced IDs have not been defined:\n"
           << id_str.substr(0, id_str.size() - 1);
  }

  // CFG checks are performed after the binary has been parsed
  // and the CFGPass has collected information about the control flow
  if (auto error = PerformCfgChecks(*vstate)) return error;
  if (auto error = UpdateIdUse(*vstate)) return error;
  if (auto error = CheckIdDefinitionDominateUse(*vstate)) return error;
  if (auto error = ValidateDecorations(*vstate))  return error;

  // Entry point validation. Based on 2.16.1 (Universal Validation Rules) of the
  // SPIRV spec:
  // * There is at least one OpEntryPoint instruction, unless the Linkage
  // capability is being used.
  // * No function can be targeted by both an OpEntryPoint instruction and an
  // OpFunctionCall instruction.
  if (vstate->entry_points().empty() &&
      !vstate->HasCapability(SpvCapabilityLinkage)) {
    return vstate->diag(SPV_ERROR_INVALID_BINARY)
           << "No OpEntryPoint instruction was found. This is only allowed if "
              "the Linkage capability is being used.";
  }
  for (const auto& entry_point : vstate->entry_points()) {
    if (vstate->IsFunctionCallTarget(entry_point)) {
      return vstate->diag(SPV_ERROR_INVALID_BINARY)
             << "A function (" << entry_point
             << ") may not be targeted by both an OpEntryPoint instruction and "
                "an OpFunctionCall instruction.";
    }
  }

  // NOTE: Copy each instruction for easier processing
  std::vector<spv_instruction_t> instructions;
  uint64_t index = SPV_INDEX_INSTRUCTION;
  while (index < binary->wordCount) {
    uint16_t wordCount;
    uint16_t opcode;
    spvOpcodeSplit(spvFixWord(binary->code[index], endian), &wordCount,
                   &opcode);
    spv_instruction_t inst;
    spvInstructionCopy(&binary->code[index], static_cast<SpvOp>(opcode),
                       wordCount, endian, &inst);
    instructions.push_back(inst);
    index += wordCount;
  }

  position.index = SPV_INDEX_INSTRUCTION;
  return spvValidateIDs(instructions.data(), instructions.size(),
                        context.opcode_table,
                        context.operand_table,
                        context.ext_inst_table, *vstate, &position);
}

spv_result_t spvValidateBinary(const spv_const_context context,
                               const uint32_t* words, const size_t num_words,
                               spv_diagnostic* pDiagnostic) {
  spv_context_t hijack_context = *context;
  if (pDiagnostic) {
    *pDiagnostic = nullptr;
    libspirv::UseDiagnosticAsMessageConsumer(&hijack_context, pDiagnostic);
  }

  // This interface is used for default command line options.
  spv_validator_options default_options = spvValidatorOptionsCreate();

  // Create the ValidationState using the context and default options.
  ValidationState_t vstate(&hijack_context, default_options);

  spv_result_t result = ValidateBinaryUsingContextAndValidationState(
      hijack_context, words, num_words, pDiagnostic, &vstate);

  spvValidatorOptionsDestroy(default_options);
  return result;
}

spv_result_t spvValidateWithOptions(const spv_const_context context,
                                    spv_const_validator_options options,
                                    const spv_const_binary binary,
                                    spv_diagnostic* pDiagnostic) {
  spv_context_t hijack_context = *context;
  if (pDiagnostic) {
    *pDiagnostic = nullptr;
    libspirv::UseDiagnosticAsMessageConsumer(&hijack_context, pDiagnostic);
  }

  // Create the ValidationState using the context.
  ValidationState_t vstate(&hijack_context, options);

  return ValidateBinaryUsingContextAndValidationState(
      hijack_context, binary->code, binary->wordCount, pDiagnostic, &vstate);
}

namespace spvtools {

spv_result_t ValidateBinaryAndKeepValidationState(
    const spv_const_context context, spv_const_validator_options options,
    const uint32_t* words, const size_t num_words, spv_diagnostic* pDiagnostic,
    std::unique_ptr<ValidationState_t>* vstate) {
  spv_context_t hijack_context = *context;
  if (pDiagnostic) {
    *pDiagnostic = nullptr;
    libspirv::UseDiagnosticAsMessageConsumer(&hijack_context, pDiagnostic);
  }

  vstate->reset(new ValidationState_t(&hijack_context, options));

  return ValidateBinaryUsingContextAndValidationState(
      hijack_context, words, num_words, pDiagnostic, vstate->get());
}

spv_result_t ValidateInstructionAndUpdateValidationState(
    ValidationState_t* vstate, const spv_parsed_instruction_t* inst) {
  return ProcessInstruction(vstate, inst);
}

}  // namespace spvtools
<commit_msg>Reserve expected length of instructions vector<commit_after>// Copyright (c) 2015-2016 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "validate.h"

#include <cassert>
#include <cstdio>

#include <algorithm>
#include <functional>
#include <iterator>
#include <memory>
#include <sstream>
#include <string>
#include <vector>

#include "binary.h"
#include "diagnostic.h"
#include "enum_string_mapping.h"
#include "extensions.h"
#include "instruction.h"
#include "opcode.h"
#include "operand.h"
#include "spirv-tools/libspirv.h"
#include "spirv_constant.h"
#include "spirv_endian.h"
#include "spirv_validator_options.h"
#include "val/construct.h"
#include "val/function.h"
#include "val/validation_state.h"

using std::function;
using std::ostream_iterator;
using std::placeholders::_1;
using std::string;
using std::stringstream;
using std::transform;
using std::vector;

using libspirv::CfgPass;
using libspirv::Extension;
using libspirv::InstructionPass;
using libspirv::ModuleLayoutPass;
using libspirv::DataRulesPass;
using libspirv::IdPass;
using libspirv::ValidationState_t;

spv_result_t spvValidateIDs(const spv_instruction_t* pInsts,
                            const uint64_t count,
                            const spv_opcode_table opcodeTable,
                            const spv_operand_table operandTable,
                            const spv_ext_inst_table extInstTable,
                            const ValidationState_t& state,
                            spv_position position) {
  position->index = SPV_INDEX_INSTRUCTION;
  if (auto error =
          spvValidateInstructionIDs(pInsts, count, opcodeTable, operandTable,
                                    extInstTable, state, position))
    return error;
  return SPV_SUCCESS;
}

namespace {

// TODO(umar): Validate header
// TODO(umar): The binary parser validates the magic word, and the length of the
// header, but nothing else.
spv_result_t setHeader(void* user_data, spv_endianness_t endian, uint32_t magic,
                       uint32_t version, uint32_t generator, uint32_t id_bound,
                       uint32_t reserved) {
  // Record the ID bound so that the validator can ensure no ID is out of bound.
  ValidationState_t& _ = *(reinterpret_cast<ValidationState_t*>(user_data));
  _.setIdBound(id_bound);

  (void)endian;
  (void)magic;
  (void)version;
  (void)generator;
  (void)id_bound;
  (void)reserved;
  return SPV_SUCCESS;
}

// Improves diagnostic messages by collecting names of IDs
// NOTE: This function returns void and is not involved in validation
void DebugInstructionPass(ValidationState_t& _,
                          const spv_parsed_instruction_t* inst) {
  switch (inst->opcode) {
    case SpvOpName: {
      const uint32_t target = *(inst->words + inst->operands[0].offset);
      const char* str =
          reinterpret_cast<const char*>(inst->words + inst->operands[1].offset);
      _.AssignNameToId(target, str);
    } break;
    case SpvOpMemberName: {
      const uint32_t target = *(inst->words + inst->operands[0].offset);
      const char* str =
          reinterpret_cast<const char*>(inst->words + inst->operands[2].offset);
      _.AssignNameToId(target, str);
    } break;
    case SpvOpSourceContinued:
    case SpvOpSource:
    case SpvOpSourceExtension:
    case SpvOpString:
    case SpvOpLine:
    case SpvOpNoLine:

    default:
      break;
  }
}

// Parses OpExtension instruction and registers extension.
void RegisterExtension(ValidationState_t& _,
                       const spv_parsed_instruction_t* inst) {
  const std::string extension_str = libspirv::GetExtensionString(inst);
  Extension extension;
  if (!GetExtensionFromString(extension_str, &extension)) {
    // The error will be logged in the ProcessInstruction pass.
    return;
  }

  _.RegisterExtension(extension);
}

// Parses the beginning of the module searching for OpExtension instructions.
// Registers extensions if recognized. Returns SPV_REQUESTED_TERMINATION
// once an instruction which is not SpvOpCapability and SpvOpExtension is
// encountered. According to the SPIR-V spec extensions are declared after
// capabilities and before everything else.
spv_result_t ProcessExtensions(
    void* user_data, const spv_parsed_instruction_t* inst) {
  const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
  if (opcode == SpvOpCapability)
    return SPV_SUCCESS;

  if (opcode == SpvOpExtension) {
    ValidationState_t& _ = *(reinterpret_cast<ValidationState_t*>(user_data));
    RegisterExtension(_, inst);
    return SPV_SUCCESS;
  }

  // OpExtension block is finished, requesting termination.
  return SPV_REQUESTED_TERMINATION;
}

spv_result_t ProcessInstruction(void* user_data,
                                const spv_parsed_instruction_t* inst) {
  ValidationState_t& _ = *(reinterpret_cast<ValidationState_t*>(user_data));
  _.increment_instruction_count();
  if (static_cast<SpvOp>(inst->opcode) == SpvOpEntryPoint) {
    const auto entry_point = inst->words[2];
    _.RegisterEntryPointId(entry_point);
    // Operand 3 and later are the <id> of interfaces for the entry point.
    for (int i = 3; i < inst->num_operands; ++i) {
      _.RegisterInterfaceForEntryPoint(entry_point,
                                       inst->words[inst->operands[i].offset]);
    }
  }
  if (static_cast<SpvOp>(inst->opcode) == SpvOpFunctionCall) {
    _.AddFunctionCallTarget(inst->words[3]);
  }

  DebugInstructionPass(_, inst);
  if (auto error = CapabilityPass(_, inst)) return error;
  if (auto error = DataRulesPass(_, inst)) return error;
  if (auto error = IdPass(_, inst)) return error;
  if (auto error = ModuleLayoutPass(_, inst)) return error;
  if (auto error = CfgPass(_, inst)) return error;
  if (auto error = InstructionPass(_, inst)) return error;
  if (auto error = TypeUniquePass(_, inst)) return error;

  return SPV_SUCCESS;
}

void printDot(const ValidationState_t& _, const libspirv::BasicBlock& other) {
  string block_string;
  if (other.successors()->empty()) {
    block_string += "end ";
  } else {
    for (auto block : *other.successors()) {
      block_string += _.getIdOrName(block->id()) + " ";
    }
  }
  printf("%10s -> {%s\b}\n", _.getIdOrName(other.id()).c_str(),
         block_string.c_str());
}

void PrintBlocks(ValidationState_t& _, libspirv::Function func) {
  assert(func.first_block());

  printf("%10s -> %s\n", _.getIdOrName(func.id()).c_str(),
         _.getIdOrName(func.first_block()->id()).c_str());
  for (const auto& block : func.ordered_blocks()) {
    printDot(_, *block);
  }
}

#ifdef __clang__
#define UNUSED(func) [[gnu::unused]] func
#elif defined(__GNUC__)
#define UNUSED(func)            \
  func __attribute__((unused)); \
  func
#elif defined(_MSC_VER)
#define UNUSED(func) func
#endif

UNUSED(void PrintDotGraph(ValidationState_t& _, libspirv::Function func)) {
  if (func.first_block()) {
    string func_name(_.getIdOrName(func.id()));
    printf("digraph %s {\n", func_name.c_str());
    PrintBlocks(_, func);
    printf("}\n");
  }
}
}  // anonymous namespace

spv_result_t spvValidate(const spv_const_context context,
                         const spv_const_binary binary,
                         spv_diagnostic* pDiagnostic) {
  return spvValidateBinary(context, binary->code, binary->wordCount,
                           pDiagnostic);
}

spv_result_t ValidateBinaryUsingContextAndValidationState(
    const spv_context_t& context, const uint32_t* words, const size_t num_words,
    spv_diagnostic* pDiagnostic, ValidationState_t* vstate) {
  auto binary = std::unique_ptr<spv_const_binary_t>(
    new spv_const_binary_t{words, num_words});

  spv_endianness_t endian;
  spv_position_t position = {};
  if (spvBinaryEndianness(binary.get(), &endian)) {
    return libspirv::DiagnosticStream(position, context.consumer,
                                      SPV_ERROR_INVALID_BINARY)
           << "Invalid SPIR-V magic number.";
  }

  spv_header_t header;
  if (spvBinaryHeaderGet(binary.get(), endian, &header)) {
    return libspirv::DiagnosticStream(position, context.consumer,
                                      SPV_ERROR_INVALID_BINARY)
           << "Invalid SPIR-V header.";
  }

  // Look for OpExtension instructions and register extensions.
  // Diagnostics if any will be produced in the next pass (ProcessInstruction).
  spvBinaryParse(&context, vstate, words, num_words,
                 /* parsed_header = */ nullptr, ProcessExtensions,
                 /* diagnostic = */ nullptr);

  // NOTE: Parse the module and perform inline validation checks. These
  // checks do not require the the knowledge of the whole module.
  if (auto error = spvBinaryParse(&context, vstate, words, num_words,
                                  setHeader, ProcessInstruction, pDiagnostic))
    return error;

  if (vstate->in_function_body())
    return vstate->diag(SPV_ERROR_INVALID_LAYOUT)
           << "Missing OpFunctionEnd at end of module.";

  // TODO(umar): Add validation checks which require the parsing of the entire
  // module. Use the information from the ProcessInstruction pass to make the
  // checks.
  if (vstate->unresolved_forward_id_count() > 0) {
    stringstream ss;
    vector<uint32_t> ids = vstate->UnresolvedForwardIds();

    transform(begin(ids), end(ids), ostream_iterator<string>(ss, " "),
              bind(&ValidationState_t::getIdName, std::ref(*vstate), _1));

    auto id_str = ss.str();
    return vstate->diag(SPV_ERROR_INVALID_ID)
           << "The following forward referenced IDs have not been defined:\n"
           << id_str.substr(0, id_str.size() - 1);
  }

  // CFG checks are performed after the binary has been parsed
  // and the CFGPass has collected information about the control flow
  if (auto error = PerformCfgChecks(*vstate)) return error;
  if (auto error = UpdateIdUse(*vstate)) return error;
  if (auto error = CheckIdDefinitionDominateUse(*vstate)) return error;
  if (auto error = ValidateDecorations(*vstate))  return error;

  // Entry point validation. Based on 2.16.1 (Universal Validation Rules) of the
  // SPIRV spec:
  // * There is at least one OpEntryPoint instruction, unless the Linkage
  // capability is being used.
  // * No function can be targeted by both an OpEntryPoint instruction and an
  // OpFunctionCall instruction.
  if (vstate->entry_points().empty() &&
      !vstate->HasCapability(SpvCapabilityLinkage)) {
    return vstate->diag(SPV_ERROR_INVALID_BINARY)
           << "No OpEntryPoint instruction was found. This is only allowed if "
              "the Linkage capability is being used.";
  }
  for (const auto& entry_point : vstate->entry_points()) {
    if (vstate->IsFunctionCallTarget(entry_point)) {
      return vstate->diag(SPV_ERROR_INVALID_BINARY)
             << "A function (" << entry_point
             << ") may not be targeted by both an OpEntryPoint instruction and "
                "an OpFunctionCall instruction.";
    }
  }

  // NOTE: Copy each instruction for easier processing
  std::vector<spv_instruction_t> instructions;
  // Expect average instruction length to be a bit over 2 words.
  instructions.reserve(binary->wordCount / 2);
  uint64_t index = SPV_INDEX_INSTRUCTION;
  while (index < binary->wordCount) {
    uint16_t wordCount;
    uint16_t opcode;
    spvOpcodeSplit(spvFixWord(binary->code[index], endian), &wordCount,
                   &opcode);
    spv_instruction_t inst;
    spvInstructionCopy(&binary->code[index], static_cast<SpvOp>(opcode),
                       wordCount, endian, &inst);
    instructions.push_back(inst);
    index += wordCount;
  }

  position.index = SPV_INDEX_INSTRUCTION;
  return spvValidateIDs(instructions.data(), instructions.size(),
                        context.opcode_table,
                        context.operand_table,
                        context.ext_inst_table, *vstate, &position);
}

spv_result_t spvValidateBinary(const spv_const_context context,
                               const uint32_t* words, const size_t num_words,
                               spv_diagnostic* pDiagnostic) {
  spv_context_t hijack_context = *context;
  if (pDiagnostic) {
    *pDiagnostic = nullptr;
    libspirv::UseDiagnosticAsMessageConsumer(&hijack_context, pDiagnostic);
  }

  // This interface is used for default command line options.
  spv_validator_options default_options = spvValidatorOptionsCreate();

  // Create the ValidationState using the context and default options.
  ValidationState_t vstate(&hijack_context, default_options);

  spv_result_t result = ValidateBinaryUsingContextAndValidationState(
      hijack_context, words, num_words, pDiagnostic, &vstate);

  spvValidatorOptionsDestroy(default_options);
  return result;
}

spv_result_t spvValidateWithOptions(const spv_const_context context,
                                    spv_const_validator_options options,
                                    const spv_const_binary binary,
                                    spv_diagnostic* pDiagnostic) {
  spv_context_t hijack_context = *context;
  if (pDiagnostic) {
    *pDiagnostic = nullptr;
    libspirv::UseDiagnosticAsMessageConsumer(&hijack_context, pDiagnostic);
  }

  // Create the ValidationState using the context.
  ValidationState_t vstate(&hijack_context, options);

  return ValidateBinaryUsingContextAndValidationState(
      hijack_context, binary->code, binary->wordCount, pDiagnostic, &vstate);
}

namespace spvtools {

spv_result_t ValidateBinaryAndKeepValidationState(
    const spv_const_context context, spv_const_validator_options options,
    const uint32_t* words, const size_t num_words, spv_diagnostic* pDiagnostic,
    std::unique_ptr<ValidationState_t>* vstate) {
  spv_context_t hijack_context = *context;
  if (pDiagnostic) {
    *pDiagnostic = nullptr;
    libspirv::UseDiagnosticAsMessageConsumer(&hijack_context, pDiagnostic);
  }

  vstate->reset(new ValidationState_t(&hijack_context, options));

  return ValidateBinaryUsingContextAndValidationState(
      hijack_context, words, num_words, pDiagnostic, vstate->get());
}

spv_result_t ValidateInstructionAndUpdateValidationState(
    ValidationState_t* vstate, const spv_parsed_instruction_t* inst) {
  return ProcessInstruction(vstate, inst);
}

}  // namespace spvtools
<|endoftext|>


<commit_before>#include "mesh_def.h"
#include <vcg/complex/algorithms/inertia.h>
#include <vcg/complex/algorithms/stat.h>
#include <vcg/complex/algorithms/point_sampling.h>
#include<vcg/complex/algorithms/voronoi_volume_sampling.h>

using namespace vcg;
using namespace std;

void ComputeGeometricMeasures(uintptr_t meshPtr)
{
    MyMesh &m = *((MyMesh*) meshPtr);

    printf("Geometric measures:\n");

    tri::UpdateBounding<MyMesh>::Box(m);
    printf("Mesh Bounding Box size %f %f %f\n", m.bbox.DimX(), m.bbox.DimY(), m.bbox.DimZ());
    printf("Mesh Bounding Box diag %f\n", m.bbox.Diag());

    tri::Inertia<MyMesh> I(m);
    float volume = I.Mass();
    float area = tri::Stat<MyMesh>::ComputeMeshArea(m);
    printf("Mesh volume %f\n", volume);
    printf("Mesh surface is %f\n", area);

    Point3f bc = tri::Stat<MyMesh>::ComputeShellBarycenter(m);
    printf("Thin shell barycenter %9.6f  %9.6f  %9.6f\n", bc[0], bc[1], bc[2]);

    if (volume <= 0) {
        printf("Volume is negative, Mesh is not 'solid' (non manifold, non watertight, non consistently oriented)\n"
               "No information on barycenter and inertia tensor can be reported\n");
    } else {
        printf("Center of mass is %f %f %f\n", I.CenterOfMass()[0], I.CenterOfMass()[1], I.CenterOfMass()[2]);
        Matrix33f it;
        I.InertiaTensor(it);
        printf("Inertia tensor is: \n");
        printf("  | %9.6f  %9.6f  %9.6f |\n", it[0][0], it[0][1], it[0][2]);
        printf("  | %9.6f  %9.6f  %9.6f |\n", it[1][0], it[1][1], it[1][2]);
        printf("  | %9.6f  %9.6f  %9.6f |\n", it[2][0], it[2][1], it[2][2]);

        Matrix33f pca;
        Point3f pcav;
        I.InertiaTensorEigen(pca, pcav);
        printf("Principal axes are :\n");
        printf("  | %9.6f  %9.6f  %9.6f |\n", pca[0][0], pca[0][1], pca[0][2]);
        printf("  | %9.6f  %9.6f  %9.6f |\n", pca[1][0], pca[1][1], pca[1][2]);
        printf("  | %9.6f  %9.6f  %9.6f |\n", pca[2][0], pca[2][1], pca[2][2]);

        printf("Axes momenta are :\n");
        printf("  | %9.6f  %9.6f  %9.6f |\n", pcav[0], pcav[1], pcav[2]);
    }
}

void ComputeTopologicalMeasures(uintptr_t meshPtr)
{
    MyMesh &m = *((MyMesh*) meshPtr);

    printf("Topological measures:\n");
    tri::UpdateTopology<MyMesh>::FaceFace(m);

    int nonManifEdgeNumFF = tri::Clean<MyMesh>::CountNonManifoldEdgeFF(m, true);
    int faceEdgeNonManif = tri::UpdateSelection<MyMesh>::FaceCount(m);
    tri::UpdateSelection<MyMesh>::VertexClear(m);
    tri::UpdateSelection<MyMesh>::FaceClear(m);

    int nonManifVertNum = tri::Clean<MyMesh>::CountNonManifoldVertexFF(m, true);
    tri::UpdateSelection<MyMesh>::FaceFromVertexLoose(m);
    int faceVertNonManif = tri::UpdateSelection<MyMesh>::FaceCount(m);
    int edgeNum = 0, borderNum = 0, nonManifEdgeNum = 0;
    tri::Clean<MyMesh>::CountEdgeNum(m, edgeNum, borderNum, nonManifEdgeNum);
    printf("V: %6i E: %6i F:%6i\n", m.vn, edgeNum, m.fn);
    int unrefVertNum = tri::Clean<MyMesh>::CountUnreferencedVertex(m);
    printf("Unreferenced vertices %i\n", unrefVertNum);
    printf("Boundary edges %i\n", borderNum);

    int connectedComponentsNum = tri::Clean<MyMesh>::CountConnectedComponents(m);
    printf("Mesh is composed by %i connected component(s)\n", connectedComponentsNum);

    if (nonManifEdgeNumFF == 0 && nonManifVertNum == 0) {
        printf("Mesh is two-manifold\n");
    }

    if (nonManifEdgeNumFF != 0) printf("Mesh has %i non two manifold edges and %i faces are incident on these edges\n", nonManifEdgeNumFF, faceEdgeNonManif);

    if (nonManifVertNum != 0) printf("Mesh has %i non two manifold vertexes and %i faces are incident on these vertices\n", nonManifVertNum, faceVertNonManif);

    // For Manifold meshes compute some other stuff
    if (nonManifVertNum == 0 && nonManifEdgeNumFF == 0) {
        int holeNum = tri::Clean<MyMesh>::CountHoles(m);
        printf("Mesh has %i holes\n", holeNum);
        int genus = tri::Clean<MyMesh>::MeshGenus(m.vn-unrefVertNum, edgeNum, m.fn, holeNum, connectedComponentsNum);
        printf("Genus is %i\n", genus);
    } else {
        printf("Mesh has a undefined number of holes (non 2-manifold mesh)\n");
        printf("Genus is undefined (non 2-manifold mesh)\n");
    }
    tri::UpdateSelection<MyMesh>::VertexClear(m);
    tri::UpdateSelection<MyMesh>::FaceClear(m);
}

void ComputeHausdorffDistance(uintptr_t srcPtr, uintptr_t trgPtr, uintptr_t _sampleMeshPtr, int sampleNum, float distUpperBound)
{
  MyMesh &src = *((MyMesh*) srcPtr);
  MyMesh &trg = *((MyMesh*) trgPtr);
  MyMesh *sampleMeshPtr = ((MyMesh*) _sampleMeshPtr);

  HausdorffSampler<MyMesh> hs(&trg);
  hs.dist_upper_bound = distUpperBound;
  hs.init(sampleMeshPtr,0);
  printf("Sampled  mesh has %7i vert %7i face\n",src.vn,src.fn);
  printf("Searched mesh has %7i vert %7i face\n",trg.vn,trg.fn);
  printf("Max sampling distance %f on a bbox diag of %f\n",distUpperBound,trg.bbox.Diag());

  tri::SurfaceSampling<MyMesh,HausdorffSampler<MyMesh> >::VertexUniform(src,hs,sampleNum);
  tri::SurfaceSampling<MyMesh,HausdorffSampler<MyMesh> >::Montecarlo(src,hs,sampleNum);

  printf("Hausdorff Distance computed\n");
  printf("     Sampled %i pts (rng: 0)  on %s searched closest on %s \n",hs.n_total_samples,src.meshName.c_str(),trg.meshName.c_str());
  printf("     min : %f   max %f   mean : %f   RMS : %f \n",hs.getMinDist(),hs.getMaxDist(),hs.getMeanDist(),hs.getRMSDist());
  float d = src.bbox.Diag();
  printf("Values w.r.t. BBox Diag (%f)\n",d);
  printf("     min : %f   max %f   mean : %f   RMS : %f\n",hs.getMinDist()/d,hs.getMaxDist()/d,hs.getMeanDist()/d,hs.getRMSDist()/d);

  if(sampleMeshPtr)
  {
    printf("Created Sample Mesh with %i samples\n",sampleMeshPtr->vn);
  }
}

void ComputeQualityFromCurvature(uintptr_t meshPtr, int curvatureMode)
{
    MyMesh &m = *((MyMesh*) meshPtr);
    tri::UpdateCurvature<MyMesh>::MeanAndGaussian(m);
    if(curvatureMode==0)
    {
      tri::UpdateQuality<MyMesh>::VertexFromGaussianCurvatureHG(m);
      printf("Computed Gaussian Curvature\n");
    }
    else
    {
      tri::UpdateQuality<MyMesh>::VertexFromMeanCurvatureHG(m);
      printf("Computed Mean Curvature\n");
    }
}

bool ComputeThickness(uintptr_t meshPtr, uintptr_t trgPtr, uintptr_t volPtr, uintptr_t skelPtr,
                      int montecarloSampleNum, float surfSamplingRadius, float distThr)
{
  MyMesh &baseM = *((MyMesh*) meshPtr);
  MyMesh *surfSamp = ((MyMesh*) trgPtr);
  MyMesh  *volSamp = ((MyMesh*) volPtr);
  MyMesh   *skelM = ((MyMesh*) skelPtr);
  if(!tri::Clean<MyMesh>::IsWaterTight(baseM))
  {
    printf("Volume Sampling Requires Watertight Mesh. Nothing Done.\n");
    return false;
  }

  MyMesh pVm; // unused...
  tri::VoronoiVolumeSampling<MyMesh> vvs(baseM, pVm);
  float poissonRadiusSurface = baseM.bbox.Diag()*surfSamplingRadius;
  int t0=clock();
  vvs.Init(poissonRadiusSurface);
  vvs.BuildMontecarloSampling(montecarloSampleNum);
  int t1=clock();
  vvs.ThicknessEvaluator(distThr,16,3,skelM);
  int t2=clock();
  printf("Sampling %4.2f Medial Axis Eval %5.2f\n",float(t1-t0)/CLOCKS_PER_SEC,float(t2-t1)/CLOCKS_PER_SEC);
  tri::UpdateColor<MyMesh>::PerVertexQualityRamp(baseM);
  if(surfSamp)
  {
    tri::Append<MyMesh,MyMesh>::MeshCopy(*surfSamp, vvs.poissonSurfaceMesh);
    tri::UpdateColor<MyMesh>::PerVertexQualityRamp(*surfSamp);
  }
  if(volSamp)
  {
    tri::Append<MyMesh,MyMesh>::MeshCopy(*volSamp, vvs.montecarloVolumeMesh);
    tri::UpdateColor<MyMesh>::PerVertexQualityRamp(*volSamp);
  }
  return true;
}

void MeasurePluginTEST()
{
  MyMesh m0,m1;
  tri::Sphere(m0,3);
  tri::Sphere(m1,4);

  ComputeHausdorffDistance(uintptr_t(&m0),uintptr_t(&m1),0,10000,0.1);
  ComputeHausdorffDistance(uintptr_t(&m1),uintptr_t(&m0),0,10000,0.1);
  ComputeQualityFromCurvature(uintptr_t(&m0),0);
  ComputeQualityFromCurvature(uintptr_t(&m0),1);
  ComputeThickness(uintptr_t(&m0),0,0,0,10000,0.01,1.05);
  ComputeThickness(uintptr_t(&m1),0,0,0,10000,0.01,1.05);
}

#ifdef __EMSCRIPTEN__
EMSCRIPTEN_BINDINGS(MLMeasurePlugin) {
    emscripten::function("ComputeGeometricMeasures",   &ComputeGeometricMeasures);
    emscripten::function("ComputeTopologicalMeasures", &ComputeTopologicalMeasures);
    emscripten::function("ComputeHausdorffDistance",   &ComputeHausdorffDistance);
    emscripten::function("ComputeQualityFromCurvature",   &ComputeQualityFromCurvature);
    emscripten::function("ComputeThickness",   &ComputeThickness);
}
#endif
<commit_msg>Better timings of thickness evaluator<commit_after>#include "mesh_def.h"
#include <vcg/complex/algorithms/inertia.h>
#include <vcg/complex/algorithms/stat.h>
#include <vcg/complex/algorithms/point_sampling.h>
#include<vcg/complex/algorithms/voronoi_volume_sampling.h>

using namespace vcg;
using namespace std;

void ComputeGeometricMeasures(uintptr_t meshPtr)
{
    MyMesh &m = *((MyMesh*) meshPtr);

    printf("Geometric measures:\n");

    tri::UpdateBounding<MyMesh>::Box(m);
    printf("Mesh Bounding Box size %f %f %f\n", m.bbox.DimX(), m.bbox.DimY(), m.bbox.DimZ());
    printf("Mesh Bounding Box diag %f\n", m.bbox.Diag());

    tri::Inertia<MyMesh> I(m);
    float volume = I.Mass();
    float area = tri::Stat<MyMesh>::ComputeMeshArea(m);
    printf("Mesh volume %f\n", volume);
    printf("Mesh surface is %f\n", area);

    Point3f bc = tri::Stat<MyMesh>::ComputeShellBarycenter(m);
    printf("Thin shell barycenter %9.6f  %9.6f  %9.6f\n", bc[0], bc[1], bc[2]);

    if (volume <= 0) {
        printf("Volume is negative, Mesh is not 'solid' (non manifold, non watertight, non consistently oriented)\n"
               "No information on barycenter and inertia tensor can be reported\n");
    } else {
        printf("Center of mass is %f %f %f\n", I.CenterOfMass()[0], I.CenterOfMass()[1], I.CenterOfMass()[2]);
        Matrix33f it;
        I.InertiaTensor(it);
        printf("Inertia tensor is: \n");
        printf("  | %9.6f  %9.6f  %9.6f |\n", it[0][0], it[0][1], it[0][2]);
        printf("  | %9.6f  %9.6f  %9.6f |\n", it[1][0], it[1][1], it[1][2]);
        printf("  | %9.6f  %9.6f  %9.6f |\n", it[2][0], it[2][1], it[2][2]);

        Matrix33f pca;
        Point3f pcav;
        I.InertiaTensorEigen(pca, pcav);
        printf("Principal axes are :\n");
        printf("  | %9.6f  %9.6f  %9.6f |\n", pca[0][0], pca[0][1], pca[0][2]);
        printf("  | %9.6f  %9.6f  %9.6f |\n", pca[1][0], pca[1][1], pca[1][2]);
        printf("  | %9.6f  %9.6f  %9.6f |\n", pca[2][0], pca[2][1], pca[2][2]);

        printf("Axes momenta are :\n");
        printf("  | %9.6f  %9.6f  %9.6f |\n", pcav[0], pcav[1], pcav[2]);
    }
}

void ComputeTopologicalMeasures(uintptr_t meshPtr)
{
    MyMesh &m = *((MyMesh*) meshPtr);

    printf("Topological measures:\n");
    tri::UpdateTopology<MyMesh>::FaceFace(m);

    int nonManifEdgeNumFF = tri::Clean<MyMesh>::CountNonManifoldEdgeFF(m, true);
    int faceEdgeNonManif = tri::UpdateSelection<MyMesh>::FaceCount(m);
    tri::UpdateSelection<MyMesh>::VertexClear(m);
    tri::UpdateSelection<MyMesh>::FaceClear(m);

    int nonManifVertNum = tri::Clean<MyMesh>::CountNonManifoldVertexFF(m, true);
    tri::UpdateSelection<MyMesh>::FaceFromVertexLoose(m);
    int faceVertNonManif = tri::UpdateSelection<MyMesh>::FaceCount(m);
    int edgeNum = 0, borderNum = 0, nonManifEdgeNum = 0;
    tri::Clean<MyMesh>::CountEdgeNum(m, edgeNum, borderNum, nonManifEdgeNum);
    printf("V: %6i E: %6i F:%6i\n", m.vn, edgeNum, m.fn);
    int unrefVertNum = tri::Clean<MyMesh>::CountUnreferencedVertex(m);
    printf("Unreferenced vertices %i\n", unrefVertNum);
    printf("Boundary edges %i\n", borderNum);

    int connectedComponentsNum = tri::Clean<MyMesh>::CountConnectedComponents(m);
    printf("Mesh is composed by %i connected component(s)\n", connectedComponentsNum);

    if (nonManifEdgeNumFF == 0 && nonManifVertNum == 0) {
        printf("Mesh is two-manifold\n");
    }

    if (nonManifEdgeNumFF != 0) printf("Mesh has %i non two manifold edges and %i faces are incident on these edges\n", nonManifEdgeNumFF, faceEdgeNonManif);

    if (nonManifVertNum != 0) printf("Mesh has %i non two manifold vertexes and %i faces are incident on these vertices\n", nonManifVertNum, faceVertNonManif);

    // For Manifold meshes compute some other stuff
    if (nonManifVertNum == 0 && nonManifEdgeNumFF == 0) {
        int holeNum = tri::Clean<MyMesh>::CountHoles(m);
        printf("Mesh has %i holes\n", holeNum);
        int genus = tri::Clean<MyMesh>::MeshGenus(m.vn-unrefVertNum, edgeNum, m.fn, holeNum, connectedComponentsNum);
        printf("Genus is %i\n", genus);
    } else {
        printf("Mesh has a undefined number of holes (non 2-manifold mesh)\n");
        printf("Genus is undefined (non 2-manifold mesh)\n");
    }
    tri::UpdateSelection<MyMesh>::VertexClear(m);
    tri::UpdateSelection<MyMesh>::FaceClear(m);
}

void ComputeHausdorffDistance(uintptr_t srcPtr, uintptr_t trgPtr, uintptr_t _sampleMeshPtr, int sampleNum, float distUpperBound)
{
  MyMesh &src = *((MyMesh*) srcPtr);
  MyMesh &trg = *((MyMesh*) trgPtr);
  MyMesh *sampleMeshPtr = ((MyMesh*) _sampleMeshPtr);

  HausdorffSampler<MyMesh> hs(&trg);
  hs.dist_upper_bound = distUpperBound;
  hs.init(sampleMeshPtr,0);
  printf("Sampled  mesh has %7i vert %7i face\n",src.vn,src.fn);
  printf("Searched mesh has %7i vert %7i face\n",trg.vn,trg.fn);
  printf("Max sampling distance %f on a bbox diag of %f\n",distUpperBound,trg.bbox.Diag());

  tri::SurfaceSampling<MyMesh,HausdorffSampler<MyMesh> >::VertexUniform(src,hs,sampleNum);
  tri::SurfaceSampling<MyMesh,HausdorffSampler<MyMesh> >::Montecarlo(src,hs,sampleNum);

  printf("Hausdorff Distance computed\n");
  printf("     Sampled %i pts (rng: 0)  on %s searched closest on %s \n",hs.n_total_samples,src.meshName.c_str(),trg.meshName.c_str());
  printf("     min : %f   max %f   mean : %f   RMS : %f \n",hs.getMinDist(),hs.getMaxDist(),hs.getMeanDist(),hs.getRMSDist());
  float d = src.bbox.Diag();
  printf("Values w.r.t. BBox Diag (%f)\n",d);
  printf("     min : %f   max %f   mean : %f   RMS : %f\n",hs.getMinDist()/d,hs.getMaxDist()/d,hs.getMeanDist()/d,hs.getRMSDist()/d);

  if(sampleMeshPtr)
  {
    printf("Created Sample Mesh with %i samples\n",sampleMeshPtr->vn);
  }
}

void ComputeQualityFromCurvature(uintptr_t meshPtr, int curvatureMode)
{
    MyMesh &m = *((MyMesh*) meshPtr);
    tri::UpdateCurvature<MyMesh>::MeanAndGaussian(m);
    if(curvatureMode==0)
    {
      tri::UpdateQuality<MyMesh>::VertexFromGaussianCurvatureHG(m);
      printf("Computed Gaussian Curvature\n");
    }
    else
    {
      tri::UpdateQuality<MyMesh>::VertexFromMeanCurvatureHG(m);
      printf("Computed Mean Curvature\n");
    }
}

bool ComputeThickness(uintptr_t meshPtr, uintptr_t trgPtr, uintptr_t volPtr, uintptr_t skelPtr,
                      int montecarloSampleNum, float surfSamplingRadius, float distThr)
{
  MyMesh &baseM = *((MyMesh*) meshPtr);
  MyMesh *surfSamp = ((MyMesh*) trgPtr);
  MyMesh  *volSamp = ((MyMesh*) volPtr);
  MyMesh   *skelM = ((MyMesh*) skelPtr);
  if(!tri::Clean<MyMesh>::IsWaterTight(baseM))
  {
    printf("Volume Sampling Requires Watertight Mesh. Nothing Done.\n");
    return false;
  }
  tri::UpdateBounding<MyMesh>::Box(baseM);
  float meshVol = tri::Stat<MyMesh>::ComputeMeshVolume(baseM);
  float boxVol = baseM.bbox.Volume();
  printf("Volume ratio %f = %f/%f \n", meshVol/boxVol,meshVol,boxVol);

  MyMesh pVm; // unused...
  tri::VoronoiVolumeSampling<MyMesh> vvs(baseM, pVm);
  float poissonRadiusSurface = baseM.bbox.Diag()*surfSamplingRadius;
  int t0=clock();
  vvs.Init(poissonRadiusSurface);
  int t1=clock();
  vvs.BuildMontecarloSampling(montecarloSampleNum);
  int t2=clock();
  vvs.ThicknessEvaluator(distThr,16,3,skelM);
  int t3=clock();
  printf("Surface Sampling %5.2f sec\n",float(t1-t0)/CLOCKS_PER_SEC);
  printf("Volume  Sampling %5.2f sec\n",float(t2-t1)/CLOCKS_PER_SEC);
  printf("Medial Axis Eval %5.2f sec\n",float(t3-t2)/CLOCKS_PER_SEC);
  tri::UpdateColor<MyMesh>::PerVertexQualityRamp(baseM);
  if(surfSamp)
  {
    tri::Append<MyMesh,MyMesh>::MeshCopy(*surfSamp, vvs.poissonSurfaceMesh);
    tri::UpdateColor<MyMesh>::PerVertexQualityRamp(*surfSamp);
  }
  if(volSamp)
  {
    tri::Append<MyMesh,MyMesh>::MeshCopy(*volSamp, vvs.montecarloVolumeMesh);
    tri::UpdateColor<MyMesh>::PerVertexQualityRamp(*volSamp);
  }
  return true;
}

void MeasurePluginTEST()
{
  MyMesh m0,m1;
  tri::Sphere(m0,3);
  tri::Sphere(m1,4);

  ComputeHausdorffDistance(uintptr_t(&m0),uintptr_t(&m1),0,10000,0.1);
  ComputeHausdorffDistance(uintptr_t(&m1),uintptr_t(&m0),0,10000,0.1);
  ComputeQualityFromCurvature(uintptr_t(&m0),0);
  ComputeQualityFromCurvature(uintptr_t(&m0),1);
  ComputeThickness(uintptr_t(&m0),0,0,0,10000,0.01,1.05);
  ComputeThickness(uintptr_t(&m1),0,0,0,10000,0.01,1.05);
}

#ifdef __EMSCRIPTEN__
EMSCRIPTEN_BINDINGS(MLMeasurePlugin) {
    emscripten::function("ComputeGeometricMeasures",   &ComputeGeometricMeasures);
    emscripten::function("ComputeTopologicalMeasures", &ComputeTopologicalMeasures);
    emscripten::function("ComputeHausdorffDistance",   &ComputeHausdorffDistance);
    emscripten::function("ComputeQualityFromCurvature",   &ComputeQualityFromCurvature);
    emscripten::function("ComputeThickness",   &ComputeThickness);
}
#endif
<|endoftext|>


<commit_before>// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>

#include "checkpoints.h"

#include "main.h"
#include "uint256.h"

namespace Checkpoints
{
    typedef std::map<int, uint256> MapCheckpoints;

    //
    // What makes a good checkpoint block?
    // + Is surrounded by blocks with reasonable timestamps
    //   (no blocks before with a timestamp after, none after with
    //    timestamp before)
    // + Contains no strange transactions
    //
    static MapCheckpoints mapCheckpoints =
        boost::assign::map_list_of
        ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
        ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
        ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
        (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
        (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
        (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
        (185333, uint256("0x00000000000002334c71b8706940c20348af897a9cfc0f1a6dab0d14d4ceb815"))
        ;

    static MapCheckpoints mapCheckpointsTestnet =
        boost::assign::map_list_of
        ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
        ;

    bool CheckBlock(int nHeight, const uint256& hash)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
        if (i == checkpoints.end()) return true;
        return hash == i->second;
    }

    int GetTotalBlocksEstimate()
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        return checkpoints.rbegin()->first;
    }

    CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
        {
            const uint256& hash = i.second;
            std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
            if (t != mapBlockIndex.end())
                return t->second;
        }
        return NULL;
    }
}
<commit_msg>Checkpoint at block 193,000<commit_after>// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>

#include "checkpoints.h"

#include "main.h"
#include "uint256.h"

namespace Checkpoints
{
    typedef std::map<int, uint256> MapCheckpoints;

    //
    // What makes a good checkpoint block?
    // + Is surrounded by blocks with reasonable timestamps
    //   (no blocks before with a timestamp after, none after with
    //    timestamp before)
    // + Contains no strange transactions
    //
    static MapCheckpoints mapCheckpoints =
        boost::assign::map_list_of
        ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
        ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
        ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
        (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
        (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
        (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
        (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"))
        ;

    static MapCheckpoints mapCheckpointsTestnet =
        boost::assign::map_list_of
        ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
        ;

    bool CheckBlock(int nHeight, const uint256& hash)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
        if (i == checkpoints.end()) return true;
        return hash == i->second;
    }

    int GetTotalBlocksEstimate()
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        return checkpoints.rbegin()->first;
    }

    CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
        {
            const uint256& hash = i.second;
            std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
            if (t != mapBlockIndex.end())
                return t->second;
        }
        return NULL;
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>

#include "checkpoints.h"

#include "main.h"
#include "uint256.h"

namespace Checkpoints
{
    typedef std::map<int, uint256> MapCheckpoints;

    //
    // What makes a good checkpoint block?
    // + Is surrounded by blocks with reasonable timestamps
    //   (no blocks before with a timestamp after, none after with
    //    timestamp before)
    // + Contains no strange transactions
    //
    static MapCheckpoints mapCheckpoints =
        boost::assign::map_list_of
        ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
        ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
        ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
        (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
        (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
        (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
        (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"))
        ;

    static MapCheckpoints mapCheckpointsTestnet =
        boost::assign::map_list_of
        ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
        ;

    bool CheckBlock(int nHeight, const uint256& hash)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
        if (i == checkpoints.end()) return true;
        return hash == i->second;
    }

    int GetTotalBlocksEstimate()
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        return checkpoints.rbegin()->first;
    }

    CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
        {
            const uint256& hash = i.second;
            std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
            if (t != mapBlockIndex.end())
                return t->second;
        }
        return NULL;
    }
}
<commit_msg>Checkpoint at first 25-btc-reward block (210,000)<commit_after>// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>

#include "checkpoints.h"

#include "main.h"
#include "uint256.h"

namespace Checkpoints
{
    typedef std::map<int, uint256> MapCheckpoints;

    //
    // What makes a good checkpoint block?
    // + Is surrounded by blocks with reasonable timestamps
    //   (no blocks before with a timestamp after, none after with
    //    timestamp before)
    // + Contains no strange transactions
    //
    static MapCheckpoints mapCheckpoints =
        boost::assign::map_list_of
        ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
        ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
        ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20"))
        (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97"))
        (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"))
        (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763"))
        (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317"))
        (210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e"))
        ;

    static MapCheckpoints mapCheckpointsTestnet =
        boost::assign::map_list_of
        ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
        ;

    bool CheckBlock(int nHeight, const uint256& hash)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
        if (i == checkpoints.end()) return true;
        return hash == i->second;
    }

    int GetTotalBlocksEstimate()
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        return checkpoints.rbegin()->first;
    }

    CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
        {
            const uint256& hash = i.second;
            std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
            if (t != mapBlockIndex.end())
                return t->second;
        }
        return NULL;
    }
}
<|endoftext|>


<commit_before><commit_msg>Avoid use of the preprocessor<commit_after><|endoftext|>


<commit_before><commit_msg>WaE: equality comparison with extraneous parentheses<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 Blazecoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>

#include "checkpoints.h"

#include "main.h"
#include "uint256.h"

namespace Checkpoints
{
    typedef std::map<int, uint256> MapCheckpoints;

    //
    // What makes a good checkpoint block?
    // + Is surrounded by blocks with reasonable timestamps
    //   (no blocks before with a timestamp after, none after with
    //    timestamp before)
    // + Contains no strange transactions
    //

	// no checkpoint now, can be added in later releases
    static MapCheckpoints mapCheckpoints =
            boost::assign::map_list_of
            (  0,    uint256("0x5d871c1b6ea542c2bb8a3b3ac70028a591bbf81369e90c2446c1a2bbfb89459b"))
            ( 18500, uint256("0x6cfc4decf7c26c037c621190681f9b3f12912f8330b06c652e0c193340a23347"))
            ( 33000, uint256("0xcfd0eb628a7fee82accc4e2f183cdd1abd08afeedf2b1b030230836a4e74629e"))
			;

    bool CheckBlock(int nHeight, const uint256& hash)
    {
        if (fTestNet) return true; // Testnet has no checkpoints

        MapCheckpoints::const_iterator i = mapCheckpoints.find(nHeight);
        if (i == mapCheckpoints.end()) return true;
        return hash == i->second;
		// return true;
    }

    int GetTotalBlocksEstimate()
    {
        if (fTestNet) return 0;

        return mapCheckpoints.rbegin()->first;
		// return 0;
    }

    CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
    {
        if (fTestNet) return NULL;

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
        {
            const uint256& hash = i.second;
            std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
            if (t != mapBlockIndex.end())
                return t->second;
				// return NULL;
        }
        return NULL;
    }
}
<commit_msg>Added checkpoint for block 60413<commit_after>// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 Blazecoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>

#include "checkpoints.h"

#include "main.h"
#include "uint256.h"

namespace Checkpoints
{
    typedef std::map<int, uint256> MapCheckpoints;

    //
    // What makes a good checkpoint block?
    // + Is surrounded by blocks with reasonable timestamps
    //   (no blocks before with a timestamp after, none after with
    //    timestamp before)
    // + Contains no strange transactions
    //

	// no checkpoint now, can be added in later releases
    static MapCheckpoints mapCheckpoints =
            boost::assign::map_list_of
            (  0,    uint256("0x5d871c1b6ea542c2bb8a3b3ac70028a591bbf81369e90c2446c1a2bbfb89459b"))
            ( 18500, uint256("0x6cfc4decf7c26c037c621190681f9b3f12912f8330b06c652e0c193340a23347"))
            ( 33000, uint256("0xcfd0eb628a7fee82accc4e2f183cdd1abd08afeedf2b1b030230836a4e74629e"))
            ( 60413, uint256("0x99ea9310aac366b03161254d77ada05c9eb1392ca8ca370885b013f80d41f56e"))
			;

    bool CheckBlock(int nHeight, const uint256& hash)
    {
        if (fTestNet) return true; // Testnet has no checkpoints

        MapCheckpoints::const_iterator i = mapCheckpoints.find(nHeight);
        if (i == mapCheckpoints.end()) return true;
        return hash == i->second;
		// return true;
    }

    int GetTotalBlocksEstimate()
    {
        if (fTestNet) return 0;

        return mapCheckpoints.rbegin()->first;
		// return 0;
    }

    CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
    {
        if (fTestNet) return NULL;

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
        {
            const uint256& hash = i.second;
            std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
            if (t != mapBlockIndex.end())
                return t->second;
				// return NULL;
        }
        return NULL;
    }
}
<|endoftext|>


<commit_before>#include "afa.h"
//+-----------------------------------------------------------------------------------------+
//| This formulation was first formulated in                                                |
//|                                                                                |
//| J.B. Gao, J. Hu, W.W. Tung, Facilitating joint chaos and fractal analysis of biosignals |
//| through nonlinear adaptive filtering.  PLoS ONE PLoS ONE 6(9): e24331.                  |
//| doi:10.1371/journal.pone.0024331                                                        |
//+-----------------------------------------------------------------------------------------+

EXPORT CAfa * __stdcall Create(	const unsigned int length,	 const unsigned int order)
{
	return new CAfa(length, 1u, order);
}

EXPORT void __stdcall Destroy(CAfa * instance)
{
	delete instance;
}

EXPORT int __stdcall Push(CAfa * instance, const int x, const double y, const time_t t0, const time_t t1)
{
	return instance->push(x, y, t0, t1);
}

EXPORT double __stdcall Calculate(CAfa * instance)
{
	return instance->calculate();
}

CAfa::CAfa(const unsigned int length,const double step,const unsigned int order) :
	m_length(validate_length(length)),
	m_step(validate_step(step)),
	m_order(validate_order(order)),
	m_series(CSeries(m_length + 1))
{
	// EChETCY̏
	int imax = int(std::round(std::log2(m_length)));
	int sz = int((imax - 2) / step) + 1;
	for (double m = 2; m < imax; m += m_step)
		{
		unsigned int w = int(round(pow(2, m) + 1));
		if ((w % 2) == 0) w += 1u;
		// ZOg̒ǉ
		m_segments.emplace_back(unsigned int((w-1)*0.5));
		// ghtB^̒ǉ
		m_filters.emplace_back(w, m_order);
	}
	// LbV̏
	for (auto it = m_segments.begin(); it != m_segments.end(); it++)
	{

		m_cache.insert(std::make_pair(*it, CCache(*it, m_length)));

	}
}

int CAfa::push(const int x, const double y, const time_t t0, const time_t t1)
{
	int result = 0;
	try
	{
		result = m_series.push(x, y, t0, t1);

	}
	catch (...)
	{
		return -9999;
	}
    // VKo[̈ȊO͉ȂB
	if (!m_series.is_adding())return -1;
    // XP[[v
	std::deque<double> series = m_series.get_series();
	for (unsigned int i = 0; i < m_segments.size(); i++)
	{
		unsigned int step = m_segments[i];	// n[tTCY
		unsigned int w = step * 2 + 1;		// EChETCY
		unsigned int len = step * 3 + 1;	// EChETCY{n[tTCY
		unsigned int sz = series.size();

		if (sz - 1 < len) continue;	//TCYȂꍇXLbv
		// vZɎgpf[^ deque  vector ɃRs[
		int offset = sz - len - 1;
		std::vector<double> data;
		std::copy(series.cbegin() + offset, series.cend() - 1, std::back_inserter(data));
		std::vector <double> trend;
		double v1 = 0.0;
		double v2 = 0.0;
		// tBbg
		if (m_filters[i].fit(data, trend)) {
			// cΒla߂B
			volatility(data, trend, step, v1, v2);
		}

		// LbVɒǉ
		m_cache[step].set(x - step, v1);
		m_cache[step].set(x, v2);

	}
	return result;

}

double CAfa::calculate()
{
	// ̈ÕCfbNX
	int x = m_series.prev_x();
	if (x == -1) return -1.0;
	// XP[Ow߂B
	std::vector<Stats> fq;
	for (unsigned int i = 0; i < m_segments.size(); i++)
	{
		unsigned int step = m_segments[i];
		unsigned int w = step * 2 + 1;
		// cΒla̕ς߂B
		double v = m_cache[step].calc_fractal(x);
		fq.emplace_back(1, log2(w), log2(v));
	}
	// X[v߂B
	Stats stat = std::accumulate(fq.begin(), fq.end(), Stats());
	double slope = stat.slope();
	return (isnan(slope)) ? -1.0 : slope;
}
void CAfa::volatility(std::vector<double> &y, std::vector<double> &y_hat, const unsigned int step, double &v1,double &v2)
{
	unsigned int sz = step*2;
	unsigned int from_y = y.size() - sz;
	unsigned int from_y_hat = y_hat.size() - sz;

	v1 = 0.0;
	for (unsigned int i = 0; i < step; i++)
	{
		v1 += abs(y[from_y + i] - y_hat[from_y_hat + i]);
	}
//	std::cout << "1 v1:" <<v1 << std::endl;

	v2 = 0.0;
	for (unsigned int i = step; i < sz; i++)
	{
		v2 += abs(y[from_y + i] - y_hat[from_y_hat + i]);
	}
//	std::cout << "2 v2:" << v2 << std::endl;

}

bool CAfa::get_results(const unsigned int idx, double &y)
{
	if (m_results.size() <= idx) return false;
	y = m_results[idx];
	return true;
}

unsigned int CAfa::validate_length(const unsigned int len)
{
	unsigned int l = int(pow(2, int(log2(len))));
	return std::max(16u, std::min(1024u, l));
}

double CAfa::validate_step(const double step)
{
	double tmp = int(step * 2.0)*0.5;
	return std::min(2.0, std::max(0.5, tmp));
}
unsigned int  CAfa::validate_order(const unsigned int order)
{
	return 1u;
}

<commit_msg>miner bugfix<commit_after>#include "afa.h"

EXPORT CAfa * __stdcall Create(	const unsigned int length,	 const unsigned int order)
{
	return new CAfa(length, 1u, order);
}

EXPORT void __stdcall Destroy(CAfa * instance)
{
	delete instance;
}

EXPORT int __stdcall Push(CAfa * instance, const int x, const double y, const time_t t0, const time_t t1)
{
	return instance->push(x, y, t0, t1);
}

EXPORT double __stdcall Calculate(CAfa * instance)
{
	return instance->calculate();
}

CAfa::CAfa(const unsigned int length,const double step,const unsigned int order) :
	m_length(validate_length(length)),
	m_step(validate_step(step)),
	m_order(validate_order(order)),
	m_series(CSeries(m_length + 1))
{
	// EChETCY̏
	int imax = int(std::round(std::log2(m_length)));
	int sz = int((imax - 2) / step) + 1;
	for (double m = 2; m < imax; m += m_step)
		{
		unsigned int w = int(round(pow(2, m) + 1));
		if ((w % 2) == 0) w += 1u;
		// ZOg̒ǉ
		m_segments.emplace_back(unsigned int((w-1)*0.5));
		// ghtB^̒ǉ
		m_filters.emplace_back(w, m_order);
	}
	// LbV̏
	for (auto it = m_segments.begin(); it != m_segments.end(); it++)
	{

		m_cache.insert(std::make_pair(*it, CCache(*it, m_length)));

	}
}

int CAfa::push(const int x, const double y, const time_t t0, const time_t t1)
{
	int result = 0;
	try
	{
		result = m_series.push(x, y, t0, t1);

	}
	catch (...)
	{
		return -9999;
	}

	if (!m_series.is_adding())return -1;
	std::deque<double> series = m_series.get_series();
	for (unsigned int i = 0; i < m_segments.size(); i++)
	{

		unsigned int step = m_segments[i];
		//		std::cout << step << std::endl;
		unsigned int w = step * 2 + 1;
		unsigned int len = step * 3 + 1;
		unsigned int sz = series.size();
		if (sz - 1 < len) continue;
		int offset = sz - len - 1;
		std::vector<double> data;
		std::copy(series.cbegin() + offset, series.cend() - 1, std::back_inserter(data));
		std::vector <double> trend;
		double v1 = 0.0;
		double v2 = 0.0;
		if (m_filters[i].fit(data, trend)) {
			//if (x%step == 0 && w == 9)
			//{

			//	for (unsigned int i = 0; i < step; i++)
			//	{
			//		unsigned int o = data.size() - (step * 2);
			//		//std::cout <<x <<", " << w << "]:" << data[o + i] << " - " << trend[i] << " ;" << std::endl;
			//	}
			//}
			volatility(data, trend, step, v1, v2);
		}

		// LbVɒǉ

		m_cache[step].set(x - step, v1);
		m_cache[step].set(x, v2);
//		std::cout << w << ":" << step << std::endl;

//		if (x%step == 2)
//		{
//			std::cout << "[" << x - step << "]<-" << v1 << ", ";
//			std::cout << "[" << x << "]<-" << v2 << std::endl;
//			m_cache[step].print(x);
//		}

	}
	return result;

}

double CAfa::calculate()
{
	int x = m_series.last_x();

	std::vector<Stats> fq;
	//std::cout << "------------------------------" << std::endl;
	for (unsigned int i = 0; i < m_segments.size(); i++)
	{
		unsigned int step = m_segments[i];
		unsigned int w = step * 2 + 1;
		double v = m_cache[step].calc_fractal(x);
		fq.emplace_back(1, log2(w), log2(v));
		//std::cout<< (w) << "," <<  (v) << std::endl;
	}

	Stats stat = std::accumulate(fq.begin(), fq.end(), Stats());
	double slope = stat.slope();
//	std::cout <<"slope:"<< slope << std::endl;
	return (isnan(slope)) ? -1.0 : slope;
}
void CAfa::volatility(std::vector<double> &y, std::vector<double> &y_hat, const unsigned int step, double &v1,double &v2)
{
	unsigned int sz = step*2;
	unsigned int from_y = y.size() - sz;
	unsigned int from_y_hat = y_hat.size() - sz;

	v1 = 0.0;
	for (unsigned int i = 0; i < step; i++)
	{
//		std::cout << "1 y:" << from_y+i << " y^:" << from_y_hat+i << std::endl;
//		std::cout << "1 v:" << y[from_y + i] << " v^:" << y_hat[from_y_hat + i] << std::endl;
//		std::cout << "1 volat:" << y[from_y + i] - y_hat[from_y_hat + i] << std::endl;
		v1 += abs(y[from_y + i] - y_hat[from_y_hat + i]);
	}
//	std::cout << "1 v1:" <<v1 << std::endl;

	v2 = 0.0;
	for (unsigned int i = step; i < sz; i++)
	{
//		std::cout << "2 x:" << from_y + i << " y^:" << from_y_hat + i << std::endl;
//		std::cout << "2 v:" << y[from_y + i] << " v^:" << y_hat[from_y_hat + i] << std::endl;
//		std::cout << "2 volat:" << y[from_y + i] - y_hat[from_y_hat + i] << std::endl;
		v2 += abs(y[from_y + i] - y_hat[from_y_hat + i]);
	}
//	std::cout << "2 v2:" << v2 << std::endl;

}

bool CAfa::get_results(const unsigned int idx, double &y)
{
	if (m_results.size() <= idx) return false;
	y = m_results[idx];
	return true;
}

unsigned int CAfa::validate_length(const unsigned int len)
{
	unsigned int l = int(pow(2, int(log2(len))));
	return std::max(16u, std::min(1024u, l));
}

double CAfa::validate_step(const double step)
{
	return 1u;
}
unsigned int  CAfa::validate_order(const unsigned int order)
{
	return std::min(3u, std::max(1u, order));
}

<|endoftext|>


<commit_before>//=============================================================================
//
// akaze_match.cpp
// Authors: Pablo F. Alcantarilla (1), Jesus Nuevo (2)
// Institutions: Toshiba Research Europe Ltd (1)
//               TrueVision Solutions (2)
// Date: 07/10/2014
// Email: pablofdezalc@gmail.com
//
// AKAZE Features Copyright 2014, Pablo F. Alcantarilla, Jesus Nuevo
// All Rights Reserved
// See LICENSE for the license information
//=============================================================================

/**
 * @file akaze_match.cpp
 * @brief Main program for matching two images with AKAZE features
 * @date Oct 07, 2014
 * @author Pablo F. Alcantarilla
 */

#include "./lib/AKAZE.h"

// OpenCV
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace libAKAZECU;

/* ************************************************************************* */
// Image matching options
const float MIN_H_ERROR = 2.50f;            ///< Maximum error in pixels to accept an inlier
const float DRATIO = 0.80f;                 ///< NNDR Matching value

/* ************************************************************************* */
/**
 * @brief This function parses the command line arguments for setting A-KAZE parameters
 * and image matching between two input images
 * @param options Structure that contains A-KAZE settings
 * @param img_path1 Path for the first input image
 * @param img_path2 Path for the second input image
 * @param homography_path Path for the file that contains the ground truth homography
 */
int parse_input_options(AKAZEOptions &options, std::string& img_path1,
                        std::string& img_path2, std::string& homography_path,
                        int argc, char *argv[]);

/* ************************************************************************* */
int main(int argc, char *argv[]) {

  // Variables
  AKAZEOptions options;
  cv::Mat img1, img1_32, img2, img2_32, img1_rgb, img2_rgb, img_com, img_r;
  string img_path1, img_path2, homography_path;
  float ratio = 0.0, rfactor = .60;
  int nkpts1 = 0, nkpts2 = 0, nmatches = 0, ninliers = 0, noutliers = 0;

  vector<cv::KeyPoint> kpts1, kpts2;
  vector<vector<cv::DMatch> > dmatches;
  cv::Mat desc1, desc2;
  cv::Mat HG;

  // Variables for measuring computation times
  double t1 = 0.0, t2 = 0.0;
  double takaze = 0.0, tmatch = 0.0;

  // Parse the input command line options
  if (parse_input_options(options,img_path1,img_path2,homography_path,argc,argv))
    return -1;

  // Read image 1 and if necessary convert to grayscale.
  img1 = cv::imread(img_path1, 0);
  if (img1.data == NULL) {
    cerr << "Error loading image 1: " << img_path1 << endl;
    return -1;
  }

  // Read image 2 and if necessary convert to grayscale.
  img2 = cv::imread(img_path2, 0);
  if (img2.data == NULL) {
    cerr << "Error loading image 2: " << img_path2 << endl;
    return -1;
  }

  // Read ground truth homography file
  bool use_ransac = false;
  if (read_homography(homography_path, HG) == false)
    use_ransac = true;

  // Convert the images to float
  img1.convertTo(img1_32, CV_32F, 1.0/255.0, 0);
  img2.convertTo(img2_32, CV_32F, 1.0/255.0, 0);

  // Color images for results visualization
  img1_rgb = cv::Mat(cv::Size(img1.cols, img1.rows), CV_8UC3);
  img2_rgb = cv::Mat(cv::Size(img2.cols, img1.rows), CV_8UC3);
  img_com = cv::Mat(cv::Size(img1.cols*2, img1.rows), CV_8UC3);
  img_r = cv::Mat(cv::Size(img_com.cols*rfactor, img_com.rows*rfactor), CV_8UC3);

  // Create the first AKAZE object
  options.img_width = img1.cols;
  options.img_height = img1.rows;
  AKAZE evolution1(options);

  // Create the second HKAZE object
  options.img_width = img2.cols;
  options.img_height = img2.rows;
  AKAZE evolution2(options);

  t1 = cv::getTickCount();

  evolution1.Create_Nonlinear_Scale_Space(img1_32);
  evolution1.Feature_Detection(kpts1);
  evolution1.Compute_Descriptors(kpts1, desc1);

  evolution2.Create_Nonlinear_Scale_Space(img2_32);
  evolution2.Feature_Detection(kpts2);
  evolution2.Compute_Descriptors(kpts2, desc2);

  t2 = cv::getTickCount();
  takaze = 1000.0*(t2-t1)/cv::getTickFrequency();

  // Matching Descriptors!!
  vector<cv::Point2f> matches, inliers;
  cv::Ptr<cv::DescriptorMatcher> matcher_l2 = cv::DescriptorMatcher::create("BruteForce");
  cv::Ptr<cv::DescriptorMatcher> matcher_l1 = cv::DescriptorMatcher::create("BruteForce-Hamming");

  t1 = cv::getTickCount();

  MatchDescriptors(desc1, desc2, dmatches);

  t2 = cv::getTickCount();
  tmatch = 1000.0*(t2 - t1)/ cv::getTickFrequency();

  /*t1 = cv::getTickCount();

  if (options.descriptor < MLDB_UPRIGHT)
    matcher_l2->knnMatch(desc1, desc2, dmatches, 2);
  else
    matcher_l1->knnMatch(desc1, desc2, dmatches, 2);

  t2 = cv::getTickCount();
  tmatch = 1000.0*(t2 - t1)/ cv::getTickFrequency();*/

  // Compute Inliers!!
  matches2points_nndr(kpts1, kpts2, dmatches, matches, DRATIO);

  if (use_ransac == false)
    compute_inliers_homography(matches, inliers, HG, MIN_H_ERROR);
  else
    compute_inliers_ransac(matches, inliers, MIN_H_ERROR, false);

  // Compute the inliers statistics
  nkpts1 = kpts1.size();
  nkpts2 = kpts2.size();
  nmatches = matches.size()/2;
  ninliers = inliers.size()/2;
  noutliers = nmatches - ninliers;
  ratio = 100.0*((float) ninliers / (float) nmatches);

  // Prepare the visualization
  cvtColor(img1, img1_rgb, cv::COLOR_GRAY2BGR);
  cvtColor(img2, img2_rgb, cv::COLOR_GRAY2BGR);

  // Show matching statistics
  cout << "Number of Keypoints Image 1: " << nkpts1 << endl;
  cout << "Number of Keypoints Image 2: " << nkpts2 << endl;
  cout << "A-KAZE Features Extraction Time (ms): " << takaze << endl;
  cout << "Matching Descriptors Time (ms): " << tmatch << endl;
  cout << "Number of Matches: " << nmatches << endl;
  cout << "Number of Inliers: " << ninliers << endl;
  cout << "Number of Outliers: " << noutliers << endl;
  cout << "Inliers Ratio: " << ratio << endl << endl;

  draw_keypoints(img1_rgb, kpts1);
  draw_keypoints(img2_rgb, kpts2);
  draw_inliers(img1_rgb, img2_rgb, img_com, inliers);
  cv::namedWindow("Inliers", cv::WINDOW_NORMAL);
  cv::imshow("Inliers",img_com);
  cv::waitKey(0);
}

/* ************************************************************************* */
int parse_input_options(AKAZEOptions& options, std::string& img_path1, std::string& img_path2,
                        std::string& homography_path, int argc, char *argv[]) {

  // If there is only one argument return
  if (argc == 1) {
    show_input_options_help(1);
    return -1;
  }
  // Set the options from the command line
  else if (argc >= 2) {

    // Load the default options
    options = AKAZEOptions();

    if (!strcmp(argv[1],"--help")) {
      show_input_options_help(1);
      return -1;
    }

    img_path1 = argv[1];
    img_path2 = argv[2];

    if (argc >= 4)
     homography_path = argv[3];

    for (int i = 3; i < argc; i++) {
      if (!strcmp(argv[i],"--soffset")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.soffset = atof(argv[i]);
        }
      }
      else if (!strcmp(argv[i],"--omax")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.omax = atof(argv[i]);
        }
      }
      else if ( !strcmp(argv[i],"--dthreshold")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.dthreshold = atof(argv[i]);
        }
      }
      else if (!strcmp(argv[i],"--sderivatives")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.sderivatives = atof(argv[i]);
        }
      }
      else if (!strcmp(argv[i],"--nsublevels")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.nsublevels = atoi(argv[i]);
        }
      }
      else if (!strcmp(argv[i],"--diffusivity"))
      {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.diffusivity = DIFFUSIVITY_TYPE(atoi(argv[i]));
        }
      }
      else if (!strcmp(argv[i],"--descriptor")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.descriptor = DESCRIPTOR_TYPE(atoi(argv[i]));

          if (options.descriptor < 0 || options.descriptor > MLDB) {
            options.descriptor = MLDB;
          }
        }
      }
      else if (!strcmp(argv[i],"--descriptor_channels")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.descriptor_channels = atoi(argv[i]);

          if (options.descriptor_channels <= 0 || options.descriptor_channels > 3 ) {
            options.descriptor_channels = 3;
          }
        }
      }
      else if (!strcmp(argv[i],"--descriptor_size")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.descriptor_size = atoi(argv[i]);

          if (options.descriptor_size < 0) {
            options.descriptor_size = 0;
          }
        }
      }
      else if (!strcmp(argv[i],"--verbose")) {
        options.verbosity = true;
      }
      else if (!strncmp(argv[i],"--",2))
        cerr << "Unknown command "<<argv[i] << endl;
    }
  }
  else {
    cerr << "Error introducing input options!!" << endl;
    show_input_options_help(1);
    return -1;
  }

  return 0;
}
<commit_msg>added cuda profiler calls<commit_after>//=============================================================================
//
// akaze_match.cpp
// Authors: Pablo F. Alcantarilla (1), Jesus Nuevo (2)
// Institutions: Toshiba Research Europe Ltd (1)
//               TrueVision Solutions (2)
// Date: 07/10/2014
// Email: pablofdezalc@gmail.com
//
// AKAZE Features Copyright 2014, Pablo F. Alcantarilla, Jesus Nuevo
// All Rights Reserved
// See LICENSE for the license information
//=============================================================================

/**
 * @file akaze_match.cpp
 * @brief Main program for matching two images with AKAZE features
 * @date Oct 07, 2014
 * @author Pablo F. Alcantarilla
 */

#include "./lib/AKAZE.h"

// OpenCV
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <cuda_profiler_api.h>

using namespace std;
using namespace libAKAZECU;

/* ************************************************************************* */
// Image matching options
const float MIN_H_ERROR = 2.50f;            ///< Maximum error in pixels to accept an inlier
const float DRATIO = 0.80f;                 ///< NNDR Matching value

/* ************************************************************************* */
/**
 * @brief This function parses the command line arguments for setting A-KAZE parameters
 * and image matching between two input images
 * @param options Structure that contains A-KAZE settings
 * @param img_path1 Path for the first input image
 * @param img_path2 Path for the second input image
 * @param homography_path Path for the file that contains the ground truth homography
 */
int parse_input_options(AKAZEOptions &options, std::string& img_path1,
                        std::string& img_path2, std::string& homography_path,
                        int argc, char *argv[]);

/* ************************************************************************* */
int main(int argc, char *argv[]) {

  // Variables
  AKAZEOptions options;
  cv::Mat img1, img1_32, img2, img2_32, img1_rgb, img2_rgb, img_com, img_r;
  string img_path1, img_path2, homography_path;
  float ratio = 0.0, rfactor = .60;
  int nkpts1 = 0, nkpts2 = 0, nmatches = 0, ninliers = 0, noutliers = 0;

  vector<cv::KeyPoint> kpts1, kpts2;
  vector<vector<cv::DMatch> > dmatches;
  cv::Mat desc1, desc2;
  cv::Mat HG;

  // Variables for measuring computation times
  double t1 = 0.0, t2 = 0.0;
  double takaze = 0.0, tmatch = 0.0;

  // Parse the input command line options
  if (parse_input_options(options,img_path1,img_path2,homography_path,argc,argv))
    return -1;

  // Read image 1 and if necessary convert to grayscale.
  img1 = cv::imread(img_path1, 0);
  if (img1.data == NULL) {
    cerr << "Error loading image 1: " << img_path1 << endl;
    return -1;
  }

  // Read image 2 and if necessary convert to grayscale.
  img2 = cv::imread(img_path2, 0);
  if (img2.data == NULL) {
    cerr << "Error loading image 2: " << img_path2 << endl;
    return -1;
  }

  // Read ground truth homography file
  bool use_ransac = false;
  if (read_homography(homography_path, HG) == false)
    use_ransac = true;

  // Convert the images to float
  img1.convertTo(img1_32, CV_32F, 1.0/255.0, 0);
  img2.convertTo(img2_32, CV_32F, 1.0/255.0, 0);

  // Color images for results visualization
  img1_rgb = cv::Mat(cv::Size(img1.cols, img1.rows), CV_8UC3);
  img2_rgb = cv::Mat(cv::Size(img2.cols, img1.rows), CV_8UC3);
  img_com = cv::Mat(cv::Size(img1.cols*2, img1.rows), CV_8UC3);
  img_r = cv::Mat(cv::Size(img_com.cols*rfactor, img_com.rows*rfactor), CV_8UC3);

  // Create the first AKAZE object
  options.img_width = img1.cols;
  options.img_height = img1.rows;
  AKAZE evolution1(options);

  // Create the second HKAZE object
  options.img_width = img2.cols;
  options.img_height = img2.rows;
  AKAZE evolution2(options);

  t1 = cv::getTickCount();

  cudaProfilerStart();

  evolution1.Create_Nonlinear_Scale_Space(img1_32);
  evolution1.Feature_Detection(kpts1);
  evolution1.Compute_Descriptors(kpts1, desc1);

  evolution2.Create_Nonlinear_Scale_Space(img2_32);
  evolution2.Feature_Detection(kpts2);
  evolution2.Compute_Descriptors(kpts2, desc2);

  t2 = cv::getTickCount();
  takaze = 1000.0*(t2-t1)/cv::getTickFrequency();

  // Matching Descriptors!!
  vector<cv::Point2f> matches, inliers;
  cv::Ptr<cv::DescriptorMatcher> matcher_l2 = cv::DescriptorMatcher::create("BruteForce");
  cv::Ptr<cv::DescriptorMatcher> matcher_l1 = cv::DescriptorMatcher::create("BruteForce-Hamming");

  t1 = cv::getTickCount();

  MatchDescriptors(desc1, desc2, dmatches);

  cudaProfilerStop();

  t2 = cv::getTickCount();
  tmatch = 1000.0*(t2 - t1)/ cv::getTickFrequency();

  /*t1 = cv::getTickCount();

  if (options.descriptor < MLDB_UPRIGHT)
    matcher_l2->knnMatch(desc1, desc2, dmatches, 2);
  else
    matcher_l1->knnMatch(desc1, desc2, dmatches, 2);

  t2 = cv::getTickCount();
  tmatch = 1000.0*(t2 - t1)/ cv::getTickFrequency();*/

  // Compute Inliers!!
  matches2points_nndr(kpts1, kpts2, dmatches, matches, DRATIO);

  if (use_ransac == false)
    compute_inliers_homography(matches, inliers, HG, MIN_H_ERROR);
  else
    compute_inliers_ransac(matches, inliers, MIN_H_ERROR, false);

  // Compute the inliers statistics
  nkpts1 = kpts1.size();
  nkpts2 = kpts2.size();
  nmatches = matches.size()/2;
  ninliers = inliers.size()/2;
  noutliers = nmatches - ninliers;
  ratio = 100.0*((float) ninliers / (float) nmatches);

  // Prepare the visualization
  cvtColor(img1, img1_rgb, cv::COLOR_GRAY2BGR);
  cvtColor(img2, img2_rgb, cv::COLOR_GRAY2BGR);

  // Show matching statistics
  cout << "Number of Keypoints Image 1: " << nkpts1 << endl;
  cout << "Number of Keypoints Image 2: " << nkpts2 << endl;
  cout << "A-KAZE Features Extraction Time (ms): " << takaze << endl;
  cout << "Matching Descriptors Time (ms): " << tmatch << endl;
  cout << "Number of Matches: " << nmatches << endl;
  cout << "Number of Inliers: " << ninliers << endl;
  cout << "Number of Outliers: " << noutliers << endl;
  cout << "Inliers Ratio: " << ratio << endl << endl;

  draw_keypoints(img1_rgb, kpts1);
  draw_keypoints(img2_rgb, kpts2);
  draw_inliers(img1_rgb, img2_rgb, img_com, inliers);
  cv::namedWindow("Inliers", cv::WINDOW_NORMAL);
  cv::imshow("Inliers",img_com);
  cv::waitKey(0);
}

/* ************************************************************************* */
int parse_input_options(AKAZEOptions& options, std::string& img_path1, std::string& img_path2,
                        std::string& homography_path, int argc, char *argv[]) {

  // If there is only one argument return
  if (argc == 1) {
    show_input_options_help(1);
    return -1;
  }
  // Set the options from the command line
  else if (argc >= 2) {

    // Load the default options
    options = AKAZEOptions();

    if (!strcmp(argv[1],"--help")) {
      show_input_options_help(1);
      return -1;
    }

    img_path1 = argv[1];
    img_path2 = argv[2];

    if (argc >= 4)
     homography_path = argv[3];

    for (int i = 3; i < argc; i++) {
      if (!strcmp(argv[i],"--soffset")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.soffset = atof(argv[i]);
        }
      }
      else if (!strcmp(argv[i],"--omax")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.omax = atof(argv[i]);
        }
      }
      else if ( !strcmp(argv[i],"--dthreshold")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.dthreshold = atof(argv[i]);
        }
      }
      else if (!strcmp(argv[i],"--sderivatives")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.sderivatives = atof(argv[i]);
        }
      }
      else if (!strcmp(argv[i],"--nsublevels")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.nsublevels = atoi(argv[i]);
        }
      }
      else if (!strcmp(argv[i],"--diffusivity"))
      {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.diffusivity = DIFFUSIVITY_TYPE(atoi(argv[i]));
        }
      }
      else if (!strcmp(argv[i],"--descriptor")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.descriptor = DESCRIPTOR_TYPE(atoi(argv[i]));

          if (options.descriptor < 0 || options.descriptor > MLDB) {
            options.descriptor = MLDB;
          }
        }
      }
      else if (!strcmp(argv[i],"--descriptor_channels")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.descriptor_channels = atoi(argv[i]);

          if (options.descriptor_channels <= 0 || options.descriptor_channels > 3 ) {
            options.descriptor_channels = 3;
          }
        }
      }
      else if (!strcmp(argv[i],"--descriptor_size")) {
        i = i+1;
        if (i >= argc) {
          cerr << "Error introducing input options!!" << endl;
          return -1;
        }
        else {
          options.descriptor_size = atoi(argv[i]);

          if (options.descriptor_size < 0) {
            options.descriptor_size = 0;
          }
        }
      }
      else if (!strcmp(argv[i],"--verbose")) {
        options.verbosity = true;
      }
      else if (!strncmp(argv[i],"--",2))
        cerr << "Unknown command "<<argv[i] << endl;
    }
  }
  else {
    cerr << "Error introducing input options!!" << endl;
    show_input_options_help(1);
    return -1;
  }

  return 0;
}
<|endoftext|>