<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/lite/delegates/gpu/common/tasks/elementwise.h"

#include <memory>
#include <string>
#include <utility>

#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"

namespace tflite {
namespace gpu {

namespace {
std::string GetOneInputCode(const GpuInfo& gpu_info,
                            const OperationType& op_type,
                            CalculationsPrecision precision,
                            const std::string& input_value,
                            const std::string& output_value) {
  const bool use_native_opencl_functions =
      gpu_info.IsApiOpenCl() && precision != CalculationsPrecision::F32 &&
      gpu_info.IsAdreno();
  std::string result;
  switch (op_type) {
    case OperationType::ABS:
      result = "$0 = fabs($1);";
      break;
    case OperationType::COS:
      if (use_native_opencl_functions) {
        result = "$0 = convert_half4(native_cos(convert_float4($1)));";
      } else {
        result = "$0 = cos($1);";
      }
      break;
    case OperationType::COPY:
      result = "$0 = $1;";
      break;
    case OperationType::ELU:
      if (gpu_info.IsApiOpenCl()) {
        result = R"(
$0.x = $1.x < INIT_FLT(0.0f) ? expm1($1.x) : $1.x;
$0.y = $1.y < INIT_FLT(0.0f) ? expm1($1.y) : $1.y;
$0.z = $1.z < INIT_FLT(0.0f) ? expm1($1.z) : $1.z;
$0.w = $1.w < INIT_FLT(0.0f) ? expm1($1.w) : $1.w;)";
      } else {
        result = R"(
$0.x = $1.x < INIT_FLT(0.0f) ? exp($1.x) - INIT_FLT(1.0f) : $1.x;
$0.y = $1.y < INIT_FLT(0.0f) ? exp($1.y) - INIT_FLT(1.0f) : $1.y;
$0.z = $1.z < INIT_FLT(0.0f) ? exp($1.z) - INIT_FLT(1.0f) : $1.z;
$0.w = $1.w < INIT_FLT(0.0f) ? exp($1.w) - INIT_FLT(1.0f) : $1.w;)";
      }
      break;
    case OperationType::EXP:
      if (use_native_opencl_functions) {
        result = "$0 = convert_half4(native_exp(convert_float4($1)));";
      } else {
        result = "$0 = exp($1);";
      }
      break;
    case OperationType::FLOOR:
      result = "$0 = floor($1);";
      break;
    case OperationType::HARD_SWISH:
      result =
          "$0 = $1 * clamp($1 * INIT_FLT(0.16666667f) + INIT_FLT(0.5f), "
          "INIT_FLT4(0.0f), "
          "INIT_FLT4(1.0f));";
      break;
    case OperationType::LOG:
      if (use_native_opencl_functions) {
        result = "$0 = convert_half4(native_log(convert_float4($1)));";
      } else {
        result = "$0 = log($1);";
      }
      break;
    case OperationType::NEG:
      result = "$0 = -($1);";
      break;
    case OperationType::RSQRT:
      if (use_native_opencl_functions) {
        result = "$0 = convert_half4(native_rsqrt(convert_float4($1)));";
      } else {
        result = "$0 = rsqrt($1);";
      }
      break;
    case OperationType::SIGMOID:
      if (use_native_opencl_functions) {
        result =
            "$0 = convert_half4(native_recip(1.0f + "
            "native_exp(convert_float4(-$1))));";
      } else {
        result = "$0 = INIT_FLT4(1.0f) / (INIT_FLT4(1.0f) + exp(-($1)));";
      }
      break;
    case OperationType::SIN:
      if (use_native_opencl_functions) {
        result = "$0 = convert_half4(native_sin(convert_float4($1)));";
      } else {
        result = "$0 = sin($1);";
      }
      break;
    case OperationType::SQRT:
      if (use_native_opencl_functions) {
        result = "$0 = convert_half4(native_sqrt(convert_float4($1)));";
      } else {
        result = "$0 = sqrt($1);";
      }
      break;
    case OperationType::SQUARE:
      result = "$0 = $1 * $1;";
      break;
    case OperationType::TANH:
      if (use_native_opencl_functions) {
        result =
            "  FLT4 exp_val = convert_half4(native_exp(2.0f * "
            "convert_float4($1)));";
        result +=
            "$0 = ((exp_val - INIT_FLT4(1.0f)) / (exp_val + "
            "INIT_FLT4(1.0f)));";
      } else {
        result = "$0 = tanh($1);";
      }
      break;
    default:
      return "Unknown operation type;";
  }
  return absl::Substitute(result, output_value, input_value);
}

std::string GetTwoInputCode(const OperationType& op_type,
                            const std::string& result_var,
                            const std::string& input0,
                            const std::string& input1,
                            bool swap_inputs = false) {
  std::string result;
  switch (op_type) {
    case OperationType::ADD:
      result += "$0 = $1 + $2;";
      break;
    case OperationType::DIV:
      result += "$0 = $1 / $2;";
      break;
    case OperationType::FLOOR_DIV:
      result = "$0 = floor($1 / $2);";
      break;
    case OperationType::FLOOR_MOD:
      result = "$0 = $1 - floor($1 / $2) * $2;";
      break;
    case OperationType::MAXIMUM:
      result += "$0 = max($1, $2);";
      break;
    case OperationType::MINIMUM:
      result += "$0 = min($1, $2);";
      break;
    case OperationType::MUL:
      result += "$0 = $1 * $2;";
      break;
    case OperationType::POW:
      result += "$0 = pow($1, $2);";
      break;
    case OperationType::SQUARED_DIFF:
      result += "$0 = ($1 - $2) * ($1 - $2);";
      break;
    case OperationType::SUB:
      result += "$0 = $1 - $2;";
      break;
    // Comparison operators
    case OperationType::LESS:
      result = "$0.x = $1.x < $2.x;\n";
      result += "$0.y = $1.y < $2.y;\n";
      result += "$0.z = $1.z < $2.z;\n";
      result += "$0.w = $1.w < $2.w;";
      break;
    case OperationType::LESS_EQUAL:
      result = "$0.x = $1.x <= $2.x;\n";
      result += "$0.y = $1.y <= $2.y;\n";
      result += "$0.z = $1.z <= $2.z;\n";
      result += "$0.w = $1.w <= $2.w;";
      break;
    case OperationType::GREATER:
      result = "$0.x = $1.x > $2.x;\n";
      result += "$0.y = $1.y > $2.y;\n";
      result += "$0.z = $1.z > $2.z;\n";
      result += "$0.w = $1.w > $2.w;";
      break;
    case OperationType::GREATER_EQUAL:
      result = "$0.x = $1.x >= $2.x;\n";
      result += "$0.y = $1.y >= $2.y;\n";
      result += "$0.z = $1.z >= $2.z;\n";
      result += "$0.w = $1.w >= $2.w;";
      break;
    case OperationType::EQUAL:
      result = "$0.x = $1.x == $2.x;\n";
      result += "$0.y = $1.y == $2.y;\n";
      result += "$0.z = $1.z == $2.z;\n";
      result += "$0.w = $1.w == $2.w;";
      break;
    case OperationType::NOT_EQUAL:
      result = "$0.x = $1.x != $2.x;\n";
      result += "$0.y = $1.y != $2.y;\n";
      result += "$0.z = $1.z != $2.z;\n";
      result += "$0.w = $1.w != $2.w;";
      break;
    default:
      return "Unknown operation type;";
  }
  if (swap_inputs) {
    return absl::Substitute(result, result_var, input1, input0);
  } else {
    return absl::Substitute(result, result_var, input0, input1);
  }
}

// Creates simple two input (first input is runtime tensor and second input is
// scalar argument) operation, for example sub, div, pow, etc.
GPUOperation CreateElementwiseOneRuntimeOneScalar(
    const OperationDef& definition, const OperationType& op_type,
    float scalar_parameter, bool swap_inputs) {
  ElementwiseDescriptor op_desc;
  if (definition.precision == CalculationsPrecision::F32) {
    op_desc.args.AddFloat("scalar", scalar_parameter);
  } else {
    op_desc.args.AddHalf("scalar", half(scalar_parameter));
  }
  op_desc.code = "FLT4 second_val = INIT_FLT4(args.scalar);\n";
  op_desc.code += GetTwoInputCode(op_type, "out_value", "in_value",
                                  "second_val", swap_inputs);
  return CreateGpuOperation(definition, std::move(op_desc));
}

// Creates simple two input(first input is runtime tensor and second input is
// constant linear tensor) operation, for example sub, div and etc.
GPUOperation CreateElementwiseTwoInput(
    const GpuInfo& gpu_info, const OperationDef& definition,
    const OperationType& op_type,
    const tflite::gpu::Tensor<Linear, DataType::FLOAT32>& constant_tensor,
    bool swap_inputs) {
  TensorDescriptor const_tensor_desc = CreateConstantLinearTensorDescriptor(
      gpu_info, definition.src_tensors[0].GetDataType(), constant_tensor);
  ElementwiseDescriptor op_desc;
  op_desc.args.AddObject("second_tensor", std::make_unique<TensorDescriptor>(
                                              std::move(const_tensor_desc)));
  const std::string s_coord = constant_tensor.shape.v == 1 ? "0" : "S_COORD";
  op_desc.code = absl::StrCat(
      "args.second_tensor::type second_val = args.second_tensor.Read(", s_coord,
      ");\n");
  if (constant_tensor.shape.v == 1) {
    op_desc.code += "  second_val.y = second_val.x;\n";
    op_desc.code += "  second_val.z = second_val.x;\n";
    op_desc.code += "  second_val.w = second_val.x;\n";
  }
  op_desc.code += GetTwoInputCode(op_type, "out_value", "in_value",
                                  "second_val", swap_inputs);
  return CreateGpuOperation(definition, std::move(op_desc));
}

// Creates simple two input(first input is runtime tensor and second input is
// constant HWC tensor) operation, for example sub, div and etc.
GPUOperation CreateElementwiseTwoInput(
    const GpuInfo& gpu_info, const OperationDef& definition,
    const OperationType& op_type,
    const tflite::gpu::Tensor<HWC, DataType::FLOAT32>& constant_tensor,
    bool swap_inputs) {
  const BHWC shape = BHWC(1, constant_tensor.shape.h, constant_tensor.shape.w,
                          constant_tensor.shape.c);
  TensorDescriptor const_tensor_desc = definition.src_tensors[0];
  auto status = const_tensor_desc.UpdateToSupportedStorageType(gpu_info, shape);
  const_tensor_desc.UploadData(constant_tensor);

  ElementwiseDescriptor op_desc;
  op_desc.args.AddObject("second_tensor", std::make_unique<TensorDescriptor>(
                                              std::move(const_tensor_desc)));
  const std::string x_coord = shape.w == 1 ? "0" : "X_COORD";
  const std::string y_coord = shape.h == 1 ? "0" : "Y_COORD";
  const std::string s_coord = shape.c == 1 ? "0" : "S_COORD";
  op_desc.code = absl::StrCat(
      "args.second_tensor::type second_val = args.second_tensor.Read(", x_coord,
      ", ", y_coord, ", ", s_coord, ");\n");
  if (shape.c == 1) {
    op_desc.code += "  second_val.y = second_val.x;\n";
    op_desc.code += "  second_val.z = second_val.x;\n";
    op_desc.code += "  second_val.w = second_val.x;\n";
  }
  op_desc.code += GetTwoInputCode(op_type, "out_value", "in_value",
                                  "second_val", swap_inputs);

  return CreateGpuOperation(definition, std::move(op_desc));
}

}  // namespace

GPUOperation CreateElementwiseOneInput(const GpuInfo& gpu_info,
                                       const OperationDef& definition,
                                       const OperationType& op_type) {
  ElementwiseDescriptor op_desc;
  op_desc.code = GetOneInputCode(gpu_info, op_type, definition.precision,
                                 "in_value", "out_value");
  return CreateGpuOperation(definition, std::move(op_desc));
}

GPUOperation CreateElementwise(const GpuInfo& gpu_info,
                               const OperationDef& definition,
                               const OperationType& op_type,
                               const ElementwiseAttributes& attr) {
  const float* scalar = absl::get_if<float>(&attr.param);
  const auto* linear_tensor =
      absl::get_if<tflite::gpu::Tensor<Linear, DataType::FLOAT32>>(&attr.param);
  const auto* hwc_tensor =
      absl::get_if<tflite::gpu::Tensor<HWC, DataType::FLOAT32>>(&attr.param);

  if (scalar) {
    return CreateElementwiseOneRuntimeOneScalar(definition, op_type, *scalar,
                                                attr.runtime_tensor_is_second);
  } else if (linear_tensor) {
    return CreateElementwiseTwoInput(gpu_info, definition, op_type,
                                     *linear_tensor,
                                     attr.runtime_tensor_is_second);
  } else if (hwc_tensor) {
    return CreateElementwiseTwoInput(gpu_info, definition, op_type, *hwc_tensor,
                                     attr.runtime_tensor_is_second);
  } else {
    return GPUOperation(definition);
  }
}

GPUOperation CreateElementwiseTwoInput(const OperationDef& definition,
                                       const OperationType& op_type,
                                       const BHWC& shape) {
  ElementwiseDescriptor op_desc;
  op_desc.code =
      GetTwoInputCode(op_type, "out_value", "in_value", "in2_value", false);
  return CreateGpuOperation(definition, std::move(op_desc), shape);
}

}  // namespace gpu
}  // namespace tflite
<commit_msg>Small syntax changes to tanh.<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/lite/delegates/gpu/common/tasks/elementwise.h"

#include <memory>
#include <string>
#include <utility>

#include "absl/strings/str_cat.h"
#include "absl/strings/substitute.h"

namespace tflite {
namespace gpu {

namespace {
std::string GetOneInputCode(const GpuInfo& gpu_info,
                            const OperationType& op_type,
                            CalculationsPrecision precision,
                            const std::string& input_value,
                            const std::string& output_value) {
  const bool use_native_opencl_functions =
      gpu_info.IsApiOpenCl() && precision != CalculationsPrecision::F32 &&
      gpu_info.IsAdreno();
  std::string result;
  switch (op_type) {
    case OperationType::ABS:
      result = "$0 = fabs($1);";
      break;
    case OperationType::COS:
      if (use_native_opencl_functions) {
        result = "$0 = convert_half4(native_cos(convert_float4($1)));";
      } else {
        result = "$0 = cos($1);";
      }
      break;
    case OperationType::COPY:
      result = "$0 = $1;";
      break;
    case OperationType::ELU:
      if (gpu_info.IsApiOpenCl()) {
        result = R"(
$0.x = $1.x < INIT_FLT(0.0f) ? expm1($1.x) : $1.x;
$0.y = $1.y < INIT_FLT(0.0f) ? expm1($1.y) : $1.y;
$0.z = $1.z < INIT_FLT(0.0f) ? expm1($1.z) : $1.z;
$0.w = $1.w < INIT_FLT(0.0f) ? expm1($1.w) : $1.w;)";
      } else {
        result = R"(
$0.x = $1.x < INIT_FLT(0.0f) ? exp($1.x) - INIT_FLT(1.0f) : $1.x;
$0.y = $1.y < INIT_FLT(0.0f) ? exp($1.y) - INIT_FLT(1.0f) : $1.y;
$0.z = $1.z < INIT_FLT(0.0f) ? exp($1.z) - INIT_FLT(1.0f) : $1.z;
$0.w = $1.w < INIT_FLT(0.0f) ? exp($1.w) - INIT_FLT(1.0f) : $1.w;)";
      }
      break;
    case OperationType::EXP:
      if (use_native_opencl_functions) {
        result = "$0 = convert_half4(native_exp(convert_float4($1)));";
      } else {
        result = "$0 = exp($1);";
      }
      break;
    case OperationType::FLOOR:
      result = "$0 = floor($1);";
      break;
    case OperationType::HARD_SWISH:
      result =
          "$0 = $1 * clamp($1 * INIT_FLT(0.16666667f) + INIT_FLT(0.5f), "
          "INIT_FLT4(0.0f), "
          "INIT_FLT4(1.0f));";
      break;
    case OperationType::LOG:
      if (use_native_opencl_functions) {
        result = "$0 = convert_half4(native_log(convert_float4($1)));";
      } else {
        result = "$0 = log($1);";
      }
      break;
    case OperationType::NEG:
      result = "$0 = -($1);";
      break;
    case OperationType::RSQRT:
      if (use_native_opencl_functions) {
        result = "$0 = convert_half4(native_rsqrt(convert_float4($1)));";
      } else {
        result = "$0 = rsqrt($1);";
      }
      break;
    case OperationType::SIGMOID:
      if (use_native_opencl_functions) {
        result =
            "$0 = convert_half4(native_recip(1.0f + "
            "native_exp(convert_float4(-$1))));";
      } else {
        result = "$0 = INIT_FLT4(1.0f) / (INIT_FLT4(1.0f) + exp(-($1)));";
      }
      break;
    case OperationType::SIN:
      if (use_native_opencl_functions) {
        result = "$0 = convert_half4(native_sin(convert_float4($1)));";
      } else {
        result = "$0 = sin($1);";
      }
      break;
    case OperationType::SQRT:
      if (use_native_opencl_functions) {
        result = "$0 = convert_half4(native_sqrt(convert_float4($1)));";
      } else {
        result = "$0 = sqrt($1);";
      }
      break;
    case OperationType::SQUARE:
      result = "$0 = $1 * $1;";
      break;
    case OperationType::TANH:
      if (use_native_opencl_functions) {
        result =
            "FLT4 exp_val = convert_half4(native_exp(2.0f * "
            "convert_float4($1)));\n";
        result +=
            "$0 = ((exp_val - INIT_FLT4(1.0f)) / (exp_val + "
            "INIT_FLT4(1.0f)));";
      } else {
        result = "$0 = tanh($1);";
      }
      break;
    default:
      return "Unknown operation type;";
  }
  return absl::Substitute(result, output_value, input_value);
}

std::string GetTwoInputCode(const OperationType& op_type,
                            const std::string& result_var,
                            const std::string& input0,
                            const std::string& input1,
                            bool swap_inputs = false) {
  std::string result;
  switch (op_type) {
    case OperationType::ADD:
      result += "$0 = $1 + $2;";
      break;
    case OperationType::DIV:
      result += "$0 = $1 / $2;";
      break;
    case OperationType::FLOOR_DIV:
      result = "$0 = floor($1 / $2);";
      break;
    case OperationType::FLOOR_MOD:
      result = "$0 = $1 - floor($1 / $2) * $2;";
      break;
    case OperationType::MAXIMUM:
      result += "$0 = max($1, $2);";
      break;
    case OperationType::MINIMUM:
      result += "$0 = min($1, $2);";
      break;
    case OperationType::MUL:
      result += "$0 = $1 * $2;";
      break;
    case OperationType::POW:
      result += "$0 = pow($1, $2);";
      break;
    case OperationType::SQUARED_DIFF:
      result += "$0 = ($1 - $2) * ($1 - $2);";
      break;
    case OperationType::SUB:
      result += "$0 = $1 - $2;";
      break;
    // Comparison operators
    case OperationType::LESS:
      result = "$0.x = $1.x < $2.x;\n";
      result += "$0.y = $1.y < $2.y;\n";
      result += "$0.z = $1.z < $2.z;\n";
      result += "$0.w = $1.w < $2.w;";
      break;
    case OperationType::LESS_EQUAL:
      result = "$0.x = $1.x <= $2.x;\n";
      result += "$0.y = $1.y <= $2.y;\n";
      result += "$0.z = $1.z <= $2.z;\n";
      result += "$0.w = $1.w <= $2.w;";
      break;
    case OperationType::GREATER:
      result = "$0.x = $1.x > $2.x;\n";
      result += "$0.y = $1.y > $2.y;\n";
      result += "$0.z = $1.z > $2.z;\n";
      result += "$0.w = $1.w > $2.w;";
      break;
    case OperationType::GREATER_EQUAL:
      result = "$0.x = $1.x >= $2.x;\n";
      result += "$0.y = $1.y >= $2.y;\n";
      result += "$0.z = $1.z >= $2.z;\n";
      result += "$0.w = $1.w >= $2.w;";
      break;
    case OperationType::EQUAL:
      result = "$0.x = $1.x == $2.x;\n";
      result += "$0.y = $1.y == $2.y;\n";
      result += "$0.z = $1.z == $2.z;\n";
      result += "$0.w = $1.w == $2.w;";
      break;
    case OperationType::NOT_EQUAL:
      result = "$0.x = $1.x != $2.x;\n";
      result += "$0.y = $1.y != $2.y;\n";
      result += "$0.z = $1.z != $2.z;\n";
      result += "$0.w = $1.w != $2.w;";
      break;
    default:
      return "Unknown operation type;";
  }
  if (swap_inputs) {
    return absl::Substitute(result, result_var, input1, input0);
  } else {
    return absl::Substitute(result, result_var, input0, input1);
  }
}

// Creates simple two input (first input is runtime tensor and second input is
// scalar argument) operation, for example sub, div, pow, etc.
GPUOperation CreateElementwiseOneRuntimeOneScalar(
    const OperationDef& definition, const OperationType& op_type,
    float scalar_parameter, bool swap_inputs) {
  ElementwiseDescriptor op_desc;
  if (definition.precision == CalculationsPrecision::F32) {
    op_desc.args.AddFloat("scalar", scalar_parameter);
  } else {
    op_desc.args.AddHalf("scalar", half(scalar_parameter));
  }
  op_desc.code = "FLT4 second_val = INIT_FLT4(args.scalar);\n";
  op_desc.code += GetTwoInputCode(op_type, "out_value", "in_value",
                                  "second_val", swap_inputs);
  return CreateGpuOperation(definition, std::move(op_desc));
}

// Creates simple two input(first input is runtime tensor and second input is
// constant linear tensor) operation, for example sub, div and etc.
GPUOperation CreateElementwiseTwoInput(
    const GpuInfo& gpu_info, const OperationDef& definition,
    const OperationType& op_type,
    const tflite::gpu::Tensor<Linear, DataType::FLOAT32>& constant_tensor,
    bool swap_inputs) {
  TensorDescriptor const_tensor_desc = CreateConstantLinearTensorDescriptor(
      gpu_info, definition.src_tensors[0].GetDataType(), constant_tensor);
  ElementwiseDescriptor op_desc;
  op_desc.args.AddObject("second_tensor", std::make_unique<TensorDescriptor>(
                                              std::move(const_tensor_desc)));
  const std::string s_coord = constant_tensor.shape.v == 1 ? "0" : "S_COORD";
  op_desc.code = absl::StrCat(
      "args.second_tensor::type second_val = args.second_tensor.Read(", s_coord,
      ");\n");
  if (constant_tensor.shape.v == 1) {
    op_desc.code += "  second_val.y = second_val.x;\n";
    op_desc.code += "  second_val.z = second_val.x;\n";
    op_desc.code += "  second_val.w = second_val.x;\n";
  }
  op_desc.code += GetTwoInputCode(op_type, "out_value", "in_value",
                                  "second_val", swap_inputs);
  return CreateGpuOperation(definition, std::move(op_desc));
}

// Creates simple two input(first input is runtime tensor and second input is
// constant HWC tensor) operation, for example sub, div and etc.
GPUOperation CreateElementwiseTwoInput(
    const GpuInfo& gpu_info, const OperationDef& definition,
    const OperationType& op_type,
    const tflite::gpu::Tensor<HWC, DataType::FLOAT32>& constant_tensor,
    bool swap_inputs) {
  const BHWC shape = BHWC(1, constant_tensor.shape.h, constant_tensor.shape.w,
                          constant_tensor.shape.c);
  TensorDescriptor const_tensor_desc = definition.src_tensors[0];
  auto status = const_tensor_desc.UpdateToSupportedStorageType(gpu_info, shape);
  const_tensor_desc.UploadData(constant_tensor);

  ElementwiseDescriptor op_desc;
  op_desc.args.AddObject("second_tensor", std::make_unique<TensorDescriptor>(
                                              std::move(const_tensor_desc)));
  const std::string x_coord = shape.w == 1 ? "0" : "X_COORD";
  const std::string y_coord = shape.h == 1 ? "0" : "Y_COORD";
  const std::string s_coord = shape.c == 1 ? "0" : "S_COORD";
  op_desc.code = absl::StrCat(
      "args.second_tensor::type second_val = args.second_tensor.Read(", x_coord,
      ", ", y_coord, ", ", s_coord, ");\n");
  if (shape.c == 1) {
    op_desc.code += "  second_val.y = second_val.x;\n";
    op_desc.code += "  second_val.z = second_val.x;\n";
    op_desc.code += "  second_val.w = second_val.x;\n";
  }
  op_desc.code += GetTwoInputCode(op_type, "out_value", "in_value",
                                  "second_val", swap_inputs);

  return CreateGpuOperation(definition, std::move(op_desc));
}

}  // namespace

GPUOperation CreateElementwiseOneInput(const GpuInfo& gpu_info,
                                       const OperationDef& definition,
                                       const OperationType& op_type) {
  ElementwiseDescriptor op_desc;
  op_desc.code = GetOneInputCode(gpu_info, op_type, definition.precision,
                                 "in_value", "out_value");
  return CreateGpuOperation(definition, std::move(op_desc));
}

GPUOperation CreateElementwise(const GpuInfo& gpu_info,
                               const OperationDef& definition,
                               const OperationType& op_type,
                               const ElementwiseAttributes& attr) {
  const float* scalar = absl::get_if<float>(&attr.param);
  const auto* linear_tensor =
      absl::get_if<tflite::gpu::Tensor<Linear, DataType::FLOAT32>>(&attr.param);
  const auto* hwc_tensor =
      absl::get_if<tflite::gpu::Tensor<HWC, DataType::FLOAT32>>(&attr.param);

  if (scalar) {
    return CreateElementwiseOneRuntimeOneScalar(definition, op_type, *scalar,
                                                attr.runtime_tensor_is_second);
  } else if (linear_tensor) {
    return CreateElementwiseTwoInput(gpu_info, definition, op_type,
                                     *linear_tensor,
                                     attr.runtime_tensor_is_second);
  } else if (hwc_tensor) {
    return CreateElementwiseTwoInput(gpu_info, definition, op_type, *hwc_tensor,
                                     attr.runtime_tensor_is_second);
  } else {
    return GPUOperation(definition);
  }
}

GPUOperation CreateElementwiseTwoInput(const OperationDef& definition,
                                       const OperationType& op_type,
                                       const BHWC& shape) {
  ElementwiseDescriptor op_desc;
  op_desc.code =
      GetTwoInputCode(op_type, "out_value", "in_value", "in2_value", false);
  return CreateGpuOperation(definition, std::move(op_desc), shape);
}

}  // namespace gpu
}  // namespace tflite
<|endoftext|>


<commit_before>/*
 * Jamoma N-Dimensional Matrix Data Class
 * Copyright © 2011, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTMatrix.h"

#define thisTTClass			TTMatrix
#define thisTTClassName		"matrix"
#define thisTTClassTags		"matrix"

TT_OBJECT_CONSTRUCTOR,
	mData(NULL),
	mDataSize(0),
	mType(TT("uint8")),
	mElementCount(1)
{
	addAttributeWithGetterAndSetter(Dimensions, kTypeUInt32);
	addAttributeWithSetter(Type,				kTypeUInt8);
	addAttributeWithSetter(ElementCount,		kTypeUInt8);

	addMessage(clear);
	addMessageWithArgument(fill);
	addMessageWithArgument(get);
	addMessageWithArgument(set);

	// TODO: getLockedPointer -- returns a pointer to the data, locks the matrix mutex
	// TODO: releaseLockedPointer -- releases the matrix mutex
	// TODO: the above two items mean we need a TTMutex member

	setAttributeValue(TT("dimensions"), kTTVal1); // initialize to a 1x1 matrix by default (maybe we should be using the args?
}

TTMatrix::~TTMatrix()
{
	delete[] mData; // TODO: only do this if the refcount for the data is down to zero!
}

TTErr TTMatrix::resize()
{
	TTUInt32 productOfDimensions = 1;

	for (uint i=0; i<mDimensions.size(); i++) {
		if (i == 0)
			productOfDimensions = mDimensions[i];
		else
			productOfDimensions *= mDimensions[i];
	}
	mDataSize = productOfDimensions * mElementCount * mTypeSizeInBytes;

	// TODO: currently, we are not preserving memory when resizing. Should we try to preserve the previous memory contents?
	// TODO: thread protection
	delete[] mData;
	mData = new TTByte[mDataSize];

	mValueStride = mTypeSizeInBytes * mElementCount;

	if (mDataSize && mData)
		return kTTErrNone;
	else
		return kTTErrAllocFailed;
}

TTErr TTMatrix::setDimensions(const TTValue& someNewDimensions)
{
	TTUInt8	size = someNewDimensions.getSize();

	mDimensions.resize(size);
	for (int i=0; i<size; i++) {
		TTUInt8 aNewDimension = 0;

		someNewDimensions.get(i, aNewDimension);
		mDimensions[i] = aNewDimension;
	}
	return resize();
}

TTErr TTMatrix::getDimensions(TTValue& returnedDimensions)
{
	TTUInt8	size = mDimensions.size();

	returnedDimensions.setSize(size);
	for (uint i=0; i<size; i++)
		returnedDimensions.set(i, mDimensions[i]);
	return kTTErrNone;
}

TTErr TTMatrix::setType(const TTValue& aType)
{
	TTSymbolPtr typeName = aType;

	// TODO: it's dumb to do this big switch below...
	// TODO: we should use the info already defined in TTDataInfo

	if (typeName == TT("uint8"))
		mTypeSizeInBytes = 1;
	else if (typeName == TT("int32"))
		mTypeSizeInBytes = 4;
	else if (typeName == TT("float32"))
		mTypeSizeInBytes = 4;
	else if (typeName == TT("float64"))
		mTypeSizeInBytes = 8;
	else {
		// don't change the matrix data if something bogus was passed-in
		return kTTErrInvalidValue;
	}

	mType = typeName;
	return resize();
}

TTErr TTMatrix::setElementCount(const TTValue& newElementCount)
{
	mElementCount = newElementCount;
	return resize();
}

TTErr TTMatrix::clear()
{
	memset(mData, 0, mDataSize);
	return kTTErrNone;
}

TTErr TTMatrix::fill(const TTValue& aValue)
{
// Windows compiler chokes the on the syntax below...
// TODO: I guess we should make all of the code the same, working with the lowest common denominator (Windows)
// Of course, it sucks that we have to alloc this on the heap instead of the stack... :-/
#ifdef TT_PLATFORM_WIN
	TTBytePtr	fillValue = new TTByte[mValueStride];
#else
	TTByte	fillValue[mValueStride];
#endif

	// TODO: here we have this ugly switch again...
	if (mType == TT("uint8"))
		aValue.getArray((TTUInt8*)fillValue, mElementCount);
	else if (mType == TT("int32"))
		aValue.getArray((TTInt32*)fillValue, mElementCount);
	else if (mType == TT("float32"))
		aValue.getArray((TTFloat32*)fillValue, mElementCount);
	else if (mType == TT("float64"))
		aValue.getArray((TTFloat64*)fillValue, mElementCount);

	for (TTUInt32 i=0; i<mDataSize; i += mValueStride)
		memcpy(mData+i, fillValue, mValueStride);

	delete[] fillValue;
	return kTTErrNone;
}

/*
	To find the index in the matrix:

	1D Matrix:	index = x
	2D Matrix:	index = dim_0 y  +  x
	3D Matrix:	index = dim_0 dim_1 z  +  dim_0 y  +  x
	etc.
 */

// args passed-in should be the coordinates
// args returned will be the value at those coordinates
TTErr TTMatrix::get(TTValue& aValue)
{
	TTUInt16 dimensionCount = aValue.getSize();

	if (dimensionCount != mDimensions.size())
		return kTTErrWrongNumValues;

	int productOfLowerDimensionSizes = 1;
	int index = 0;

	for (int d=0; d<dimensionCount; d++) {
		int position = aValue.getInt32(d);

		index += position * productOfLowerDimensionSizes;
		productOfLowerDimensionSizes *= mDimensions[d];
	}

	aValue.clear();

	// TODO: here we have this ugly switch again...
	// Maybe we could just have duplicate pointers of different types in our class, and then we could access them more cleanly?
	if (mType == TT("uint8")) {
		for (int e=0; e<mElementCount; e++)
			aValue.append((TTUInt8*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("int32")) {
		for (int e=0; e<mElementCount; e++)
			aValue.append((TTInt32*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float32")) {
		for (int e=0; e<mElementCount; e++)
			aValue.append((TTFloat32*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float64")) {
		for (int e=0; e<mElementCount; e++)
			aValue.append((TTFloat64*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}

	return kTTErrNone;
}

// args passed-in should be the coordinates plus the value
TTErr TTMatrix::set(const TTValue& aValue)
{
	TTValue		theValue;
	TTValue		theDimensions = aValue;
	TTUInt16	dimensionCount = aValue.getSize() - mElementCount;

	if (dimensionCount != mDimensions.size())
		return kTTErrWrongNumValues;

	theValue.copyFrom(aValue, dimensionCount);
	theDimensions.setSize(dimensionCount);

	int productOfLowerDimensionSizes = 1;
	int index = 0;

	for (int d=0; d<dimensionCount; d++) {
		int position = aValue.getInt32(d);

		index += position * productOfLowerDimensionSizes;
		productOfLowerDimensionSizes *= mDimensions[d];
	}

	// TODO: here we have this ugly switch again...
	// Maybe we could just have duplicate pointers of different types in our class, and then we could access them more cleanly?
	if (mType == TT("uint8")) {
		for (int e=0; e<mElementCount; e++)
			aValue.get(e+dimensionCount, *(TTUInt8*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("int32")) {
		for (int e=0; e<mElementCount; e++)
			aValue.get(e+dimensionCount, *(TTInt32*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float32")) {
		for (int e=0; e<mElementCount; e++)
			aValue.get(e+dimensionCount, *(TTFloat32*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float64")) {
		for (int e=0; e<mElementCount; e++)
			aValue.get(e+dimensionCount, *(TTFloat64*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}

	return kTTErrNone;
}

<commit_msg>TTMatrix: making the Windows and Mac implementations of the fill() method the same.<commit_after>/*
 * Jamoma N-Dimensional Matrix Data Class
 * Copyright © 2011, Timothy Place
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTMatrix.h"

#define thisTTClass			TTMatrix
#define thisTTClassName		"matrix"
#define thisTTClassTags		"matrix"

TT_OBJECT_CONSTRUCTOR,
	mData(NULL),
	mDataSize(0),
	mType(TT("uint8")),
	mElementCount(1)
{
	addAttributeWithGetterAndSetter(Dimensions, kTypeUInt32);
	addAttributeWithSetter(Type,				kTypeUInt8);
	addAttributeWithSetter(ElementCount,		kTypeUInt8);

	addMessage(clear);
	addMessageWithArgument(fill);
	addMessageWithArgument(get);
	addMessageWithArgument(set);

	// TODO: getLockedPointer -- returns a pointer to the data, locks the matrix mutex
	// TODO: releaseLockedPointer -- releases the matrix mutex
	// TODO: the above two items mean we need a TTMutex member

	setAttributeValue(TT("dimensions"), kTTVal1); // initialize to a 1x1 matrix by default (maybe we should be using the args?
}

TTMatrix::~TTMatrix()
{
	delete[] mData; // TODO: only do this if the refcount for the data is down to zero!
}

TTErr TTMatrix::resize()
{
	TTUInt32 productOfDimensions = 1;

	for (uint i=0; i<mDimensions.size(); i++) {
		if (i == 0)
			productOfDimensions = mDimensions[i];
		else
			productOfDimensions *= mDimensions[i];
	}
	mDataSize = productOfDimensions * mElementCount * mTypeSizeInBytes;

	// TODO: currently, we are not preserving memory when resizing. Should we try to preserve the previous memory contents?
	// TODO: thread protection
	delete[] mData;
	mData = new TTByte[mDataSize];

	mValueStride = mTypeSizeInBytes * mElementCount;

	if (mDataSize && mData)
		return kTTErrNone;
	else
		return kTTErrAllocFailed;
}

TTErr TTMatrix::setDimensions(const TTValue& someNewDimensions)
{
	TTUInt8	size = someNewDimensions.getSize();

	mDimensions.resize(size);
	for (int i=0; i<size; i++) {
		TTUInt8 aNewDimension = 0;

		someNewDimensions.get(i, aNewDimension);
		mDimensions[i] = aNewDimension;
	}
	return resize();
}

TTErr TTMatrix::getDimensions(TTValue& returnedDimensions)
{
	TTUInt8	size = mDimensions.size();

	returnedDimensions.setSize(size);
	for (uint i=0; i<size; i++)
		returnedDimensions.set(i, mDimensions[i]);
	return kTTErrNone;
}

TTErr TTMatrix::setType(const TTValue& aType)
{
	TTSymbolPtr typeName = aType;

	// TODO: it's dumb to do this big switch below...
	// TODO: we should use the info already defined in TTDataInfo

	if (typeName == TT("uint8"))
		mTypeSizeInBytes = 1;
	else if (typeName == TT("int32"))
		mTypeSizeInBytes = 4;
	else if (typeName == TT("float32"))
		mTypeSizeInBytes = 4;
	else if (typeName == TT("float64"))
		mTypeSizeInBytes = 8;
	else {
		// don't change the matrix data if something bogus was passed-in
		return kTTErrInvalidValue;
	}

	mType = typeName;
	return resize();
}

TTErr TTMatrix::setElementCount(const TTValue& newElementCount)
{
	mElementCount = newElementCount;
	return resize();
}

TTErr TTMatrix::clear()
{
	memset(mData, 0, mDataSize);
	return kTTErrNone;
}

TTErr TTMatrix::fill(const TTValue& aValue)
{
	TTBytePtr fillValue = new TTByte[mValueStride];

	// TODO: here we have this ugly switch again...
	if (mType == TT("uint8"))
		aValue.getArray((TTUInt8*)fillValue, mElementCount);
	else if (mType == TT("int32"))
		aValue.getArray((TTInt32*)fillValue, mElementCount);
	else if (mType == TT("float32"))
		aValue.getArray((TTFloat32*)fillValue, mElementCount);
	else if (mType == TT("float64"))
		aValue.getArray((TTFloat64*)fillValue, mElementCount);

	for (TTUInt32 i=0; i<mDataSize; i += mValueStride)
		memcpy(mData+i, fillValue, mValueStride);

	delete[] fillValue;
	return kTTErrNone;
}

/*
	To find the index in the matrix:

	1D Matrix:	index = x
	2D Matrix:	index = dim_0 y  +  x
	3D Matrix:	index = dim_0 dim_1 z  +  dim_0 y  +  x
	etc.
 */

// args passed-in should be the coordinates
// args returned will be the value at those coordinates
TTErr TTMatrix::get(TTValue& aValue)
{
	TTUInt16 dimensionCount = aValue.getSize();

	if (dimensionCount != mDimensions.size())
		return kTTErrWrongNumValues;

	int productOfLowerDimensionSizes = 1;
	int index = 0;

	for (int d=0; d<dimensionCount; d++) {
		int position = aValue.getInt32(d);

		index += position * productOfLowerDimensionSizes;
		productOfLowerDimensionSizes *= mDimensions[d];
	}

	aValue.clear();

	// TODO: here we have this ugly switch again...
	// Maybe we could just have duplicate pointers of different types in our class, and then we could access them more cleanly?
	if (mType == TT("uint8")) {
		for (int e=0; e<mElementCount; e++)
			aValue.append((TTUInt8*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("int32")) {
		for (int e=0; e<mElementCount; e++)
			aValue.append((TTInt32*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float32")) {
		for (int e=0; e<mElementCount; e++)
			aValue.append((TTFloat32*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float64")) {
		for (int e=0; e<mElementCount; e++)
			aValue.append((TTFloat64*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}

	return kTTErrNone;
}

// args passed-in should be the coordinates plus the value
TTErr TTMatrix::set(const TTValue& aValue)
{
	TTValue		theValue;
	TTValue		theDimensions = aValue;
	TTUInt16	dimensionCount = aValue.getSize() - mElementCount;

	if (dimensionCount != mDimensions.size())
		return kTTErrWrongNumValues;

	theValue.copyFrom(aValue, dimensionCount);
	theDimensions.setSize(dimensionCount);

	int productOfLowerDimensionSizes = 1;
	int index = 0;

	for (int d=0; d<dimensionCount; d++) {
		int position = aValue.getInt32(d);

		index += position * productOfLowerDimensionSizes;
		productOfLowerDimensionSizes *= mDimensions[d];
	}

	// TODO: here we have this ugly switch again...
	// Maybe we could just have duplicate pointers of different types in our class, and then we could access them more cleanly?
	if (mType == TT("uint8")) {
		for (int e=0; e<mElementCount; e++)
			aValue.get(e+dimensionCount, *(TTUInt8*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("int32")) {
		for (int e=0; e<mElementCount; e++)
			aValue.get(e+dimensionCount, *(TTInt32*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float32")) {
		for (int e=0; e<mElementCount; e++)
			aValue.get(e+dimensionCount, *(TTFloat32*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}
	else if (mType == TT("float64")) {
		for (int e=0; e<mElementCount; e++)
			aValue.get(e+dimensionCount, *(TTFloat64*)(mData+(index*mValueStride+e*mTypeSizeInBytes)));
	}

	return kTTErrNone;
}

<|endoftext|>


<commit_before>#include "onlineldainterface.h"

#include <new>
using std::bad_alloc;

#include <vector>
using std::vector;

#include <utility>
using std::pair;

#include <iostream>
using std::cout;
using std::endl;

#include "trlda/utils"
using TRLDA::Exception;

#include "pyutils.h"

const char* OnlineLDA_doc =
	"An implementation of an online trust region method for latent dirichlet allocation (LDA).";

int OnlineLDA_init(OnlineLDAObject* self, PyObject* args, PyObject* kwds) {
	const char* kwlist[] = {
		"num_words",
		"num_topics",
		"num_documents",
		"alpha",
		"eta",
		"kappa_",
		"tau_", 0};

	int num_words;
	int num_topics;
	int num_documents;
	PyObject* alpha = 0;
	double eta = .3;

	// needed to support opening of old versions of pickled OnlineLDA objects
	double kappa_ = 0.;
	double tau_ = 0.;

	if(!PyArg_ParseTupleAndKeywords(args, kwds, "iii|Oddd", const_cast<char**>(kwlist),
			&num_words, &num_topics, &num_documents, &alpha, &eta, &kappa_, &tau_))
		return -1;

	try {
		if(alpha == 0) {
			self->lda = new OnlineLDA(num_words, num_topics, num_documents, .1, eta);
		} else if(PyFloat_Check(alpha)) {
			self->lda = new OnlineLDA(num_words, num_topics, num_documents, PyFloat_AsDouble(alpha), eta);
		} else if(PyInt_Check(alpha)) {
			self->lda = new OnlineLDA(num_words, num_topics, num_documents, PyInt_AsLong(alpha), eta);
		} else {
			alpha = PyArray_FROM_OTF(alpha, NPY_DOUBLE, NPY_IN_ARRAY);

			if(!alpha) {
				PyErr_SetString(PyExc_TypeError, "Alpha should be of type `ndarray`.");
				return -1;
			}

			MatrixXd alpha_ = PyArray_ToMatrixXd(alpha);

			if(alpha_.rows() == 1)
				alpha_ = alpha_.transpose();
			if(alpha_.cols() != 1) {
				PyErr_SetString(PyExc_TypeError, "Alpha should be one-dimensional.");
				return -1;
			}

			self->lda = new OnlineLDA(num_words, num_documents, alpha_, eta);
		}

	} catch(Exception& exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
	}

	return 0;
}

PyObject* OnlineLDA_num_topics(OnlineLDAObject* self, void*) {
	return PyInt_FromLong(self->lda->numTopics());
}

PyObject* OnlineLDA_num_words(OnlineLDAObject* self, void*) {
	return PyInt_FromLong(self->lda->numWords());
}

PyObject* OnlineLDA_num_documents(OnlineLDAObject* self, void*) {
	return PyInt_FromLong(self->lda->numDocuments());
}

int OnlineLDA_set_num_documents(OnlineLDAObject* self, PyObject* value, void*) {
	int num_documents = PyInt_AsLong(value);

	if(PyErr_Occurred())
		return -1;

	try {
		self->lda->setNumDocuments(num_documents);
	} catch(Exception exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return -1;
	}

	return 0;
}

PyObject* OnlineLDA_lambda(OnlineLDAObject* self, void*) {
	PyObject* array = PyArray_FromMatrixXd(self->lda->lambda());

	// make array immutable
	reinterpret_cast<PyArrayObject*>(array)->flags &= ~NPY_WRITEABLE;

	return array;
}

int OnlineLDA_set_lambda(OnlineLDAObject* self, PyObject* value, void*) {
	value = PyArray_FROM_OTF(value, NPY_DOUBLE, NPY_IN_ARRAY);

	if(!value) {
		PyErr_SetString(PyExc_TypeError, "Lambda should be of type `ndarray`.");
		return -1;
	}

	try {
		self->lda->setLambda(PyArray_ToMatrixXd(value));
	} catch(Exception exception) {
		Py_DECREF(value);
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return -1;
	}

	Py_DECREF(value);

	return 0;
}

PyObject* OnlineLDA_alpha(OnlineLDAObject* self, void*) {
	return PyArray_FromMatrixXd(self->lda->alpha());
}

int OnlineLDA_set_alpha(OnlineLDAObject* self, PyObject* alpha, void*) {
	try {
		if(PyFloat_Check(alpha)) {
			self->lda->setAlpha(PyFloat_AsDouble(alpha));
		} else if(PyInt_Check(alpha)) {
			self->lda->setAlpha(PyInt_AsLong(alpha));
		} else {
			alpha = PyArray_FROM_OTF(alpha, NPY_DOUBLE, NPY_IN_ARRAY);

			if(!alpha) {
				PyErr_SetString(PyExc_TypeError, "Alpha should be of type `ndarray`.");
				return -1;
			}

			MatrixXd alpha_ = PyArray_ToMatrixXd(alpha);

			if(alpha_.rows() == 1)
				alpha_ = alpha_.transpose();
			if(alpha_.cols() != 1) {
				PyErr_SetString(PyExc_TypeError, "Alpha should be one-dimensional.");
				return -1;
			}

			self->lda->setAlpha(alpha_);
		}
	} catch(Exception exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return -1;
	}

	return 0;
}

PyObject* OnlineLDA_eta(OnlineLDAObject* self, void*) {
	return PyFloat_FromDouble(self->lda->eta());
}

int OnlineLDA_set_eta(OnlineLDAObject* self, PyObject* value, void*) {
	double eta = PyFloat_AsDouble(value);

	if(PyErr_Occurred())
		return -1;

	try {
		self->lda->setEta(eta);
	} catch(Exception exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return -1;
	}

	return 0;
}

int PyList_ToDocuments(PyObject* docs, void* documents_) {
	OnlineLDA::Documents& documents = *reinterpret_cast<OnlineLDA::Documents*>(documents_);

	if(!PyList_Check(docs)) {
		PyErr_SetString(PyExc_TypeError, "Documents must be stored in a list.");
		return 0;
	}

	try {
		// create container for documents
		documents = OnlineLDA::Documents(PyList_Size(docs));

		// convert documents
		for(int i = 0; i < documents.size(); ++i) {
			PyObject* doc = PyList_GetItem(docs, i);

			// make sure document is a list
			if(!PyList_Check(doc)) {
				PyErr_SetString(PyExc_TypeError, "Each document must be a list of tuples.");
				return 0;
			}

			// create container for words
			documents[i] = OnlineLDA::Document(PyList_Size(doc));

			// load words
			for(int j = 0; j < documents[i].size(); ++j)
				if(!PyArg_ParseTuple(PyList_GetItem(doc, j), "ii",
					&documents[i][j].first,
					&documents[i][j].second))
					return 0;
		}
	} catch(bad_alloc&) {
		PyErr_SetString(PyExc_TypeError, "Not enough memory.");
		return 0;
	}

	return 1;
}

PyObject* PyList_FromDocuments(const OnlineLDA::Documents& documents) {
	PyObject* documents_ = PyList_New(0);

	for(int n = 0; n < documents.size(); ++n) {
		PyObject* document = PyList_New(0);

		for(int i = 0; i < documents[n].size(); ++i) {
			const int& wordID = documents[n][i].first;
			const int& wordCount = documents[n][i].second;

			PyObject* tuple = Py_BuildValue("(ii)", wordID, wordCount);
			PyList_Append(document, tuple);
			Py_DECREF(tuple);
		}

		PyList_Append(documents_, document);
		Py_DECREF(document);
	}

	return documents_;
}

const char* OnlineLDA_sample_doc =
	"";

PyObject* OnlineLDA_sample(
	OnlineLDAObject* self,
	PyObject* args,
	PyObject* kwds)
{
	const char* kwlist[] = {"num_documents", "length", 0};

	int num_documents;
	int length;

	// parse arguments
	if(!PyArg_ParseTupleAndKeywords(args, kwds, "ii", const_cast<char**>(kwlist),
			&num_documents, &length))
		return 0;

	try {
		// return list of documents
		return PyList_FromDocuments(self->lda->sample(num_documents, length));
	} catch(Exception& exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return 0;
	}

	return 0;
}

const char* OnlineLDA_update_variables_doc =
	"";

PyObject* OnlineLDA_update_variables(
	OnlineLDAObject* self,
	PyObject* args,
	PyObject* kwds)
{
	const char* kwlist[] = {"docs", "latents", "inference_method", "max_iter", "num_samples", "burn_in", 0};

	OnlineLDA::Documents documents;
	OnlineLDA::Parameters parameters;
	PyObject* latents = 0;
	const char* inference_method = 0;

	// parse arguments
	if(!PyArg_ParseTupleAndKeywords(args, kwds, "O&|Osiii", const_cast<char**>(kwlist),
			&PyList_ToDocuments, &documents,
			&latents,
			&inference_method,
			&parameters.maxIterInference,
			&parameters.numSamples,
			&parameters.burnIn))
		return 0;

	if(latents) {
		// make sure latents is a NumPy array
		latents = PyArray_FROM_OTF(latents, NPY_DOUBLE, NPY_IN_ARRAY);
		if(!latents) {
			PyErr_SetString(PyExc_TypeError, "`latents` should be of type `ndarray`.");
			return 0;
		}
	}

	if(inference_method) {
		switch(inference_method[0]) {
			case 'g':
			case 'G':
				parameters.inferenceMethod = OnlineLDA::GIBBS;
				break;

			case 'v':
			case 'V':
				parameters.inferenceMethod = OnlineLDA::VI;
				break;

			default:
				PyErr_SetString(PyExc_TypeError, "`inference_method` should be either 'gibbs' or 'vi'.");
				return 0;
		}
	}

	try {
		pair<ArrayXXd, ArrayXXd> results;

		if(latents)
			results = self->lda->updateVariables(
				documents,
				PyArray_ToMatrixXd(latents),
				parameters);
		else
			results = self->lda->updateVariables(documents, parameters);

		PyObject* rlatents = PyArray_FromMatrixXd(results.first);
		PyObject* sstats = PyArray_FromMatrixXd(results.second);
		PyObject* result = Py_BuildValue("(OO)", rlatents, sstats);

		Py_DECREF(rlatents);
		Py_DECREF(sstats);

		return result;

	} catch(Exception& exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		Py_XDECREF(latents);
		return 0;
	}

	Py_XDECREF(latents);

	return 0;
}

const char* OnlineLDA_update_parameters_doc =
	"";

PyObject* OnlineLDA_update_parameters(
	OnlineLDAObject* self,
	PyObject* args,
	PyObject* kwds)
{
	const char* kwlist[] = {
		"docs",
		"max_iter",
		"kappa",
		"tau",
		"rho",
		"adaptive",
		"init_gamma",
		"update_lambda",
		"update_alpha",
		"update_eta",
		"min_alpha",
		"min_eta", 0};

	OnlineLDA::Documents documents;
	OnlineLDA::Parameters parameters;

	// parse arguments
	if(!PyArg_ParseTupleAndKeywords(args, kwds, "O&|idddbbbbbdd", const_cast<char**>(kwlist),
			&PyList_ToDocuments, &documents,
			&parameters.maxIterTR,
			&parameters.kappa,
			&parameters.tau,
			&parameters.rho,
			&parameters.adaptive,
			&parameters.initGamma,
			&parameters.updateLambda,
			&parameters.updateAlpha,
			&parameters.updateEta,
			&parameters.minAlpha,
			&parameters.minEta))
		return 0;

	try {
		// return learning rate used
		return PyFloat_FromDouble(self->lda->updateParameters(documents, parameters));
	} catch(Exception& exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return 0;
	}

	return 0;
}

const char* OnlineLDA_reduce_doc =
	"__reduce__(self)\n"
	"\n"
	"Method used by Pickle.";

PyObject* OnlineLDA_reduce(OnlineLDAObject* self, PyObject*) {
	PyObject* alpha = PyArray_FromMatrixXd(self->lda->alpha());

	// constructor arguments
	PyObject* args = Py_BuildValue("(iiiOd)",
		self->lda->numWords(),
		self->lda->numTopics(),
		self->lda->numDocuments(),
		alpha,
		self->lda->eta());

	Py_DECREF(alpha);

	PyObject* lambda = OnlineLDA_lambda(self, 0);
	PyObject* state = Py_BuildValue("(Oi)", lambda, self->lda->updateCount());
	PyObject* result = Py_BuildValue("(OOO)", Py_TYPE(self), args, state);

	Py_DECREF(lambda);
	Py_DECREF(args);
	Py_DECREF(state);

	return result;
}

const char* OnlineLDA_setstate_doc =
	"__setstate__(self)\n"
	"\n"
	"Method used by Pickle.";

PyObject* OnlineLDA_setstate(OnlineLDAObject* self, PyObject* state) {
	PyObject* lambda;
	int updateCount;

	if(!PyArg_ParseTuple(state, "(Oi)", &lambda, &updateCount))
		return 0;

	try {
		OnlineLDA_set_lambda(self, lambda, 0);
		self->lda->setUpdateCount(updateCount);
	} catch(Exception exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return 0;
	}

	Py_INCREF(Py_None);
	return Py_None;
}
<commit_msg>Number of trust region steps and inner loop inference steps can now both be controlled.<commit_after>#include "onlineldainterface.h"

#include <new>
using std::bad_alloc;

#include <vector>
using std::vector;

#include <utility>
using std::pair;

#include <iostream>
using std::cout;
using std::endl;

#include "trlda/utils"
using TRLDA::Exception;

#include "pyutils.h"

const char* OnlineLDA_doc =
	"An implementation of an online trust region method for latent dirichlet allocation (LDA).";

int OnlineLDA_init(OnlineLDAObject* self, PyObject* args, PyObject* kwds) {
	const char* kwlist[] = {
		"num_words",
		"num_topics",
		"num_documents",
		"alpha",
		"eta",
		"kappa_",
		"tau_", 0};

	int num_words;
	int num_topics;
	int num_documents;
	PyObject* alpha = 0;
	double eta = .3;

	// needed to support opening of old versions of pickled OnlineLDA objects
	double kappa_ = 0.;
	double tau_ = 0.;

	if(!PyArg_ParseTupleAndKeywords(args, kwds, "iii|Oddd", const_cast<char**>(kwlist),
			&num_words, &num_topics, &num_documents, &alpha, &eta, &kappa_, &tau_))
		return -1;

	try {
		if(alpha == 0) {
			self->lda = new OnlineLDA(num_words, num_topics, num_documents, .1, eta);
		} else if(PyFloat_Check(alpha)) {
			self->lda = new OnlineLDA(num_words, num_topics, num_documents, PyFloat_AsDouble(alpha), eta);
		} else if(PyInt_Check(alpha)) {
			self->lda = new OnlineLDA(num_words, num_topics, num_documents, PyInt_AsLong(alpha), eta);
		} else {
			alpha = PyArray_FROM_OTF(alpha, NPY_DOUBLE, NPY_IN_ARRAY);

			if(!alpha) {
				PyErr_SetString(PyExc_TypeError, "Alpha should be of type `ndarray`.");
				return -1;
			}

			MatrixXd alpha_ = PyArray_ToMatrixXd(alpha);

			if(alpha_.rows() == 1)
				alpha_ = alpha_.transpose();
			if(alpha_.cols() != 1) {
				PyErr_SetString(PyExc_TypeError, "Alpha should be one-dimensional.");
				return -1;
			}

			self->lda = new OnlineLDA(num_words, num_documents, alpha_, eta);
		}

	} catch(Exception& exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
	}

	return 0;
}

PyObject* OnlineLDA_num_topics(OnlineLDAObject* self, void*) {
	return PyInt_FromLong(self->lda->numTopics());
}

PyObject* OnlineLDA_num_words(OnlineLDAObject* self, void*) {
	return PyInt_FromLong(self->lda->numWords());
}

PyObject* OnlineLDA_num_documents(OnlineLDAObject* self, void*) {
	return PyInt_FromLong(self->lda->numDocuments());
}

int OnlineLDA_set_num_documents(OnlineLDAObject* self, PyObject* value, void*) {
	int num_documents = PyInt_AsLong(value);

	if(PyErr_Occurred())
		return -1;

	try {
		self->lda->setNumDocuments(num_documents);
	} catch(Exception exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return -1;
	}

	return 0;
}

PyObject* OnlineLDA_lambda(OnlineLDAObject* self, void*) {
	PyObject* array = PyArray_FromMatrixXd(self->lda->lambda());

	// make array immutable
	reinterpret_cast<PyArrayObject*>(array)->flags &= ~NPY_WRITEABLE;

	return array;
}

int OnlineLDA_set_lambda(OnlineLDAObject* self, PyObject* value, void*) {
	value = PyArray_FROM_OTF(value, NPY_DOUBLE, NPY_IN_ARRAY);

	if(!value) {
		PyErr_SetString(PyExc_TypeError, "Lambda should be of type `ndarray`.");
		return -1;
	}

	try {
		self->lda->setLambda(PyArray_ToMatrixXd(value));
	} catch(Exception exception) {
		Py_DECREF(value);
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return -1;
	}

	Py_DECREF(value);

	return 0;
}

PyObject* OnlineLDA_alpha(OnlineLDAObject* self, void*) {
	return PyArray_FromMatrixXd(self->lda->alpha());
}

int OnlineLDA_set_alpha(OnlineLDAObject* self, PyObject* alpha, void*) {
	try {
		if(PyFloat_Check(alpha)) {
			self->lda->setAlpha(PyFloat_AsDouble(alpha));
		} else if(PyInt_Check(alpha)) {
			self->lda->setAlpha(PyInt_AsLong(alpha));
		} else {
			alpha = PyArray_FROM_OTF(alpha, NPY_DOUBLE, NPY_IN_ARRAY);

			if(!alpha) {
				PyErr_SetString(PyExc_TypeError, "Alpha should be of type `ndarray`.");
				return -1;
			}

			MatrixXd alpha_ = PyArray_ToMatrixXd(alpha);

			if(alpha_.rows() == 1)
				alpha_ = alpha_.transpose();
			if(alpha_.cols() != 1) {
				PyErr_SetString(PyExc_TypeError, "Alpha should be one-dimensional.");
				return -1;
			}

			self->lda->setAlpha(alpha_);
		}
	} catch(Exception exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return -1;
	}

	return 0;
}

PyObject* OnlineLDA_eta(OnlineLDAObject* self, void*) {
	return PyFloat_FromDouble(self->lda->eta());
}

int OnlineLDA_set_eta(OnlineLDAObject* self, PyObject* value, void*) {
	double eta = PyFloat_AsDouble(value);

	if(PyErr_Occurred())
		return -1;

	try {
		self->lda->setEta(eta);
	} catch(Exception exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return -1;
	}

	return 0;
}

int PyList_ToDocuments(PyObject* docs, void* documents_) {
	OnlineLDA::Documents& documents = *reinterpret_cast<OnlineLDA::Documents*>(documents_);

	if(!PyList_Check(docs)) {
		PyErr_SetString(PyExc_TypeError, "Documents must be stored in a list.");
		return 0;
	}

	try {
		// create container for documents
		documents = OnlineLDA::Documents(PyList_Size(docs));

		// convert documents
		for(int i = 0; i < documents.size(); ++i) {
			PyObject* doc = PyList_GetItem(docs, i);

			// make sure document is a list
			if(!PyList_Check(doc)) {
				PyErr_SetString(PyExc_TypeError, "Each document must be a list of tuples.");
				return 0;
			}

			// create container for words
			documents[i] = OnlineLDA::Document(PyList_Size(doc));

			// load words
			for(int j = 0; j < documents[i].size(); ++j)
				if(!PyArg_ParseTuple(PyList_GetItem(doc, j), "ii",
					&documents[i][j].first,
					&documents[i][j].second))
					return 0;
		}
	} catch(bad_alloc&) {
		PyErr_SetString(PyExc_TypeError, "Not enough memory.");
		return 0;
	}

	return 1;
}

PyObject* PyList_FromDocuments(const OnlineLDA::Documents& documents) {
	PyObject* documents_ = PyList_New(0);

	for(int n = 0; n < documents.size(); ++n) {
		PyObject* document = PyList_New(0);

		for(int i = 0; i < documents[n].size(); ++i) {
			const int& wordID = documents[n][i].first;
			const int& wordCount = documents[n][i].second;

			PyObject* tuple = Py_BuildValue("(ii)", wordID, wordCount);
			PyList_Append(document, tuple);
			Py_DECREF(tuple);
		}

		PyList_Append(documents_, document);
		Py_DECREF(document);
	}

	return documents_;
}

const char* OnlineLDA_sample_doc =
	"";

PyObject* OnlineLDA_sample(
	OnlineLDAObject* self,
	PyObject* args,
	PyObject* kwds)
{
	const char* kwlist[] = {"num_documents", "length", 0};

	int num_documents;
	int length;

	// parse arguments
	if(!PyArg_ParseTupleAndKeywords(args, kwds, "ii", const_cast<char**>(kwlist),
			&num_documents, &length))
		return 0;

	try {
		// return list of documents
		return PyList_FromDocuments(self->lda->sample(num_documents, length));
	} catch(Exception& exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return 0;
	}

	return 0;
}

const char* OnlineLDA_update_variables_doc =
	"";

PyObject* OnlineLDA_update_variables(
	OnlineLDAObject* self,
	PyObject* args,
	PyObject* kwds)
{
	const char* kwlist[] = {"docs", "latents", "inference_method", "max_iter", "num_samples", "burn_in", 0};

	OnlineLDA::Documents documents;
	OnlineLDA::Parameters parameters;
	PyObject* latents = 0;
	const char* inference_method = 0;

	// parse arguments
	if(!PyArg_ParseTupleAndKeywords(args, kwds, "O&|Osiii", const_cast<char**>(kwlist),
			&PyList_ToDocuments, &documents,
			&latents,
			&inference_method,
			&parameters.maxIterInference,
			&parameters.numSamples,
			&parameters.burnIn))
		return 0;

	if(latents) {
		// make sure latents is a NumPy array
		latents = PyArray_FROM_OTF(latents, NPY_DOUBLE, NPY_IN_ARRAY);
		if(!latents) {
			PyErr_SetString(PyExc_TypeError, "`latents` should be of type `ndarray`.");
			return 0;
		}
	}

	if(inference_method) {
		switch(inference_method[0]) {
			case 'g':
			case 'G':
				parameters.inferenceMethod = OnlineLDA::GIBBS;
				break;

			case 'v':
			case 'V':
				parameters.inferenceMethod = OnlineLDA::VI;
				break;

			default:
				PyErr_SetString(PyExc_TypeError, "`inference_method` should be either 'gibbs' or 'vi'.");
				return 0;
		}
	}

	try {
		pair<ArrayXXd, ArrayXXd> results;

		if(latents)
			results = self->lda->updateVariables(
				documents,
				PyArray_ToMatrixXd(latents),
				parameters);
		else
			results = self->lda->updateVariables(documents, parameters);

		PyObject* rlatents = PyArray_FromMatrixXd(results.first);
		PyObject* sstats = PyArray_FromMatrixXd(results.second);
		PyObject* result = Py_BuildValue("(OO)", rlatents, sstats);

		Py_DECREF(rlatents);
		Py_DECREF(sstats);

		return result;

	} catch(Exception& exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		Py_XDECREF(latents);
		return 0;
	}

	Py_XDECREF(latents);

	return 0;
}

const char* OnlineLDA_update_parameters_doc =
	"";

PyObject* OnlineLDA_update_parameters(
	OnlineLDAObject* self,
	PyObject* args,
	PyObject* kwds)
{
	const char* kwlist[] = {
		"docs",
		"max_iter_tr",
		"max_iter_inference",
		"kappa",
		"tau",
		"rho",
		"adaptive",
		"init_gamma",
		"update_lambda",
		"update_alpha",
		"update_eta",
		"min_alpha",
		"min_eta", 0};

	OnlineLDA::Documents documents;
	OnlineLDA::Parameters parameters;

	// parse arguments
	if(!PyArg_ParseTupleAndKeywords(args, kwds, "O&|iidddbbbbbdd", const_cast<char**>(kwlist),
			&PyList_ToDocuments, &documents,
			&parameters.maxIterTR,
			&parameters.maxIterInference,
			&parameters.kappa,
			&parameters.tau,
			&parameters.rho,
			&parameters.adaptive,
			&parameters.initGamma,
			&parameters.updateLambda,
			&parameters.updateAlpha,
			&parameters.updateEta,
			&parameters.minAlpha,
			&parameters.minEta))
		return 0;

	try {
		// return learning rate used
		return PyFloat_FromDouble(self->lda->updateParameters(documents, parameters));
	} catch(Exception& exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return 0;
	}

	return 0;
}

const char* OnlineLDA_reduce_doc =
	"__reduce__(self)\n"
	"\n"
	"Method used by Pickle.";

PyObject* OnlineLDA_reduce(OnlineLDAObject* self, PyObject*) {
	PyObject* alpha = PyArray_FromMatrixXd(self->lda->alpha());

	// constructor arguments
	PyObject* args = Py_BuildValue("(iiiOd)",
		self->lda->numWords(),
		self->lda->numTopics(),
		self->lda->numDocuments(),
		alpha,
		self->lda->eta());

	Py_DECREF(alpha);

	PyObject* lambda = OnlineLDA_lambda(self, 0);
	PyObject* state = Py_BuildValue("(Oi)", lambda, self->lda->updateCount());
	PyObject* result = Py_BuildValue("(OOO)", Py_TYPE(self), args, state);

	Py_DECREF(lambda);
	Py_DECREF(args);
	Py_DECREF(state);

	return result;
}

const char* OnlineLDA_setstate_doc =
	"__setstate__(self)\n"
	"\n"
	"Method used by Pickle.";

PyObject* OnlineLDA_setstate(OnlineLDAObject* self, PyObject* state) {
	PyObject* lambda;
	int updateCount;

	if(!PyArg_ParseTuple(state, "(Oi)", &lambda, &updateCount))
		return 0;

	try {
		OnlineLDA_set_lambda(self, lambda, 0);
		self->lda->setUpdateCount(updateCount);
	} catch(Exception exception) {
		PyErr_SetString(PyExc_RuntimeError, exception.message());
		return 0;
	}

	Py_INCREF(Py_None);
	return Py_None;
}
<|endoftext|>


<commit_before>#include "SimpleTwoOptTSPSolver.h"
#include <Engine/SceneManager/Schedule.h>
#include <Engine/SceneEditor/Actions/SwapRunWorkStops.h>
#include <Engine/SceneEditor/Actions/ReverseRunWorkStopsSubsequence.h>
#include <Engine/SceneManager/Run.h>
#include <Engine/SceneEditor/SceneEditor.h>

namespace Scheduler
{
	SimpleTwoOptTSPSolver::SimpleTwoOptTSPSolver():
		schedule_cost_function(nullptr)
	{
	}

    void SimpleTwoOptTSPSolver::optimize(Schedule* schedule) const
	{
		if (!schedule_cost_function) return; // We don't have a metric to optimize - so we can't

        const auto &runs = schedule->getRuns();
        for (auto run_it = runs.begin(); run_it != runs.end(); ++run_it) {
            optimize(schedule, std::distance(run_it, runs.end() - 1));
        }
	}

	void SimpleTwoOptTSPSolver::optimize(Schedule* schedule, size_t run_index) const
	{
		if (!schedule_cost_function) return; // We don't have a metric to optimize - so we can't

        const auto &runs = schedule->getRuns();
        const auto run_ptr = runs.at(run_index);
        const auto &stops = run_ptr->getWorkStops();
        Cost best_cost = schedule_cost_function->calculateCost(run_ptr->getSchedule());
        for (auto stop_it1 = stops.begin(); stop_it1 != stops.end() - 1; ++stop_it1) {
            for (auto stop_it2 = stop_it1 + 1; stop_it2 != stops.end(); ++stop_it2) {
                SceneEditor editor;
                editor.performAction<SwapRunWorkStops>(run_ptr, *stop_it1, *stop_it2);
                editor.performAction<ReverseWorkStopsSubsequence>(run_ptr, *(stop_it1 + 1), *(stop_it2 - 1));
                Cost cost = schedule_cost_function->calculateCost(schedule);
                if (cost > best_cost) {
                    best_cost = cost;
                } else {
                    editor.rollbackAll();
                }

            }
        }
	}

	void SimpleTwoOptTSPSolver::setScheduleCostFunction(ScheduleCostFunction* cost_function)
	{
		this->schedule_cost_function = cost_function;
	}
}
<commit_msg>[#22] Optimize while changed<commit_after>#include "SimpleTwoOptTSPSolver.h"
#include <Engine/SceneManager/Schedule.h>
#include <Engine/SceneEditor/Actions/SwapRunWorkStops.h>
#include <Engine/SceneEditor/Actions/ReverseRunWorkStopsSubsequence.h>
#include <Engine/SceneManager/Run.h>
#include <Engine/SceneEditor/SceneEditor.h>

namespace Scheduler
{
	SimpleTwoOptTSPSolver::SimpleTwoOptTSPSolver():
		schedule_cost_function(nullptr)
	{
	}

    void SimpleTwoOptTSPSolver::optimize(Schedule* schedule) const
	{
		if (!schedule_cost_function) return; // We don't have a metric to optimize - so we can't

        const auto &runs = schedule->getRuns();
        for (auto run_it = runs.begin(); run_it != runs.end(); ++run_it) {
            optimize(schedule, std::distance(run_it, runs.end() - 1));
        }
	}

	void SimpleTwoOptTSPSolver::optimize(Schedule* schedule, size_t run_index) const
	{
		if (!schedule_cost_function) return; // We don't have a metric to optimize - so we can't

        const auto &runs = schedule->getRuns();
        const auto run_ptr = runs.at(run_index);
        const auto &stops = run_ptr->getWorkStops();
        Cost best_cost = schedule_cost_function->calculateCost(run_ptr->getSchedule());
        bool changed = true;
        while (changed) {
            changed = false;
            for (auto stop_it1 = stops.begin(); stop_it1 != stops.end() - 1; ++stop_it1) {
                for (auto stop_it2 = stop_it1 + 1; stop_it2 != stops.end(); ++stop_it2) {
                    SceneEditor editor;
                    editor.performAction<SwapRunWorkStops>(run_ptr, *stop_it1, *stop_it2);
                    editor.performAction<ReverseWorkStopsSubsequence>(run_ptr, *(stop_it1 + 1), *(stop_it2 - 1));
                    Cost cost = schedule_cost_function->calculateCost(schedule);
                    if (cost > best_cost) {
                        best_cost = cost;
                        changed = true;
                    } else {
                        editor.rollbackAll();
                    }

                }
            }
        }
	}

	void SimpleTwoOptTSPSolver::setScheduleCostFunction(ScheduleCostFunction* cost_function)
	{
		this->schedule_cost_function = cost_function;
	}
}
<|endoftext|>


<commit_before>void AddTask_dNdPtpp_TPCITS(Int_t cutMode =222 , char *particleMode ="default", char* eventTrigger="kINT7"){

  TString stEventTrigger(eventTrigger);
  TString stParticleMode(particleMode);

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {Error("AddTask_dNdPtpp_TPCITS", "No analysis manager found.");return 0;}

  Bool_t hasMC=(AliAnalysisManager::GetAnalysisManager()->GetMCtruthEventHandler()!=0x0);

  // Switch off all AliInfo (too much output!!!)
  AliLog::SetGlobalLogLevel(AliLog::kError);
  mgr->SetDebugLevel(0);

  /// Create event cuts
  Float_t zvWindow = 30. ;

  AlidNdPtEventCuts *evtCuts = new AlidNdPtEventCuts("AlidNdPtEventCuts","Event cuts");
  evtCuts->SetZvRange(-zvWindow,zvWindow);
  evtCuts->SetMeanXYZv(0.0,0.0,0.0);
  evtCuts->SetSigmaMeanXYZv(1.0,1.0,10.0);
  evtCuts->SetTriggerRequired(kTRUE);

  // Create geom. acceptance cuts

  Float_t etaWindow = 1. ;
  Float_t ptMin = 0.10;

  AlidNdPtAcceptanceCuts *accCuts = new AlidNdPtAcceptanceCuts("AlidNdPtAcceptanceCuts","Geom. acceptance cuts");
  accCuts->SetEtaRange(-etaWindow,etaWindow);
  accCuts->SetPtRange(ptMin,1.e10);

  gROOT->LoadMacro("$ALICE_PHYSICS/PWGLF/SPECTRA/ChargedHadrons/dNdPt/macros/CreatedNdPtTrackCuts.C");
  AliESDtrackCuts* esdTrackCuts = CreatedNdPtTrackCuts(cutMode,hasMC);
  if (!esdTrackCuts) { printf("ERROR: esdTrackCuts could not be created\n"); return; }
  esdTrackCuts->SetHistogramsOn(kTRUE);

  // Create task
  AlidNdPtTask *task = new AlidNdPtTask("AlidNdPtTask");
  task->SetUseMCInfo(hasMC);

  // trigger selection: MB
  if(stEventTrigger.Contains("kINT7")) task->SelectCollisionCandidates(AliVEvent::kINT7);
  else if(stEventTrigger.Contains("kMB")) task->SelectCollisionCandidates(AliVEvent::kMB);

  // Create cut analysis object
  AlidNdPtAnalysis *fdNdPtAnalysispp = new AlidNdPtAnalysis("dNdPtAnalysis","dN/dPt Analysis");
  fdNdPtAnalysispp->SetEventCuts(evtCuts);
  fdNdPtAnalysispp->SetAcceptanceCuts(accCuts);
  fdNdPtAnalysispp->SetTrackCuts(esdTrackCuts);
  fdNdPtAnalysispp->SetAnalysisMode(AlidNdPtHelper::kTPCITS);
  if(stEventTrigger.Contains("kINT7")) fdNdPtAnalysispp->SetTriggerMask(AliVEvent::kINT7);
  else if(stEventTrigger.Contains("kMB")) fdNdPtAnalysispp->SetTriggerMask(AliVEvent::kMB);

  // SetParticleMode
  if(stParticleMode.Contains("Pion")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCPion);}
  else if (stParticleMode.Contains("Proton")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCProton);}
  else if (stParticleMode.Contains("Kaon")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCKaon);}
  else if (stParticleMode.Contains("RemainingRest")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCRemainingRest);}
  else if (stParticleMode.Contains("Rest")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCRest);}
  else if (stParticleMode.Contains("SigmaPlus")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCSigmaPlus);}
  else if (stParticleMode.Contains("SigmaMinus")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCSigmaMinus);}
  else if (stParticleMode.Contains("XiMinus")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCXiMinus);}
  else if (stParticleMode.Contains("OmegaMinus")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCOmegaMinus);}
  else if (stParticleMode.Contains("Plus")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kPlus);}
  else if (stParticleMode.Contains("Minus")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMinus);}
  else if (stParticleMode.Contains("Electron")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCElectron);}
  else if (stParticleMode.Contains("Muon")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCMuon);}
  else{fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kAllPart);}
  // Change binning
  const Int_t ptNbins = 81;
  Double_t bins[82] = {0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 18.0, 20.0, 22.0, 24.0, 26.0, 28.0, 30.0, 32.0, 34.0, 36.0, 40.0, 45.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0, 120.0, 130.0, 140.0, 150.0, 160.0, 180.0, 200.0};
  Double_t* binsPt = new Double_t[82];
  for (int i=0; i<82; i++) {binsPt[i] = bins[i];}
  fdNdPtAnalysispp->SetBinsPt(ptNbins, binsPt);
  fdNdPtAnalysispp->SetBinsPtCorr(ptNbins, binsPt);
  fdNdPtAnalysispp->SetUseMCInfo(hasMC);
  fdNdPtAnalysispp->SetHistogramsOn(hasMC);

  task->AddAnalysisObject( fdNdPtAnalysispp );

  // Add task
  mgr->AddTask(task);

  // Create containers for input
  AliAnalysisDataContainer *cinput = mgr->GetCommonInputContainer();
  mgr->ConnectInput(task, 0, cinput);

  TString stContainerName;
  stContainerName = Form("dNdPt_pp_%d",cutMode);
  if(!stParticleMode.Contains("default")) {
    stContainerName = stContainerName + "_" +stParticleMode;
  }

  AliAnalysisDataContainer *coutput = mgr->CreateContainer(stContainerName,TList::Class(),AliAnalysisManager::kOutputContainer, mgr->GetCommonFileName());

  mgr->ConnectOutput(task, 1, coutput);
}

<commit_msg>IsPythia flag on the AddTask<commit_after>void AddTask_dNdPtpp_TPCITS(Int_t cutMode =222 , char *particleMode ="default", char* eventTrigger="kINT7"){

  TString stEventTrigger(eventTrigger);
  TString stParticleMode(particleMode);

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {Error("AddTask_dNdPtpp_TPCITS", "No analysis manager found.");return 0;}

  Bool_t hasMC=(AliAnalysisManager::GetAnalysisManager()->GetMCtruthEventHandler()!=0x0);

  // Switch off all AliInfo (too much output!!!)
  AliLog::SetGlobalLogLevel(AliLog::kError);
  mgr->SetDebugLevel(0);

  /// Create event cuts
  Float_t zvWindow = 30. ;

  AlidNdPtEventCuts *evtCuts = new AlidNdPtEventCuts("AlidNdPtEventCuts","Event cuts");
  evtCuts->SetZvRange(-zvWindow,zvWindow);
  evtCuts->SetMeanXYZv(0.0,0.0,0.0);
  evtCuts->SetSigmaMeanXYZv(1.0,1.0,10.0);
  evtCuts->SetTriggerRequired(kTRUE);

  // Create geom. acceptance cuts

  Float_t etaWindow = 1. ;
  Float_t ptMin = 0.10;

  AlidNdPtAcceptanceCuts *accCuts = new AlidNdPtAcceptanceCuts("AlidNdPtAcceptanceCuts","Geom. acceptance cuts");
  accCuts->SetEtaRange(-etaWindow,etaWindow);
  accCuts->SetPtRange(ptMin,1.e10);

  gROOT->LoadMacro("$ALICE_PHYSICS/PWGLF/SPECTRA/ChargedHadrons/dNdPt/macros/CreatedNdPtTrackCuts.C");
  AliESDtrackCuts* esdTrackCuts = CreatedNdPtTrackCuts(cutMode,hasMC);
  if (!esdTrackCuts) { printf("ERROR: esdTrackCuts could not be created\n"); return; }
  esdTrackCuts->SetHistogramsOn(kTRUE);

  // Create task
  AlidNdPtTask *task = new AlidNdPtTask("AlidNdPtTask");
  task->SetUseMCInfo(hasMC);

  // trigger selection: MB
  if(stEventTrigger.Contains("kINT7")) task->SelectCollisionCandidates(AliVEvent::kINT7);
  else if(stEventTrigger.Contains("kMB")) task->SelectCollisionCandidates(AliVEvent::kMB);

  // Create cut analysis object
  AlidNdPtAnalysis *fdNdPtAnalysispp = new AlidNdPtAnalysis("dNdPtAnalysis","dN/dPt Analysis");
  fdNdPtAnalysispp->SetEventCuts(evtCuts);
  fdNdPtAnalysispp->SetAcceptanceCuts(accCuts);
  fdNdPtAnalysispp->SetTrackCuts(esdTrackCuts);
  fdNdPtAnalysispp->SetAnalysisMode(AlidNdPtHelper::kTPCITS);
  if(stEventTrigger.Contains("kINT7")) fdNdPtAnalysispp->SetTriggerMask(AliVEvent::kINT7);
  else if(stEventTrigger.Contains("kMB")) fdNdPtAnalysispp->SetTriggerMask(AliVEvent::kMB);

 if(hasMC)
  {
    fdNdPtAnalysispp->SetUseMCInfo(kTRUE);
    fdNdPtAnalysispp->SetHistogramsOn(kTRUE);
    fdNdPtAnalysispp->SetIsPythia(kTRUE);
    //fdNdPtAnalysis->SetHistogramsOn(kFALSE);
  }

  // SetParticleMode
  if(stParticleMode.Contains("Pion")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCPion);}
  else if (stParticleMode.Contains("Proton")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCProton);}
  else if (stParticleMode.Contains("Kaon")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCKaon);}
  else if (stParticleMode.Contains("RemainingRest")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCRemainingRest);}
  else if (stParticleMode.Contains("Rest")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCRest);}
  else if (stParticleMode.Contains("SigmaPlus")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCSigmaPlus);}
  else if (stParticleMode.Contains("SigmaMinus")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCSigmaMinus);}
  else if (stParticleMode.Contains("XiMinus")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCXiMinus);}
  else if (stParticleMode.Contains("OmegaMinus")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCOmegaMinus);}
  else if (stParticleMode.Contains("Plus")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kPlus);}
  else if (stParticleMode.Contains("Minus")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMinus);}
  else if (stParticleMode.Contains("Electron")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCElectron);}
  else if (stParticleMode.Contains("Muon")){fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kMCMuon);}
  else{fdNdPtAnalysispp->SetParticleMode(AlidNdPtHelper::kAllPart);}
  // Change binning
  const Int_t ptNbins = 81;
  Double_t bins[82] = {0.0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 18.0, 20.0, 22.0, 24.0, 26.0, 28.0, 30.0, 32.0, 34.0, 36.0, 40.0, 45.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 110.0, 120.0, 130.0, 140.0, 150.0, 160.0, 180.0, 200.0};
  Double_t* binsPt = new Double_t[82];
  for (int i=0; i<82; i++) {binsPt[i] = bins[i];}
  fdNdPtAnalysispp->SetBinsPt(ptNbins, binsPt);
  fdNdPtAnalysispp->SetBinsPtCorr(ptNbins, binsPt);
  fdNdPtAnalysispp->SetUseMCInfo(hasMC);
  fdNdPtAnalysispp->SetHistogramsOn(hasMC);

  task->AddAnalysisObject( fdNdPtAnalysispp );

  // Add task
  mgr->AddTask(task);

  // Create containers for input
  AliAnalysisDataContainer *cinput = mgr->GetCommonInputContainer();
  mgr->ConnectInput(task, 0, cinput);

  TString stContainerName;
  stContainerName = Form("dNdPt_pp_%d",cutMode);
  if(!stParticleMode.Contains("default")) {
    stContainerName = stContainerName + "_" +stParticleMode;
  }

  AliAnalysisDataContainer *coutput = mgr->CreateContainer(stContainerName,TList::Class(),AliAnalysisManager::kOutputContainer, mgr->GetCommonFileName());

  mgr->ConnectOutput(task, 1, coutput);
}

<|endoftext|>


<commit_before>#ifndef ARRAY_HPP
#define ARRAY_HPP

#include <algorithm>

template<class T, unsigned S>
class Array {
private:
    T array[S];

public:
    Array() {}
    Array(const Array<T, S>&);

    unsigned size() const;
    bool empty() const;
    void fill(const T&);

    T& operator[](unsigned i);
    const T& operator[](unsigned i) const;
    Array<T, S>& operator=(Array<T, S>);

};

template<class T, unsigned S>
Array<T, S>::Array(const Array<T, S>& p) {
    for(unsigned i = 0; i < S; ++i) {
        this->array[i] = p.array[i];
    }
}

template<class T, unsigned S>
inline unsigned Array<T, S>::size() const {
    return S;
}

template<class T, unsigned S>
inline bool Array<T, S>::empty() const {
    return S == 0;
}

template<class T, unsigned S>
inline void Array<T, S>::fill(const T& p) {
    std::fill(this->array, this->array + S, p);
}

template<class T, unsigned S>
inline T& Array<T, S>::operator[](unsigned i) {
    return this->array[i];
}

template<class T, unsigned S>
inline const T& Array<T, S>::operator[](unsigned i) const {
    return this->array[i];
}

template<class T, unsigned S>
Array<T, S>& Array<T, S>::operator=(Array<T, S> p) {
    std::swap(this->array, p.array);
    return *this;
}

#endif
<commit_msg>Array comparison<commit_after>#ifndef ARRAY_HPP
#define ARRAY_HPP

#include <algorithm>

template<class T, unsigned S>
class Array {
private:
    T array[S];

public:
    Array() {}
    Array(const Array<T, S>&);

    unsigned size() const;
    bool empty() const;
    void fill(const T&);

    T& operator[](unsigned i);
    const T& operator[](unsigned i) const;
    Array<T, S>& operator=(Array<T, S>);

    bool operator==(const Array<T, S>&) const;
    bool operator!=(const Array<T, S>&) const;

};

template<class T, unsigned S>
Array<T, S>::Array(const Array<T, S>& p) {
    for(unsigned i = 0; i < S; ++i) {
        this->array[i] = p.array[i];
    }
}

template<class T, unsigned S>
inline unsigned Array<T, S>::size() const {
    return S;
}

template<class T, unsigned S>
inline bool Array<T, S>::empty() const {
    return S == 0;
}

template<class T, unsigned S>
inline void Array<T, S>::fill(const T& p) {
    std::fill(this->array, this->array + S, p);
}

template<class T, unsigned S>
inline T& Array<T, S>::operator[](unsigned i) {
    return this->array[i];
}

template<class T, unsigned S>
inline const T& Array<T, S>::operator[](unsigned i) const {
    return this->array[i];
}

template<class T, unsigned S>
Array<T, S>& Array<T, S>::operator=(Array<T, S> p) {
    std::swap(this->array, p.array);
    return *this;
}

template<class T, unsigned S>
bool Array<T, S>::operator==(const Array<T, S>& p) const {
    for(unsigned i = 0; i < S; ++i) {
        if(this->array[i] != p.array[i]) {
            return false;
        }
    }
    return true;
}

template<class T, unsigned S>
bool Array<T, S>::operator!=(const Array<T, S>& p) const {
    return *this == p;
}

#endif
<|endoftext|>


<commit_before>#include "usbui.h"
#include "usbbusinesslogic.h"

#include <DuiNotification>
#include <DuiSceneWindow>
#include <DuiButton>
#include <DuiDialog>
#include <DuiLocale>
#include <QTimer>

#define DEBUG
#define WARNING
#include "../debug.h"

UsbUi::UsbUi (QObject *parent) : QObject (parent),
    m_logic (0),
    m_notification (0),
    m_dialog (0)
{
    m_logic = new UsbBusinessLogic (this);

    QObject::connect (m_logic, SIGNAL (UsbCableEvent (UsbCableType)),
                      this, SLOT (UsbEvent (UsbCableType)));

    // It is for UsbBusinessLogicAdaptor:
    QObject::connect (m_logic, SIGNAL (ShowDialog ()),
                      this, SLOT (ShowDialog ()));
}

UsbUi::~UsbUi ()
{
    if (m_dialog)
    {
        m_dialog->disappearNow ();
        delete m_dialog;
        m_dialog = 0;
    }
}

// Showing the mode selection dialog
// (when mode is usb-auto / "ask on connection")
// TODO: test this, how does it looks?
void
UsbUi::ShowDialog ()
{
    SYS_DEBUG ("");
    DuiButtonModel  *button;

    if (m_dialog)
    {
        m_dialog->appear ();
        m_dialog->setFocus ();
        return;
    }

    m_dialog = new DuiDialog;

    //% "Usb connected"
    m_dialog->setTitle (qtTrId ("qtn_usb_connected_title"));
    m_dialog->setWindowModal (true);

    //% "Ovi Suite"
    button = m_dialog->addButton (qtTrId ("qtn_usb_ovi_suite"));
    QObject::connect (button, SIGNAL (clicked ()),
                      this, SLOT (OviSuiteSelected ()));

    //% "Mass Storage"
    button = m_dialog->addButton (qtTrId ("qtn_usb_mass_storage"));
    QObject::connect (button, SIGNAL (clicked ()),
                      this, SLOT (MassStorageSelected ()));

    m_dialog->appear ();
}

void
UsbUi::OviSuiteSelected ()
{
    SYS_DEBUG ("");
    m_logic->setMode (USB_OVI_SUITE);
    // XXX: do we need this?
    m_dialog->disappear ();
}

void
UsbUi::MassStorageSelected ()
{
    SYS_DEBUG ("");
    m_logic->setMode (USB_MASS_STORAGE);
    // XXX: do we need this?
    m_dialog->disappear ();
}

// Showing notification on connection/disconnection
void
UsbUi::UsbEvent (UsbCableType cable)
{
    SYS_DEBUG ("");

    // remove previous one
    if (m_notification)
    {
        m_notification->remove ();
        delete m_notification;
        m_notification = 0;
    }
    // FIXME: add some nice icons to the notificitations

    if (cable == CABLE_NONE)
    {
        //% "Usb-cable disconnected"
        m_notification = new DuiNotification ("", "", qtTrId ("qtn_usb_disconnected"));

        // Hide the mode-selection dialog
        if (m_dialog)
            m_dialog->disappear ();

        return;
    }
    else if (cable == CABLE_HOST)
    {
        // Not implemented ...
        return;
    }

    usb_modes   config    = m_logic->getModeSetting ();
    QString    *mode_text = 0;

    // Activate the desired usb mode
    if (config != USB_AUTO)
        m_logic->setMode (config);

    switch (config)
    {
        case USB_OVI_SUITE:
            //% "Ovi Suite"
            mode_text = new QString (qtTrId ("qtn_usb_ovi_suite"));
            break;
        case USB_MASS_STORAGE:
            //% "Mass Storage"
            mode_text = new QString (qtTrId ("qtn_usb_mass_storage"));
            break;
        case USB_NOOP:
            //% "Do nothing"
            mode_text = new QString (qtTrId ("qtn_usb_do_nothing"));
            break;
        case USB_AUTO:
            ShowDialog ();
            return;
    }

    //% "Usb connected
Selected mode: %1"
    m_notification =
        new DuiNotification ("", "", qtTrId ("qtn_usb_connected_%1").arg (*mode_text));
}

// for dbus adaptor
UsbBusinessLogic *
UsbUi::getLogic ()
{
    return m_logic;
}

<commit_msg>SysUId: Usb ui fixes (use usb-icon for notifications, usb-mode-selection window layout fixed)<commit_after>#include "usbui.h"
#include "usbbusinesslogic.h"

#include <QGraphicsLinearLayout>
#include <DuiWidget>
#include <DuiNotification>
#include <DuiSceneWindow>
#include <DuiButton>
#include <DuiDialog>
#include <DuiLocale>
#include <QTimer>

#define DEBUG
#define WARNING
#include "../debug.h"

UsbUi::UsbUi (QObject *parent) : QObject (parent),
    m_logic (0),
    m_notification (0),
    m_dialog (0)
{
    m_logic = new UsbBusinessLogic (this);

    QObject::connect (m_logic, SIGNAL (UsbCableEvent (UsbCableType)),
                      this, SLOT (UsbEvent (UsbCableType)));

    // It is for UsbBusinessLogicAdaptor:
    QObject::connect (m_logic, SIGNAL (ShowDialog ()),
                      this, SLOT (ShowDialog ()));
}

UsbUi::~UsbUi ()
{
    if (m_dialog)
    {
        m_dialog->disappearNow ();
        delete m_dialog;
        m_dialog = 0;
    }
}

// Showing the mode selection dialog
// (when mode is usb-auto / "ask on connection")
void
UsbUi::ShowDialog ()
{
    SYS_DEBUG ("");
    DuiButton  *button;
    DuiWidget  *hbox;

    if (m_dialog)
    {
        m_dialog->appear ();
        m_dialog->setFocus ();
        return;
    }

    m_dialog = new DuiDialog;

    //% "Usb connected"
    m_dialog->setTitle (qtTrId ("qtn_usb_connected_title"));
    m_dialog->setWindowModal (true);

    QGraphicsLinearLayout *layout = new QGraphicsLinearLayout;

    //% "Ovi Suite"
    button = new DuiButton (qtTrId ("qtn_usb_ovi_suite"), m_dialog);

    layout->addItem (button);
    layout->setStretchFactor (button, 1);

    QObject::connect (button, SIGNAL (clicked ()),
                      this, SLOT (OviSuiteSelected ()));

    //% "Mass Storage"
    button = new DuiButton (qtTrId ("qtn_usb_mass_storage"), m_dialog);

    layout->addItem (button);
    layout->setStretchFactor (button, 1);

    QObject::connect (button, SIGNAL (clicked ()),
                      this, SLOT (MassStorageSelected ()));

    hbox = new DuiWidget (m_dialog);
    hbox->setLayout (layout);

    m_dialog->setCentralWidget (hbox);

    m_dialog->setButtonBoxVisible (false);
    m_dialog->appear ();
}

void
UsbUi::OviSuiteSelected ()
{
    SYS_DEBUG ("");

    m_logic->setMode (USB_OVI_SUITE);

    m_dialog->disappear ();
}

void
UsbUi::MassStorageSelected ()
{
    SYS_DEBUG ("");

    m_logic->setMode (USB_MASS_STORAGE);

    m_dialog->disappear ();
}

// Showing notification on connection/disconnection
void
UsbUi::UsbEvent (UsbCableType cable)
{
    SYS_DEBUG ("");

    // remove previous one
    if (m_notification)
    {
        m_notification->remove ();
        delete m_notification;
        m_notification = 0;
    }

    if (cable == CABLE_NONE)
    {
        //% "Usb disconnected"
        m_notification = new DuiNotification ("",
                                              "",
                                              qtTrId ("qtn_usb_disconnected"),
                                              "icon-m-usb");

        // Hide the mode-selection dialog
        if (m_dialog)
            m_dialog->disappear ();

        return;
    }
    else if (cable == CABLE_HOST)
    {
        // Not implemented ...
        return;
    }

    usb_modes   config    = m_logic->getModeSetting ();
    QString    *mode_text = 0;

    // Activate the desired usb mode
    if (config != USB_AUTO)
        m_logic->setMode (config);

    switch (config)
    {
        case USB_OVI_SUITE:
            //% "Ovi Suite"
            mode_text = new QString (qtTrId ("qtn_usb_ovi_suite"));
            break;
        case USB_MASS_STORAGE:
            //% "Mass Storage"
            mode_text = new QString (qtTrId ("qtn_usb_mass_storage"));
            break;
        case USB_NOOP:
            //% "Do nothing"
            mode_text = new QString (qtTrId ("qtn_usb_do_nothing"));
            break;
        case USB_AUTO:
            ShowDialog ();
            return;
    }

    //% "Usb connected
Selected mode: %1"
    m_notification =
        new DuiNotification ("",
                             "",
                             qtTrId ("qtn_usb_connected_%1").arg (*mode_text),
                             "icon-m-usb");
}

// for dbus adaptor
UsbBusinessLogic *
UsbUi::getLogic ()
{
    return m_logic;
}

<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "testing/gtest/include/gtest/gtest.h"

#include "base/ref_counted.h"
#include "chrome/renderer/render_widget.h"
#include "chrome/renderer/render_thread.h"

// This class is very simple mock of RenderThread. It simulates an IPC channel
// which supports only two messages:
// ViewHostMsg_CreateWidget : sync message sent by the Widget.
// ViewMsg_Close : async, send to the Widget.
class MockRenderThread : public RenderThreadBase {
 public:
  MockRenderThread()
      : routing_id_(0), opener_id_(0), widget_(NULL),
        reply_deserializer_(NULL) {
  }
  virtual ~MockRenderThread() {
  }

  // Called by the Widget. Not used in the test.
  virtual bool InSend() const {
    return false;
  }

  // Called by the Widget. The routing_id must match the routing id assigned
  // to the Widget in reply to ViewHostMsg_CreateWidget message.
  virtual void AddRoute(int32 routing_id, IPC::Channel::Listener* listener) {
    EXPECT_EQ(routing_id_, routing_id);
    widget_ = listener;
  }

  // Called by the Widget. The routing id must match the routing id of AddRoute.
  virtual void RemoveRoute(int32 routing_id) {
    EXPECT_EQ(routing_id_, routing_id);
    widget_ = NULL;
  }

  // Called by the Widget. Used to send messages to the browser.
  // We short-circuit the mechanim and handle the messages right here on this
  // class.
  virtual bool Send(IPC::Message* msg) {
    // We need to simulate a synchronous channel, thus we are going to receive
    // through this function messages, messages with reply and reply messages.
    // We can only handle one synchronous message at a time.
    if (msg->is_reply()) {
      if (reply_deserializer_)
        reply_deserializer_->SerializeOutputParameters(*msg);
        reply_deserializer_ = NULL;
    } else {
      if (msg->is_sync()) {
        reply_deserializer_ =
            static_cast<IPC::SyncMessage*>(msg)->GetReplyDeserializer();
      }
      OnMessageReceived(*msg);
    }
    delete msg;
    return true;
  }

  //////////////////////////////////////////////////////////////////////////
  // The following functions are called by the test itself.

  void set_routing_id(int32 id) {
    routing_id_ = id;
  }

  int32 opener_id() const {
    return opener_id_;
  }

  bool has_widget() const {
    return widget_ ? true : false;
  }

  // Simulates the Widget receiving a close message. This should result
  // on releasing the internal reference counts and destroying the internal
  // state.
  void SendCloseMessage() {
    ViewMsg_Close msg(routing_id_);
    widget_->OnMessageReceived(msg);
  }

 private:

  // This function operates as a regular IPC listener.
  void OnMessageReceived(const IPC::Message& msg) {
    bool handled = true;
    bool msg_is_ok = true;
    IPC_BEGIN_MESSAGE_MAP_EX(MockRenderThread, msg, msg_is_ok)
      IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWidget, OnMsgCreateWidget);
      IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP_EX()

    // This test must handle all messages that RenderWidget generates.
    EXPECT_TRUE(handled);
  }

  // The Widget expects to be returned valid route_id.
  void OnMsgCreateWidget(int opener_id, int* route_id) {
    opener_id_ = opener_id;
    *route_id = routing_id_;
  }

  // Routing id what will be assigned to the Widget.
  int32 routing_id_;
  // Opener id reported by the Widget.
  int32 opener_id_;
  // We only keep track of one Widget, we learn its pointer when it
  // adds a new route.
  IPC::Channel::Listener* widget_;
  // The last known good deserializer for sync messages.
  IPC::MessageReplyDeserializer* reply_deserializer_;
};

TEST(RenderWidgetTest, DISABLED_CreateAndCloseWidget) {
  MessageLoop msg_loop;
  MockRenderThread render_thread;

  const int32 kRouteId = 5;
  const int32 kOpenerId = 7;

  render_thread.set_routing_id(kRouteId);
  scoped_refptr<RenderWidget> rw =
      RenderWidget::Create(kOpenerId, &render_thread);
  ASSERT_TRUE(rw != NULL);

  // After the RenderWidget it must have sent a message to the render thread
  // that sets the opener id.
  EXPECT_EQ(kOpenerId, render_thread.opener_id());
  ASSERT_TRUE(render_thread.has_widget());

  // Now simulate a close of the Widget.
  render_thread.SendCloseMessage();
  EXPECT_FALSE(render_thread.has_widget());
}

<commit_msg>Modify renderwidget unittest to make purify happy - Some posted task was not being processed. - It needed a mock of RenderProcess.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "testing/gtest/include/gtest/gtest.h"

#include "base/ref_counted.h"
#include "chrome/common/child_process.h"
#include "chrome/renderer/render_widget.h"
#include "chrome/renderer/render_thread.h"

// This class is a trivial mock of the child process singleton. It is necessary
// so we don't trip DCHECKs in ChildProcess::ReleaseProcess() when destroying
// a render widget instance.
class MockProcess : public ChildProcess {
 public:
  explicit MockProcess(const std::wstring& channel_name) {}
  static void GlobalInit() {
    ChildProcessFactory<MockProcess> factory;
    ChildProcess::GlobalInit(L"dummy", &factory);
  }
};

// This class is very simple mock of RenderThread. It simulates an IPC channel
// which supports only two messages:
// ViewHostMsg_CreateWidget : sync message sent by the Widget.
// ViewMsg_Close : async, send to the Widget.
class MockRenderThread : public RenderThreadBase {
 public:
  MockRenderThread()
      : routing_id_(0), opener_id_(0), widget_(NULL),
        reply_deserializer_(NULL) {
  }
  virtual ~MockRenderThread() {
  }

  // Called by the Widget. Not used in the test.
  virtual bool InSend() const {
    return false;
  }

  // Called by the Widget. The routing_id must match the routing id assigned
  // to the Widget in reply to ViewHostMsg_CreateWidget message.
  virtual void AddRoute(int32 routing_id, IPC::Channel::Listener* listener) {
    EXPECT_EQ(routing_id_, routing_id);
    widget_ = listener;
  }

  // Called by the Widget. The routing id must match the routing id of AddRoute.
  virtual void RemoveRoute(int32 routing_id) {
    EXPECT_EQ(routing_id_, routing_id);
    widget_ = NULL;
  }

  // Called by the Widget. Used to send messages to the browser.
  // We short-circuit the mechanim and handle the messages right here on this
  // class.
  virtual bool Send(IPC::Message* msg) {
    // We need to simulate a synchronous channel, thus we are going to receive
    // through this function messages, messages with reply and reply messages.
    // We can only handle one synchronous message at a time.
    if (msg->is_reply()) {
      if (reply_deserializer_)
        reply_deserializer_->SerializeOutputParameters(*msg);
        delete reply_deserializer_;
        reply_deserializer_ = NULL;
    } else {
      if (msg->is_sync()) {
        reply_deserializer_ =
            static_cast<IPC::SyncMessage*>(msg)->GetReplyDeserializer();
      }
      OnMessageReceived(*msg);
    }
    delete msg;
    return true;
  }

  //////////////////////////////////////////////////////////////////////////
  // The following functions are called by the test itself.

  void set_routing_id(int32 id) {
    routing_id_ = id;
  }

  int32 opener_id() const {
    return opener_id_;
  }

  bool has_widget() const {
    return widget_ ? true : false;
  }

  // Simulates the Widget receiving a close message. This should result
  // on releasing the internal reference counts and destroying the internal
  // state.
  void SendCloseMessage() {
    ViewMsg_Close msg(routing_id_);
    widget_->OnMessageReceived(msg);
  }

 private:

  // This function operates as a regular IPC listener.
  void OnMessageReceived(const IPC::Message& msg) {
    bool handled = true;
    bool msg_is_ok = true;
    IPC_BEGIN_MESSAGE_MAP_EX(MockRenderThread, msg, msg_is_ok)
      IPC_MESSAGE_HANDLER(ViewHostMsg_CreateWidget, OnMsgCreateWidget);
      IPC_MESSAGE_UNHANDLED(handled = false)
    IPC_END_MESSAGE_MAP_EX()

    // This test must handle all messages that RenderWidget generates.
    EXPECT_TRUE(handled);
  }

  // The Widget expects to be returned valid route_id.
  void OnMsgCreateWidget(int opener_id, int* route_id) {
    opener_id_ = opener_id;
    *route_id = routing_id_;
  }

  // Routing id what will be assigned to the Widget.
  int32 routing_id_;
  // Opener id reported by the Widget.
  int32 opener_id_;
  // We only keep track of one Widget, we learn its pointer when it
  // adds a new route.
  IPC::Channel::Listener* widget_;
  // The last known good deserializer for sync messages.
  IPC::MessageReplyDeserializer* reply_deserializer_;
};

TEST(RenderWidgetTest, CreateAndCloseWidget) {
  MessageLoop msg_loop;
  MockRenderThread render_thread;
  MockProcess::GlobalInit();

  const int32 kRouteId = 5;
  const int32 kOpenerId = 7;
  render_thread.set_routing_id(kRouteId);

  {
  scoped_refptr<RenderWidget> rw =
      RenderWidget::Create(kOpenerId, &render_thread);
  ASSERT_TRUE(rw != NULL);

  // After the RenderWidget it must have sent a message to the render thread
  // that sets the opener id.
  EXPECT_EQ(kOpenerId, render_thread.opener_id());
  ASSERT_TRUE(render_thread.has_widget());

  // Now simulate a close of the Widget.
  render_thread.SendCloseMessage();
  EXPECT_FALSE(render_thread.has_widget());

    // Run the loop so the release task from the renderwidget executes.
    msg_loop.PostTask(FROM_HERE, new MessageLoop::QuitTask());
    msg_loop.Run();
}

  // There is a delayed task that the child process posts to terminate the
  // message loop so we need to spin the message loop to delete the task.
  MockProcess::GlobalCleanup();
  msg_loop.Run();
}
<|endoftext|>