<commit_before>/* Copyright 2021 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/c/common.h"
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
#include "tensorflow/lite/kernels/kernel_util.h"
#include "tensorflow/lite/micro/kernels/kernel_util.h"
#include "tensorflow/lite/micro/micro_utils.h"

namespace tflite {
namespace {

constexpr int kInputTensor = 0;
constexpr int kAxisTensor = 1;
constexpr int kOutputTensor = 0;

TfLiteStatus ExpandTensorDim(TfLiteContext* context,
                             const TfLiteEvalTensor* input, int axis,
                             TfLiteEvalTensor* output) {
  const TfLiteIntArray* input_dims = input->dims;
  TfLiteIntArray* output_dims = output->dims;
  if (axis < 0) {
    axis = output_dims->size + axis;
  }
  TF_LITE_ENSURE(context, axis <= input_dims->size);

  for (int i = 0; i < output_dims->size; ++i) {
    if (i < axis) {
      output_dims->data[i] = input_dims->data[i];
    } else if (i == axis) {
      output_dims->data[i] = 1;
    } else {
      output_dims->data[i] = input_dims->data[i - 1];
    }
  }
  return kTfLiteOk;
}

TfLiteStatus GetAxisValueFromTensor(TfLiteContext* context,
                                    const TfLiteEvalTensor* axis,
                                    int32_t* axis_value) {
  const int axis_dims = (tflite::micro::GetTensorShape(axis)).DimensionsCount();
  if (axis_dims > 1) {
    TF_LITE_KERNEL_LOG(context, "Axis has only one element for Expand_Dims.",
                       axis_dims);
    return kTfLiteError;
  }

  if (kTfLiteInt32 == (axis->type)) {
    const int32_t* axis_ptr = tflite::micro::GetTensorData<int32_t>(axis);
    *axis_value = axis_ptr[0];
    return kTfLiteOk;
  } else {
    TF_LITE_KERNEL_LOG(context,
                       "Axis type %s (%d) not supported by Expand_Dims.",
                       TfLiteTypeGetName(axis->type), axis->type);
    return kTfLiteError;
  }
}

TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
  TF_LITE_ENSURE_EQ(context, NumInputs(node), 2);
  TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1);
  const TfLiteTensor* input;
  TF_LITE_ENSURE_OK(context, GetInputSafe(context, node, kInputTensor, &input));
  const TfLiteTensor* axis;
  TF_LITE_ENSURE_OK(context, GetInputSafe(context, node, kAxisTensor, &axis));
  TfLiteTensor* output;
  TF_LITE_ENSURE_OK(context,
                    GetOutputSafe(context, node, kOutputTensor, &output));
  output->type = input->type;
  if (IsDynamicTensor(axis)) {
    TF_LITE_KERNEL_LOG(context,
                       "DynamicTensor is not yet supported by Expand_Dims.");
    return kTfLiteError;
  }
  return kTfLiteOk;
}

template <typename Tin, typename Tout>
void memCopyN(Tout* out, Tin* in, const int num_elements) {
  for (int i = 0; i < num_elements; ++i) {
    out[i] = static_cast<Tout>(in[i]);
  }
}

TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
  const TfLiteEvalTensor* input =
      tflite::micro::GetEvalInput(context, node, kInputTensor);
  const TfLiteEvalTensor* axis =
      tflite::micro::GetEvalInput(context, node, kAxisTensor);
  TfLiteEvalTensor* output =
      tflite::micro::GetEvalOutput(context, node, kOutputTensor);
  const int flat_size = ElementCount(*input->dims);
  const int input_dims = input->dims->size;

  int axis_value;
  TF_LITE_ENSURE_OK(context,
                    GetAxisValueFromTensor(context, axis, &axis_value));
  if ((axis_value > static_cast<int32_t>(input_dims)) ||
      (axis_value < static_cast<int32_t>(-(input_dims + 1)))) {
    TF_LITE_KERNEL_LOG(context, "Invalid Expand_Dims axis value (%d).",
                       axis_value);
    return kTfLiteError;
  }
  ExpandTensorDim(context, input, axis_value, output);

  switch (input->type) {
    case kTfLiteFloat32: {
      memCopyN(tflite::micro::GetTensorData<float>(output),
               tflite::micro::GetTensorData<float>(input), flat_size);
    } break;
    case kTfLiteInt8: {
      memCopyN(tflite::micro::GetTensorData<int8_t>(output),
               tflite::micro::GetTensorData<int8_t>(input), flat_size);
    } break;
    default:
      TF_LITE_KERNEL_LOG(
          context,
          "Expand_Dims only currently supports int8 and float32, got %d.",
          input->type);
      return kTfLiteError;
  }
  return kTfLiteOk;
}
}  // namespace

TfLiteRegistration Register_EXPAND_DIMS() {
  return {/*init=*/nullptr,
          /*free=*/nullptr,
          /*prepare=*/Prepare,
          /*invoke=*/Eval,
          /*profiling_string=*/nullptr,
          /*builtin_code=*/0,
          /*custom_name=*/nullptr,
          /*version=*/0};
}

}  // namespace tflite
<commit_msg>Consolidate int32_t axis to int for micro o EXPAND_DIMS<commit_after>/* Copyright 2021 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/c/common.h"
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
#include "tensorflow/lite/kernels/kernel_util.h"
#include "tensorflow/lite/micro/kernels/kernel_util.h"
#include "tensorflow/lite/micro/micro_utils.h"

namespace tflite {
namespace {

constexpr int kInputTensor = 0;
constexpr int kAxisTensor = 1;
constexpr int kOutputTensor = 0;

TfLiteStatus ExpandTensorDim(TfLiteContext* context,
                             const TfLiteEvalTensor* input, int axis,
                             TfLiteEvalTensor* output) {
  const TfLiteIntArray* input_dims = input->dims;
  TfLiteIntArray* output_dims = output->dims;
  if (axis < 0) {
    axis = output_dims->size + axis;
  }
  TF_LITE_ENSURE(context, axis <= input_dims->size);

  for (int i = 0; i < output_dims->size; ++i) {
    if (i < axis) {
      output_dims->data[i] = input_dims->data[i];
    } else if (i == axis) {
      output_dims->data[i] = 1;
    } else {
      output_dims->data[i] = input_dims->data[i - 1];
    }
  }
  return kTfLiteOk;
}

TfLiteStatus GetAxisValueFromTensor(TfLiteContext* context,
                                    const TfLiteEvalTensor* axis,
                                    int* axis_value) {
  const int axis_dims = (tflite::micro::GetTensorShape(axis)).DimensionsCount();
  if (axis_dims > 1) {
    TF_LITE_KERNEL_LOG(context, "Axis has only one element for Expand_Dims.",
                       axis_dims);
    return kTfLiteError;
  }

  if (kTfLiteInt32 == (axis->type)) {
    const int* axis_ptr = tflite::micro::GetTensorData<int>(axis);
    *axis_value = axis_ptr[0];
    return kTfLiteOk;
  } else {
    TF_LITE_KERNEL_LOG(context,
                       "Axis type %s (%d) not supported by Expand_Dims.",
                       TfLiteTypeGetName(axis->type), axis->type);
    return kTfLiteError;
  }
}

TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
  TF_LITE_ENSURE_EQ(context, NumInputs(node), 2);
  TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1);
  const TfLiteTensor* input;
  TF_LITE_ENSURE_OK(context, GetInputSafe(context, node, kInputTensor, &input));
  const TfLiteTensor* axis;
  TF_LITE_ENSURE_OK(context, GetInputSafe(context, node, kAxisTensor, &axis));
  TfLiteTensor* output;
  TF_LITE_ENSURE_OK(context,
                    GetOutputSafe(context, node, kOutputTensor, &output));
  output->type = input->type;
  if (IsDynamicTensor(axis)) {
    TF_LITE_KERNEL_LOG(context,
                       "DynamicTensor is not yet supported by Expand_Dims.");
    return kTfLiteError;
  }
  return kTfLiteOk;
}

template <typename Tin, typename Tout>
void memCopyN(Tout* out, Tin* in, const int num_elements) {
  for (int i = 0; i < num_elements; ++i) {
    out[i] = static_cast<Tout>(in[i]);
  }
}

TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
  const TfLiteEvalTensor* input =
      tflite::micro::GetEvalInput(context, node, kInputTensor);
  const TfLiteEvalTensor* axis =
      tflite::micro::GetEvalInput(context, node, kAxisTensor);
  TfLiteEvalTensor* output =
      tflite::micro::GetEvalOutput(context, node, kOutputTensor);
  const int flat_size = ElementCount(*input->dims);
  const int input_dims = input->dims->size;

  int axis_value;
  TF_LITE_ENSURE_OK(context,
                    GetAxisValueFromTensor(context, axis, &axis_value));
  if ((axis_value > static_cast<int>(input_dims)) ||
      (axis_value < static_cast<int>(-(input_dims + 1)))) {
    TF_LITE_KERNEL_LOG(context, "Invalid Expand_Dims axis value (%d).",
                       axis_value);
    return kTfLiteError;
  }
  ExpandTensorDim(context, input, axis_value, output);

  switch (input->type) {
    case kTfLiteFloat32: {
      memCopyN(tflite::micro::GetTensorData<float>(output),
               tflite::micro::GetTensorData<float>(input), flat_size);
    } break;
    case kTfLiteInt8: {
      memCopyN(tflite::micro::GetTensorData<int8_t>(output),
               tflite::micro::GetTensorData<int8_t>(input), flat_size);
    } break;
    default:
      TF_LITE_KERNEL_LOG(
          context,
          "Expand_Dims only currently supports int8 and float32, got %d.",
          input->type);
      return kTfLiteError;
  }
  return kTfLiteOk;
}
}  // namespace

TfLiteRegistration Register_EXPAND_DIMS() {
  return {/*init=*/nullptr,
          /*free=*/nullptr,
          /*prepare=*/Prepare,
          /*invoke=*/Eval,
          /*profiling_string=*/nullptr,
          /*builtin_code=*/0,
          /*custom_name=*/nullptr,
          /*version=*/0};
}

}  // namespace tflite
<|endoftext|>


<commit_before>#include "ParticleSystem.h"
#include <vector>

#define BUFFER_OFFSET(i) ((char *)nullptr + (i))

ParticleSystem::ParticleSystem(ShaderProgram* shaderProgram, Texture* texture, glm::vec3 origin, int maxParticleCount, int chanceToEmit, float maxVelocity, float maxLifeTime) {
	this->shaderProgram = shaderProgram;
	this->texture = texture;

	particleOrigin = origin;
	this->maxParticleCount = maxParticleCount;
	this->chanceToEmit = chanceToEmit;
	this->maxVelocity = maxVelocity;
	this->maxLifeTime = maxLifeTime;
	particleCount = 0;

	bindPointData();
}

ParticleSystem::~ParticleSystem() {
	glDeleteBuffers(1, &vertexBuffer);
}

unsigned int ParticleSystem::getParticleCount() {
	return particleCount;
}

unsigned int ParticleSystem::getMaxParticleCount() {
	return maxParticleCount;
}

void ParticleSystem::update(double time) {
	if (!this->particlePositions.empty()) {
		for (std::vector<int>::size_type i = 0; i != particleProperties.size(); i++) {
			if (particleProperties[i].lifetime > maxLifeTime) {
				particlePositions.erase(particlePositions.begin() + i);
				particleProperties.erase(particleProperties.begin() + i);
				particleCount--;
				i--;
			} else {
				particlePositions[i].worldPos += static_cast<float>(time)* particleProperties[i].velocity;
				particleProperties[i].lifetime += static_cast<float>(time);
			}
		}
	}
	emitParticle();

	if (particleCount > 0)
		glBufferSubData(GL_ARRAY_BUFFER, 0, particleCount * sizeof(ParticleSystem::ParticlePosition), &this->particlePositions[0]);
}

void ParticleSystem::render(int width, int height, const Camera* camera) {
	shaderProgram->use();

	glUniform1i(shaderProgram->uniformLocation("baseImage"), 0);

	glActiveTexture(GL_TEXTURE0 + 0);
	glBindTexture(GL_TEXTURE_2D, texture->textureID());

	glBindVertexArray(vertexAttribute);

	// Base image texture
	glActiveTexture(GL_TEXTURE0 + 0);
	glBindTexture(GL_TEXTURE_2D, texture->textureID());

	// Send the matrices to the shader.
	glm::mat4 view = camera->view();

	glUniformMatrix4fv(shaderProgram->uniformLocation("viewMatrix"), 1, GL_FALSE, &view[0][0]);
	glUniformMatrix4fv(shaderProgram->uniformLocation("projectionMatrix"), 1, GL_FALSE, &camera->projection(width, height)[0][0]);

	// Draw the triangles
	glDrawArrays(GL_POINTS, 0, getParticleCount());
}

void ParticleSystem::bindPointData() {
	// Vertex buffer
	glGenBuffers(1, &vertexBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
	glBufferData(GL_ARRAY_BUFFER, maxParticleCount * sizeof(ParticleSystem::ParticlePosition), NULL, GL_DYNAMIC_DRAW);

	// Define vertex data layout
	glGenVertexArrays(1, &vertexAttribute);
	glBindVertexArray(vertexAttribute);
	glEnableVertexAttribArray(0);

	GLuint vertexPos = shaderProgram->attributeLocation("vertex_position");
	glVertexAttribPointer(vertexPos, 3, GL_FLOAT, GL_FALSE, sizeof(ParticleSystem::ParticlePosition), BUFFER_OFFSET(0));
}

void ParticleSystem::emitParticle() {
	if ((rand() % 1000 < chanceToEmit) && (particleCount < maxParticleCount)) {
		ParticlePosition newPosition;
		ParticleProperty newProperty;

		newPosition.worldPos = particleOrigin;
		newProperty.lifetime = 0.f - static_cast<float>(rand() % static_cast<int>(maxLifeTime * 2));
		newProperty.velocity.x = static_cast<float>(rand() % (2 * static_cast<int>(maxVelocity)) - static_cast<int>(maxVelocity));
		newProperty.velocity.y = static_cast<float>(rand() % (2 * static_cast<int>(maxVelocity)) - static_cast<int>(maxVelocity));
		newProperty.velocity.z = static_cast<float>(rand() % (2 * static_cast<int>(maxVelocity)) - static_cast<int>(maxVelocity));

		particlePositions.push_back(newPosition);
		particleProperties.push_back(newProperty);

		particleCount++;
	}
}<commit_msg>Additive particle blending<commit_after>#include "ParticleSystem.h"
#include <vector>

#define BUFFER_OFFSET(i) ((char *)nullptr + (i))

ParticleSystem::ParticleSystem(ShaderProgram* shaderProgram, Texture* texture, glm::vec3 origin, int maxParticleCount, int chanceToEmit, float maxVelocity, float maxLifeTime) {
	this->shaderProgram = shaderProgram;
	this->texture = texture;

	particleOrigin = origin;
	this->maxParticleCount = maxParticleCount;
	this->chanceToEmit = chanceToEmit;
	this->maxVelocity = maxVelocity;
	this->maxLifeTime = maxLifeTime;
	particleCount = 0;

	bindPointData();
}

ParticleSystem::~ParticleSystem() {
	glDeleteBuffers(1, &vertexBuffer);
}

unsigned int ParticleSystem::getParticleCount() {
	return particleCount;
}

unsigned int ParticleSystem::getMaxParticleCount() {
	return maxParticleCount;
}

void ParticleSystem::update(double time) {
	if (!this->particlePositions.empty()) {
		for (std::vector<int>::size_type i = 0; i != particleProperties.size(); i++) {
			if (particleProperties[i].lifetime > maxLifeTime) {
				particlePositions.erase(particlePositions.begin() + i);
				particleProperties.erase(particleProperties.begin() + i);
				particleCount--;
				i--;
			} else {
				particlePositions[i].worldPos += static_cast<float>(time)* particleProperties[i].velocity;
				particleProperties[i].lifetime += static_cast<float>(time);
			}
		}
	}
	emitParticle();

	if (particleCount > 0)
		glBufferSubData(GL_ARRAY_BUFFER, 0, particleCount * sizeof(ParticleSystem::ParticlePosition), &this->particlePositions[0]);
}

void ParticleSystem::render(int width, int height, const Camera* camera) {
	// Don't write to depth buffer.
	GLboolean depthWriting;
	glGetBooleanv(GL_DEPTH_WRITEMASK, &depthWriting);
	glDepthMask(GL_FALSE);

	// Blending
	GLboolean blending;
	glGetBooleanv(GL_BLEND, &blending);
	glEnable(GL_BLEND);
	glBlendFunc(GL_ONE, GL_ONE);

	shaderProgram->use();

	glUniform1i(shaderProgram->uniformLocation("baseImage"), 0);

	glActiveTexture(GL_TEXTURE0 + 0);
	glBindTexture(GL_TEXTURE_2D, texture->textureID());

	glBindVertexArray(vertexAttribute);

	// Base image texture
	glActiveTexture(GL_TEXTURE0 + 0);
	glBindTexture(GL_TEXTURE_2D, texture->textureID());

	// Send the matrices to the shader.
	glm::mat4 view = camera->view();

	glUniformMatrix4fv(shaderProgram->uniformLocation("viewMatrix"), 1, GL_FALSE, &view[0][0]);
	glUniformMatrix4fv(shaderProgram->uniformLocation("projectionMatrix"), 1, GL_FALSE, &camera->projection(width, height)[0][0]);

	// Draw the triangles
	glDrawArrays(GL_POINTS, 0, getParticleCount());

	// Reset state values we've changed.
	glDepthMask(depthWriting);
	if (!blending)
		glDisable(GL_BLEND);
}

void ParticleSystem::bindPointData() {
	// Vertex buffer
	glGenBuffers(1, &vertexBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
	glBufferData(GL_ARRAY_BUFFER, maxParticleCount * sizeof(ParticleSystem::ParticlePosition), NULL, GL_DYNAMIC_DRAW);

	// Define vertex data layout
	glGenVertexArrays(1, &vertexAttribute);
	glBindVertexArray(vertexAttribute);
	glEnableVertexAttribArray(0);

	GLuint vertexPos = shaderProgram->attributeLocation("vertex_position");
	glVertexAttribPointer(vertexPos, 3, GL_FLOAT, GL_FALSE, sizeof(ParticleSystem::ParticlePosition), BUFFER_OFFSET(0));
}

void ParticleSystem::emitParticle() {
	if ((rand() % 1000 < chanceToEmit) && (particleCount < maxParticleCount)) {
		ParticlePosition newPosition;
		ParticleProperty newProperty;

		newPosition.worldPos = particleOrigin;
		newProperty.lifetime = 0.f - static_cast<float>(rand() % static_cast<int>(maxLifeTime * 2));
		newProperty.velocity.x = static_cast<float>(rand() % (2 * static_cast<int>(maxVelocity)) - static_cast<int>(maxVelocity));
		newProperty.velocity.y = static_cast<float>(rand() % (2 * static_cast<int>(maxVelocity)) - static_cast<int>(maxVelocity));
		newProperty.velocity.z = static_cast<float>(rand() % (2 * static_cast<int>(maxVelocity)) - static_cast<int>(maxVelocity));

		particlePositions.push_back(newPosition);
		particleProperties.push_back(newProperty);

		particleCount++;
	}
}<|endoftext|>


<commit_before>#include "stdafx.h"
#include "cartrige.h"

struct rom_header
{
	u8 start_vector[4];
	u8 nintendo_logo[48];
	u8 game_title[11];
	u8 manufacturer_code[4];
	u8 cgb_flag;
	u8 new_license_code[2];
	u8 sgb_flag;
	u8 cartrige_type;
	u8 rom_size;
	u8 ram_size;
	u8 destination_code;
	u8 old_license_code;
	u8 rom_version;
	u8 checksum;
	u8 global_checksum[2];
};

bool in_range(u32 value, u32 begin, u32 end)
{
	return (value >= begin) && (value <= end);
}

u32 get_ram_size(u8 val)
{
	assert(val < 6);

	static const u32 sizes[] = { 0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000 };

	return sizes[val];
}

Cartrige::~Cartrige()
{
	if (battery_ram)
	{
		std::ofstream ram_file(file_name + "_ram", std::ios::trunc | std::ios::binary);
		rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

		if (in_range(header->rom_version, 0x0F, 0x10))
			ram_file.write(reinterpret_cast<char*>(rtc_regs), 5);

		ram_file.write(reinterpret_cast<char*>(ram.get()), ram_size);
	}
}

void Cartrige::load_ram()
{
	rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	//MBC2 has always header->ram_size == 0, but it has 512 bytes actually!
	if (in_range(header->cartrige_type, 0x05, 0x06))
		ram_size = 512;

	else
		ram_size = get_ram_size(header->ram_size);

	ram = ram_size ? std::make_unique<u8[]>(ram_size) : nullptr;

	switch (header->cartrige_type)
	{
		case 0x03:
		case 0x06:
		case 0x09:
		case 0x0D:
		case 0x0F:
		case 0x10:
		case 0x13:
		case 0x1B:
		case 0x1E:
			battery_ram = true;
			break;

		default:
			battery_ram = false;
			break;
	}

	if (battery_ram)
	{
		std::ifstream ram_file(file_name + "_ram", std::ios::binary);

		if (ram_file.is_open())
		{
			//if this is mbc3 cart, we need to read additional time registers
			if (in_range(header->cartrige_type, 0x0F, 0x10))
				ram_file.read(reinterpret_cast<char*>(rtc_regs), 5);

			ram_file.read(reinterpret_cast<char*>(ram.get()), ram_size);
		}
	}
}

bool Cartrige::load_cartrige(const std::string& name)
{
	std::ifstream cart_file(name, std::ios::binary | std::ios::ate);

	if (!cart_file.is_open())
		return false;

	size_t size = cart_file.tellg();
	cart_file.seekg(0, std::ios_base::beg);

	rom = std::make_unique<u8[]>(size);
	cart_file.read(reinterpret_cast<char*>(rom.get()), size);

	file_name = name;
	load_ram();
	dispatch();

	return true;
}

IMemory* Cartrige::get_memory_controller() const
{
	return memory_interface.get();
}

IDmaMemory* Cartrige::get_dma_controller() const
{
	return dma_interface;
}

bool Cartrige::is_cgb_ready() const
{
	const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	return (header->cgb_flag == 0x80) || (header->cgb_flag == 0xC0);
}

void Cartrige::dispatch()
{
	rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);
	u8 type = header->cartrige_type;

	if (type == 0x00 || type == 0x08 || type == 0x09)
	{
		auto tmp = std::make_unique<NoMBC>(NoMBC(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x01, 0x03))
	{
		auto tmp = std::make_unique<MBC1>(MBC1(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x05, 0x06))
	{
		auto tmp = std::make_unique<MBC2>(MBC2(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x0F, 0x13))
	{
		auto tmp = std::make_unique<MBC3>(MBC3(rom.get(), ram.get(), (type <= 0x10 ? rtc_regs : nullptr)));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x1A, 0x1E))
	{
		auto tmp = std::make_unique<MBC5>(MBC5(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else
		memory_interface = nullptr;
}
<commit_msg>added sving rtc regs to file with time passing<commit_after>#include "stdafx.h"
#include "cartrige.h"

struct rom_header
{
	u8 start_vector[4];
	u8 nintendo_logo[48];
	u8 game_title[11];
	u8 manufacturer_code[4];
	u8 cgb_flag;
	u8 new_license_code[2];
	u8 sgb_flag;
	u8 cartrige_type;
	u8 rom_size;
	u8 ram_size;
	u8 destination_code;
	u8 old_license_code;
	u8 rom_version;
	u8 checksum;
	u8 global_checksum[2];
};

bool in_range(u32 value, u32 begin, u32 end)
{
	return (value >= begin) && (value <= end);
}

u32 get_ram_size(u8 val)
{
	assert(val < 6);

	static const u32 sizes[] = { 0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000 };

	return sizes[val];
}

Cartrige::~Cartrige()
{
	const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	if (battery_ram)
	{
		std::ofstream ram_file(file_name + "_ram", std::ios::trunc | std::ios::binary);
		ram_file.write(reinterpret_cast<char*>(ram.get()), ram_size);
	}

	if (in_range(header->rom_version, 0x0F, 0x10))
	{
		std::ofstream rtc_file(file_name + "_rtc", std::ios::trunc);

		memory_interface.reset(); //make sure that MBC3 update rtc_regs

		auto epoch = std::chrono::system_clock::now().time_since_epoch();
		auto cur_timestamp = std::chrono::duration_cast<std::chrono::seconds>(epoch);

		rtc_file << cur_timestamp.count();
		rtc_file.write(reinterpret_cast<char*>(rtc_regs), sizeof(u8) * 5);
	}
}

void Cartrige::load_ram()
{
	rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	//MBC2 has always header->ram_size == 0, but it has 512 bytes actually!
	if (in_range(header->cartrige_type, 0x05, 0x06))
		ram_size = 512;

	else
		ram_size = get_ram_size(header->ram_size);

	ram = ram_size ? std::make_unique<u8[]>(ram_size) : nullptr;

	switch (header->cartrige_type)
	{
		case 0x03:
		case 0x06:
		case 0x09:
		case 0x0D:
		case 0x0F:
		case 0x10:
		case 0x13:
		case 0x1B:
		case 0x1E:
			battery_ram = true;
			break;

		default:
			battery_ram = false;
			break;
	}

	if (battery_ram)
	{
		std::ifstream ram_file(file_name + "_ram", std::ios::binary);

		if (ram_file.is_open())
			ram_file.read(reinterpret_cast<char*>(ram.get()), ram_size);
	}

	if (in_range(header->cartrige_type, 0x0F, 0x10))
	{
		std::ifstream rtc_file(file_name + "_rtc");

		if (rtc_file.is_open())
		{
			i64 saved_timestamp;
			rtc_file >> saved_timestamp;
			rtc_file.read(reinterpret_cast<char*>(rtc_regs), sizeof(u8) * 5);

			auto epoch = std::chrono::system_clock::now().time_since_epoch();
			auto cur_timestamp = std::chrono::duration_cast<std::chrono::seconds>(epoch);
			auto delta = cur_timestamp.count() - saved_timestamp;

			if (delta <= 0 || !check_bit(rtc_regs[4], 6))
				return;

			auto ns = rtc_regs[0] + delta;
			auto nm = rtc_regs[1] + ns / 60;
			auto nh = rtc_regs[2] + nm / 60;
			auto nd = (((rtc_regs[4] & 1) << 8) | rtc_regs[3]) + nh / 24;

			rtc_regs[0] = ns % 60;
			rtc_regs[1] = nm % 60;
			rtc_regs[2] = nh % 24;
			rtc_regs[3] = (nd % 512) & 0xFF;
			rtc_regs[4] = change_bit(rtc_regs[4], (nd % 512) > 255, 0);
			rtc_regs[4] = change_bit(rtc_regs[4], nd > 511, 7);
		}
	}
}

bool Cartrige::load_cartrige(const std::string& name)
{
	std::ifstream cart_file(name, std::ios::binary | std::ios::ate);

	if (!cart_file.is_open())
		return false;

	size_t size = cart_file.tellg();
	cart_file.seekg(0, std::ios_base::beg);

	rom = std::make_unique<u8[]>(size);
	cart_file.read(reinterpret_cast<char*>(rom.get()), size);

	file_name = name;
	load_ram();
	dispatch();

	return true;
}

IMemory* Cartrige::get_memory_controller() const
{
	return memory_interface.get();
}

IDmaMemory* Cartrige::get_dma_controller() const
{
	return dma_interface;
}

bool Cartrige::is_cgb_ready() const
{
	const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	return (header->cgb_flag == 0x80) || (header->cgb_flag == 0xC0);
}

void Cartrige::dispatch()
{
	rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);
	u8 type = header->cartrige_type;

	if (type == 0x00 || type == 0x08 || type == 0x09)
	{
		auto tmp = std::make_unique<NoMBC>(NoMBC(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x01, 0x03))
	{
		auto tmp = std::make_unique<MBC1>(MBC1(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x05, 0x06))
	{
		auto tmp = std::make_unique<MBC2>(MBC2(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x0F, 0x13))
	{
		auto tmp = std::make_unique<MBC3>(MBC3(rom.get(), ram.get(), (type <= 0x10 ? rtc_regs : nullptr)));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x1A, 0x1E))
	{
		auto tmp = std::make_unique<MBC5>(MBC5(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else
		memory_interface = nullptr;
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2015  Martin Klapetek <mklapetek@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "carddav-plugin.h"
#include "carddav_p.h"
#include "syncer_p.h"

#include <KJob>
#include <KConfigCore/KSharedConfig>
#include <KConfigCore/KConfigGroup>

#include <Accounts/Service>
#include <Accounts/Manager>
#include <Accounts/Account>
#include <Accounts/AccountService>
#include <QTimer>

#include "getcredentialsjob.h"
#include "core.h"

class KAccountsCardDavPlugin::Private {
public:
    Private(KAccountsCardDavPlugin *qq) { q = qq; };

    KAccountsCardDavPlugin *q;
    KSharedConfig::Ptr config;
    QTimer *syncTimer;
};

//---------------------------------------------------------------------------------------

KAccountsCardDavPlugin::KAccountsCardDavPlugin(QObject *parent)
    : KAccountsDPlugin(parent),
      d(new Private(this))
{
    d->config = KSharedConfig::openConfig(QStringLiteral("kaccounts-carddavrc"));
    d->syncTimer = new QTimer(this);
    d->syncTimer->setInterval(1000 * 60 *30);

    connect(d->syncTimer, &QTimer::timeout, this, &KAccountsCardDavPlugin::syncAllAccounts);

    syncAllAccounts();
}

KAccountsCardDavPlugin::~KAccountsCardDavPlugin()
{
}

void KAccountsCardDavPlugin::syncAllAccounts()
{
    KConfigGroup global = d->config->group("Global");
    QList<quint32> syncedAccounts = global.readEntry("syncedAccounts", QList<quint32>());

    Q_FOREACH (const quint32 accountId, syncedAccounts) {
        KConfigGroup currentAccount = d->config->group("account" + accountId);
        QDateTime lastSync = QDateTime::fromString(currentAccount.readEntry("lastSync", QString()), Qt::ISODate);
        if (QDateTime::currentDateTime() > lastSync) {
            getCredentials(accountId);
        }
    }
}

void KAccountsCardDavPlugin::onAccountCreated(const Accounts::AccountId accountId, const Accounts::ServiceList &serviceList)
{
    Accounts::Account *account = KAccounts::accountsManager()->account(accountId);

    if (!account) {
        qWarning() << "Invalid account for id" << accountId;
        return;
    }

    Q_FOREACH (const Accounts::Service &service, serviceList) {
        account->selectService(service);
        if (service.serviceType() == QLatin1String("dav-contacts") && account->isEnabled()) {
            qDebug() << "Starting carddav contacts import for account" << accountId << "and service" << service.serviceType();
            getCredentials(accountId);
        }
    }
}

void KAccountsCardDavPlugin::onAccountRemoved(const Accounts::AccountId accountId)
{
}

void KAccountsCardDavPlugin::onServiceEnabled(const Accounts::AccountId accountId, const Accounts::Service &service)
{
}

void KAccountsCardDavPlugin::onServiceDisabled(const Accounts::AccountId accountId, const Accounts::Service &service)
{
}

void KAccountsCardDavPlugin::getCredentials(const Accounts::AccountId accountId)
{
    GetCredentialsJob *credentialsJob = new GetCredentialsJob(accountId, this);
    connect(credentialsJob, &GetCredentialsJob::finished, this, &KAccountsCardDavPlugin::importContacts);
    credentialsJob->start();
}

void KAccountsCardDavPlugin::importContacts(KJob *job)
{
    GetCredentialsJob *credentialsJob = qobject_cast<GetCredentialsJob*>(job);
    job->deleteLater();

    if (!credentialsJob) {
        return;
    }

    const QVariantMap &data = credentialsJob->credentialsData();
    Accounts::Account *account = KAccounts::accountsManager()->account(credentialsJob->accountId());

    if (!account) {
        return;
    }

    QUrl carddavUrl = account->value("carddavUrl").toUrl();

    qDebug() << "Using: host:" << carddavUrl.host() << "path:" << carddavUrl.path();

    Syncer *s = new Syncer(0);
    s->setProperty("accountId", credentialsJob->accountId());

    const QString &userName = data.value("AccountUsername").toString();

    CardDav *m_cardDav = new CardDav(s,
                                     carddavUrl.host(),
                                     carddavUrl.path(),
                                     userName,
                                     data.value("Secret").toString());

    QObject::connect(m_cardDav, SIGNAL(remoteChanges(QList<KContacts::Addressee>,QList<KContacts::Addressee>,QList<KContacts::Addressee>)),
                     s, SLOT(continueSync(QList<KContacts::Addressee>,QList<KContacts::Addressee>,QList<KContacts::Addressee>)));
    QObject::connect(m_cardDav, SIGNAL(upsyncCompleted()),
                     s, SLOT(syncFinished()));
    QObject::connect(m_cardDav, SIGNAL(error(int)),
                     s, SLOT(cardDavError(int)));

    QObject::connect(s, &Syncer::syncSucceeded, [=] {
        d->syncTimer->start();
        quint32 accountId = s->property("accountId").toUInt();

        KConfigGroup global = d->config->group("Global");
        QList<quint32> syncedAccounts = global.readEntry("syncedAccounts", QList<quint32>());
        if (!syncedAccounts.contains(accountId)) {
            syncedAccounts.append(accountId);
        }
        global.writeEntry("syncedAccounts", syncedAccounts);
        global.sync();

        KConfigGroup currentAccount = d->config->group("account" + accountId);
        currentAccount.writeEntry("lastSync", QDateTime::currentDateTime().toString(Qt::ISODate));
        currentAccount.sync();
    });

    m_cardDav->determineRemoteAMR();
}
<commit_msg>[carddav] Make extra sure the carddav accounts are synced<commit_after>/*
    Copyright (C) 2015  Martin Klapetek <mklapetek@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "carddav-plugin.h"
#include "carddav_p.h"
#include "syncer_p.h"

#include <KJob>
#include <KConfigCore/KSharedConfig>
#include <KConfigCore/KConfigGroup>

#include <Accounts/Service>
#include <Accounts/Manager>
#include <Accounts/Account>
#include <Accounts/AccountService>
#include <QTimer>

#include "getcredentialsjob.h"
#include "core.h"

class KAccountsCardDavPlugin::Private {
public:
    Private(KAccountsCardDavPlugin *qq) { q = qq; };

    KAccountsCardDavPlugin *q;
    KSharedConfig::Ptr config;
    QTimer *syncTimer;
};

//---------------------------------------------------------------------------------------

KAccountsCardDavPlugin::KAccountsCardDavPlugin(QObject *parent)
    : KAccountsDPlugin(parent),
      d(new Private(this))
{
    d->config = KSharedConfig::openConfig(QStringLiteral("kaccounts-carddavrc"));
    d->syncTimer = new QTimer(this);
    d->syncTimer->setInterval(1000 * 60 *30);

    connect(d->syncTimer, &QTimer::timeout, this, &KAccountsCardDavPlugin::syncAllAccounts);

    syncAllAccounts();
}

KAccountsCardDavPlugin::~KAccountsCardDavPlugin()
{
}

void KAccountsCardDavPlugin::syncAllAccounts()
{
    KConfigGroup global = d->config->group("Global");
    QList<quint32> syncedAccounts = global.readEntry("syncedAccounts", QList<quint32>());

    if (syncedAccounts.isEmpty()) {
        Accounts::AccountIdList accounts = KAccounts::accountsManager()->accountListEnabled(QStringLiteral("dav-contacts"));
        syncedAccounts << accounts;
    }

    Q_FOREACH (const quint32 accountId, syncedAccounts) {
        KConfigGroup currentAccount = d->config->group("account" + accountId);
        QDateTime lastSync = QDateTime::fromString(currentAccount.readEntry("lastSync", QString()), Qt::ISODate);
        if (QDateTime::currentDateTime() > lastSync) {
            getCredentials(accountId);
        }
    }
}

void KAccountsCardDavPlugin::onAccountCreated(const Accounts::AccountId accountId, const Accounts::ServiceList &serviceList)
{
    Accounts::Account *account = KAccounts::accountsManager()->account(accountId);

    if (!account) {
        qWarning() << "Invalid account for id" << accountId;
        return;
    }

    Q_FOREACH (const Accounts::Service &service, serviceList) {
        account->selectService(service);
        if (service.serviceType() == QLatin1String("dav-contacts") && account->isEnabled()) {
            qDebug() << "Starting carddav contacts import for account" << accountId << "and service" << service.serviceType();
            getCredentials(accountId);
        }
    }
}

void KAccountsCardDavPlugin::onAccountRemoved(const Accounts::AccountId accountId)
{
}

void KAccountsCardDavPlugin::onServiceEnabled(const Accounts::AccountId accountId, const Accounts::Service &service)
{
}

void KAccountsCardDavPlugin::onServiceDisabled(const Accounts::AccountId accountId, const Accounts::Service &service)
{
}

void KAccountsCardDavPlugin::getCredentials(const Accounts::AccountId accountId)
{
    GetCredentialsJob *credentialsJob = new GetCredentialsJob(accountId, this);
    connect(credentialsJob, &GetCredentialsJob::finished, this, &KAccountsCardDavPlugin::importContacts);
    credentialsJob->start();
}

void KAccountsCardDavPlugin::importContacts(KJob *job)
{
    GetCredentialsJob *credentialsJob = qobject_cast<GetCredentialsJob*>(job);
    job->deleteLater();

    if (!credentialsJob) {
        return;
    }

    const QVariantMap &data = credentialsJob->credentialsData();
    Accounts::Account *account = KAccounts::accountsManager()->account(credentialsJob->accountId());

    if (!account) {
        return;
    }

    QUrl carddavUrl = account->value("carddavUrl").toUrl();

    qDebug() << "Using: host:" << carddavUrl.host() << "path:" << carddavUrl.path();

    Syncer *s = new Syncer(0);
    s->setProperty("accountId", credentialsJob->accountId());

    const QString &userName = data.value("AccountUsername").toString();

    CardDav *m_cardDav = new CardDav(s,
                                     carddavUrl.host(),
                                     carddavUrl.path(),
                                     userName,
                                     data.value("Secret").toString());

    QObject::connect(m_cardDav, SIGNAL(remoteChanges(QList<KContacts::Addressee>,QList<KContacts::Addressee>,QList<KContacts::Addressee>)),
                     s, SLOT(continueSync(QList<KContacts::Addressee>,QList<KContacts::Addressee>,QList<KContacts::Addressee>)));
    QObject::connect(m_cardDav, SIGNAL(upsyncCompleted()),
                     s, SLOT(syncFinished()));
    QObject::connect(m_cardDav, SIGNAL(error(int)),
                     s, SLOT(cardDavError(int)));

    QObject::connect(s, &Syncer::syncSucceeded, [=] {
        d->syncTimer->start();
        quint32 accountId = s->property("accountId").toUInt();

        KConfigGroup global = d->config->group("Global");
        QList<quint32> syncedAccounts = global.readEntry("syncedAccounts", QList<quint32>());
        if (!syncedAccounts.contains(accountId)) {
            syncedAccounts.append(accountId);
        }
        global.writeEntry("syncedAccounts", syncedAccounts);
        global.sync();

        KConfigGroup currentAccount = d->config->group("account" + accountId);
        currentAccount.writeEntry("lastSync", QDateTime::currentDateTime().toString(Qt::ISODate));
        currentAccount.sync();
    });

    m_cardDav->determineRemoteAMR();
}
<|endoftext|>


<commit_before>#include <imap.hpp>

#include "helpers.hpp"

#include <vector>
#include <list>
#include <string>
#include <iterator>

#include "catch.hpp"

using iter::starmap;

namespace {
    long f(long d, int i) {
        return d * i;
    }

    std::string g(const std::string& s, int i, char c) {
        std::stringstream ss;
        ss << s << ' ' << i << ' ' << c;
        return ss.str();
    }

    struct Callable {
        int operator()(int a, int b, int c) {
            return a + b + c;
        }

        int operator()(int a) {
            return a;
        }
    };
}

TEST_CASE("starmap: works with function pointer and lambda", "[starmap]") {
    using Vec = const std::vector<int>;
    const std::vector<std::pair<double, int>> v1 =
        {{1l, 2}, {3l, 11}, {6l, 7}};
    Vec vc = {2l, 33l, 42l};

    SECTION("with function") {
        auto sm = starmap(f, v1);
        Vec v(std::begin(sm), std::end(sm));
        REQUIRE( v == vc );
    }

    SECTION("with lambda") {
        auto sm = starmap([](long a, int b) { return a * b; }, v1);
        Vec v(std::begin(sm), std::end(sm));
        REQUIRE( v == vc );
    }
}

TEST_CASE("starmap: list of tuples", "[starmap]") {
    using Vec = const std::vector<std::string>;
    using T = std::tuple<std::string, int, double>;
    std::list<T> li =
        {T{"hey", 42, 'a'}, T{"there", 3, 'b'}, T{"yall", 5, 'c'}};

    auto sm = starmap(g, li);
    Vec v(std::begin(sm), std::end(sm));
    Vec vc = {"hey 42 a", "there 3 b", "yall 5 c"};

    REQUIRE( v == vc );
}

TEST_CASE("starmap: tuple of tuples", "[starmap]") {
    using Vec = const std::vector<int>;
    auto tup = std::make_tuple(std::make_tuple(10, 19, 60),std::make_tuple(7));
    auto sm = starmap(Callable{}, tup);
    Vec v(std::begin(sm), std::end(sm));
    Vec vc = {89, 7};

    REQUIRE( v == vc );
}

TEST_CASE("starmap: tuple of pairs", "[starmap]") {
    using Vec = const std::vector<int>;
    auto p = std::make_pair(std::array<int, 3>{{15, 100, 2000}},
                            std::make_tuple(16));
    Callable c;
    auto sm = starmap(c, p);

    Vec v(std::begin(sm), std::end(sm));
    Vec vc = {2115, 16};

    REQUIRE( v == vc );
}
<commit_msg>tests that starmap moves and binds correctly<commit_after>#include <imap.hpp>

#include "helpers.hpp"

#include <vector>
#include <list>
#include <string>
#include <iterator>

#include "catch.hpp"

using iter::starmap;

namespace {
    long f(long d, int i) {
        return d * i;
    }

    std::string g(const std::string& s, int i, char c) {
        std::stringstream ss;
        ss << s << ' ' << i << ' ' << c;
        return ss.str();
    }

    struct Callable {
        int operator()(int a, int b, int c) {
            return a + b + c;
        }

        int operator()(int a) {
            return a;
        }
    };
}

TEST_CASE("starmap: works with function pointer and lambda", "[starmap]") {
    using Vec = const std::vector<int>;
    const std::vector<std::pair<double, int>> v1 =
        {{1l, 2}, {3l, 11}, {6l, 7}};
    Vec vc = {2l, 33l, 42l};

    SECTION("with function") {
        auto sm = starmap(f, v1);
        Vec v(std::begin(sm), std::end(sm));
        REQUIRE( v == vc );
    }

    SECTION("with lambda") {
        auto sm = starmap([](long a, int b) { return a * b; }, v1);
        Vec v(std::begin(sm), std::end(sm));
        REQUIRE( v == vc );
    }
}

TEST_CASE("starmap: list of tuples", "[starmap]") {
    using Vec = const std::vector<std::string>;
    using T = std::tuple<std::string, int, double>;
    std::list<T> li =
        {T{"hey", 42, 'a'}, T{"there", 3, 'b'}, T{"yall", 5, 'c'}};

    auto sm = starmap(g, li);
    Vec v(std::begin(sm), std::end(sm));
    Vec vc = {"hey 42 a", "there 3 b", "yall 5 c"};

    REQUIRE( v == vc );
}

TEST_CASE("starmap: tuple of tuples", "[starmap]") {
    using Vec = const std::vector<int>;
    auto tup = std::make_tuple(std::make_tuple(10, 19, 60),std::make_tuple(7));
    auto sm = starmap(Callable{}, tup);
    Vec v(std::begin(sm), std::end(sm));
    Vec vc = {89, 7};

    REQUIRE( v == vc );
}

TEST_CASE("starmap: tuple of pairs", "[starmap]") {
    using Vec = const std::vector<int>;
    auto p = std::make_pair(std::array<int, 3>{{15, 100, 2000}},
                            std::make_tuple(16));
    Callable c;
    auto sm = starmap(c, p);

    Vec v(std::begin(sm), std::end(sm));
    Vec vc = {2115, 16};

    REQUIRE( v == vc );
}

TEST_CASE("starmap: moves rvalues, binds to lvalues", "[starmap]") {
    itertest::BasicIterable<std::tuple<int>> bi{};
    starmap(Callable{}, bi);
    REQUIRE_FALSE( bi.was_moved_from() );
    starmap(Callable{}, std::move(bi));
    REQUIRE( bi.was_moved_from() );
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 PaddlePaddle 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 "paddle/fluid/framework/ir/conv_bias_mkldnn_fuse_pass.h"
#include <functional>
#include <string>
#include <vector>
#include "paddle/fluid/framework/lod_tensor.h"
#include "paddle/fluid/platform/enforce.h"

namespace paddle {
namespace framework {
namespace ir {

template <typename BinaryOperation>
LoDTensor tensor_apply_eltwise(const LoDTensor& vec_a, const LoDTensor& vec_b,
                               BinaryOperation f) {
  PADDLE_ENFORCE_EQ(vec_a.dims(), vec_b.dims());
  LoDTensor vec_y;
  vec_y.Resize(vec_a.dims());
  const float* a = vec_a.data<float>();
  const float* b = vec_b.data<float>();
  float* y = vec_y.mutable_data<float>(platform::CPUPlace());
  for (int i = 0; i < vec_a.numel(); i++) {
    y[i] = f(a[i], b[i]);
  }
  return vec_y;
}

std::unique_ptr<ir::Graph> ConvBiasFusePass::ApplyImpl(
    std::unique_ptr<ir::Graph> graph) const {
  PADDLE_ENFORCE(graph.get());
  FusePassBase::Init(name_scope_, graph.get());

  auto* scope = param_scope();
  PADDLE_ENFORCE(scope);

  GraphPatternDetector gpd;
  auto* conv_input =
      gpd.mutable_pattern()
          ->NewNode(patterns::PDNodeName(name_scope_, "conv_input"))
          ->AsInput()
          ->assert_is_op_input("conv2d", "Input");
  patterns::ConvBias conv_bias_pattern(gpd.mutable_pattern(), name_scope_);
  conv_bias_pattern(conv_input);
  int found_conv_bias_count = 0;
  auto handler = [&](const GraphPatternDetector::subgraph_t& subgraph,
                     Graph* g) {
    VLOG(4) << "handle ConvBias fuse";
    GET_IR_NODE_FROM_SUBGRAPH(conv_weight, conv_weight,
                              conv_bias_pattern);                      // Filter
    GET_IR_NODE_FROM_SUBGRAPH(conv_out, conv_out, conv_bias_pattern);  // tmp
    GET_IR_NODE_FROM_SUBGRAPH(conv, conv, conv_bias_pattern);  // CONV op
    // bias
    GET_IR_NODE_FROM_SUBGRAPH(eltwise_bias, eltwise_bias, conv_bias_pattern);
    // output
    GET_IR_NODE_FROM_SUBGRAPH(eltwise_out, eltwise_out, conv_bias_pattern);
    // elementwise_add op
    GET_IR_NODE_FROM_SUBGRAPH(eltwise, eltwise, conv_bias_pattern);

    PADDLE_ENFORCE(subgraph.count(conv_input));

    auto* eltwise_bias_tensor =
        scope->FindVar(eltwise_bias->Name())->GetMutable<LoDTensor>();

    auto input_names = conv->Op()->InputNames();
    bool has_bias = std::find(input_names.begin(), input_names.end(), "Bias") !=
                    input_names.end();
    if (has_bias && conv->Op()->Input("Bias").size() > 0) {
      auto conv_bias_names = conv->Op()->Input("Bias");
      // add eltwise bias to existing conv bias
      PADDLE_ENFORCE_EQ(conv_bias_names.size(), 1);
      auto* conv_bias_var = scope->FindVar(conv_bias_names[0]);
      auto* conv_bias_tensor = conv_bias_var->GetMutable<LoDTensor>();
      PADDLE_ENFORCE_EQ(conv_bias_tensor->dims(), eltwise_bias_tensor->dims());
      *conv_bias_tensor = tensor_apply_eltwise(
          *conv_bias_tensor, *eltwise_bias_tensor, std::plus<float>());

      conv->Op()->SetOutput("Output",
                            std::vector<std::string>({eltwise_out->Name()}));

      GraphSafeRemoveNodes(graph.get(), {eltwise, conv_out});

      IR_NODE_LINK_TO(conv, eltwise_out);
    } else {
      // take eltwise bias as conv bias
      OpDesc desc;

      desc.SetInput(
          "Input", std::vector<std::string>({subgraph.at(conv_input)->Name()}));
      desc.SetInput("Filter", std::vector<std::string>({conv_weight->Name()}));
      desc.SetInput("Bias", std::vector<std::string>({eltwise_bias->Name()}));
      desc.SetOutput("Output", std::vector<std::string>({eltwise_out->Name()}));
      desc.SetType("conv2d");

      for (auto& attr : conv->Op()->GetAttrMap()) {
        desc.SetAttr(attr.first, attr.second);
      }
      auto conv_bias_node = g->CreateOpNode(&desc);

      IR_NODE_LINK_TO(subgraph.at(conv_input), conv_bias_node);
      IR_NODE_LINK_TO(conv_weight, conv_bias_node);
      IR_NODE_LINK_TO(eltwise_bias, conv_bias_node);
      IR_NODE_LINK_TO(conv_bias_node, eltwise_out);

      GraphSafeRemoveNodes(graph.get(), {conv, eltwise, conv_out});
    }

    found_conv_bias_count++;
  };
  gpd(graph.get(), handler);
  AddStatis(found_conv_bias_count);
  return graph;
}
}  // namespace ir
}  // namespace framework
}  // namespace paddle
REGISTER_PASS(conv_bias_mkldnn_fuse_pass,
              paddle::framework::ir::ConvBiasFusePass);
<commit_msg>Adjust Conv+bias to placement pass<commit_after>// Copyright (c) 2018 PaddlePaddle 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 "paddle/fluid/framework/ir/conv_bias_mkldnn_fuse_pass.h"
#include <functional>
#include <string>
#include <vector>
#include "paddle/fluid/framework/lod_tensor.h"
#include "paddle/fluid/platform/enforce.h"

namespace paddle {
namespace framework {
namespace ir {

template <typename BinaryOperation>
LoDTensor tensor_apply_eltwise(const LoDTensor& vec_a, const LoDTensor& vec_b,
                               BinaryOperation f) {
  PADDLE_ENFORCE_EQ(vec_a.dims(), vec_b.dims());
  LoDTensor vec_y;
  vec_y.Resize(vec_a.dims());
  const float* a = vec_a.data<float>();
  const float* b = vec_b.data<float>();
  float* y = vec_y.mutable_data<float>(platform::CPUPlace());
  for (int i = 0; i < vec_a.numel(); i++) {
    y[i] = f(a[i], b[i]);
  }
  return vec_y;
}

std::unique_ptr<ir::Graph> ConvBiasFusePass::ApplyImpl(
    std::unique_ptr<ir::Graph> graph) const {
  PADDLE_ENFORCE(graph.get());
  FusePassBase::Init(name_scope_, graph.get());

  auto* scope = param_scope();
  PADDLE_ENFORCE(scope);

  GraphPatternDetector gpd;
  auto* conv_input =
      gpd.mutable_pattern()
          ->NewNode(patterns::PDNodeName(name_scope_, "conv_input"))
          ->AsInput()
          ->assert_is_op_input("conv2d", "Input");
  patterns::ConvBias conv_bias_pattern(gpd.mutable_pattern(), name_scope_);
  conv_bias_pattern(conv_input);
  int found_conv_bias_count = 0;
  auto handler = [&](const GraphPatternDetector::subgraph_t& subgraph,
                     Graph* g) {
    VLOG(4) << "handle ConvBias fuse";
    GET_IR_NODE_FROM_SUBGRAPH(conv_weight, conv_weight,
                              conv_bias_pattern);                      // Filter
    GET_IR_NODE_FROM_SUBGRAPH(conv_out, conv_out, conv_bias_pattern);  // tmp
    GET_IR_NODE_FROM_SUBGRAPH(conv, conv, conv_bias_pattern);  // CONV op
    // bias
    GET_IR_NODE_FROM_SUBGRAPH(eltwise_bias, eltwise_bias, conv_bias_pattern);
    // output
    GET_IR_NODE_FROM_SUBGRAPH(eltwise_out, eltwise_out, conv_bias_pattern);
    // elementwise_add op
    GET_IR_NODE_FROM_SUBGRAPH(eltwise, eltwise, conv_bias_pattern);

    PADDLE_ENFORCE(subgraph.count(conv_input));

    // check if fuse can be done and if MKL-DNN should be used
    FuseOptions fuse_option = FindFuseOption(*conv, *eltwise);
    if (fuse_option == DO_NOT_FUSE || fuse_option == FUSE_NATIVE) {
      VLOG(3) << "do not perform conv+bias fuse";
      return;
    }

    auto* eltwise_bias_tensor =
        scope->FindVar(eltwise_bias->Name())->GetMutable<LoDTensor>();

    auto input_names = conv->Op()->InputNames();
    bool has_bias = std::find(input_names.begin(), input_names.end(), "Bias") !=
                    input_names.end();
    if (has_bias && conv->Op()->Input("Bias").size() > 0) {
      auto conv_bias_names = conv->Op()->Input("Bias");
      // add eltwise bias to existing conv bias
      PADDLE_ENFORCE_EQ(conv_bias_names.size(), 1);
      auto* conv_bias_var = scope->FindVar(conv_bias_names[0]);
      auto* conv_bias_tensor = conv_bias_var->GetMutable<LoDTensor>();
      PADDLE_ENFORCE_EQ(conv_bias_tensor->dims(), eltwise_bias_tensor->dims());
      *conv_bias_tensor = tensor_apply_eltwise(
          *conv_bias_tensor, *eltwise_bias_tensor, std::plus<float>());

      conv->Op()->SetOutput("Output",
                            std::vector<std::string>({eltwise_out->Name()}));

      GraphSafeRemoveNodes(graph.get(), {eltwise, conv_out});

      IR_NODE_LINK_TO(conv, eltwise_out);
    } else {
      // take eltwise bias as conv bias
      OpDesc desc;

      desc.SetInput(
          "Input", std::vector<std::string>({subgraph.at(conv_input)->Name()}));
      desc.SetInput("Filter", std::vector<std::string>({conv_weight->Name()}));
      desc.SetInput("Bias", std::vector<std::string>({eltwise_bias->Name()}));
      desc.SetOutput("Output", std::vector<std::string>({eltwise_out->Name()}));
      desc.SetType("conv2d");

      for (auto& attr : conv->Op()->GetAttrMap()) {
        desc.SetAttr(attr.first, attr.second);
      }
      auto conv_bias_node = g->CreateOpNode(&desc);

      IR_NODE_LINK_TO(subgraph.at(conv_input), conv_bias_node);
      IR_NODE_LINK_TO(conv_weight, conv_bias_node);
      IR_NODE_LINK_TO(eltwise_bias, conv_bias_node);
      IR_NODE_LINK_TO(conv_bias_node, eltwise_out);

      GraphSafeRemoveNodes(graph.get(), {conv, eltwise, conv_out});
    }

    found_conv_bias_count++;
  };
  gpd(graph.get(), handler);
  AddStatis(found_conv_bias_count);
  return graph;
}
}  // namespace ir
}  // namespace framework
}  // namespace paddle
REGISTER_PASS(conv_bias_mkldnn_fuse_pass,
              paddle::framework::ir::ConvBiasFusePass);
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle 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 "paddle/fluid/operators/sequence_ops/sequence_pool_op.h"
#include <memory>
#include <string>

namespace paddle {
namespace operators {

class SequencePoolOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE_EQ(ctx->HasInput("X"), true,
                      "Input(X) of SequencePoolOp should not be null.");
    PADDLE_ENFORCE_EQ(ctx->HasOutput("Out"), true,
                      "Output(Out) of SequencePoolOp should not be null.");

    if (!ctx->IsRuntime()) {
      // Check the lod_level for compile-time.
      PADDLE_ENFORCE_GT(
          ctx->GetLoDLevel("X"), 0,
          "The LoD level Input(X) of sequence_pool should be larger than 0.");
    }

    ctx->SetOutputDim("Out", ctx->GetInputDim("X"));
    if (ctx->Attrs().Get<std::string>("pooltype") == "MAX") {
      PADDLE_ENFORCE_EQ(
          ctx->HasOutput("MaxIndex"), true,
          "Output(MaxIndex) of SequencePoolOp should not be null.");
      ctx->SetOutputDim("MaxIndex", ctx->GetInputDim("X"));
    }
  }
};

class SequencePoolOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("X", "(LoDTensor) The variable-length input of SequencePoolOp");
    AddOutput("Out",
              "(Tensor) The output of SequencePoolOp does not contain LoD "
              "infomation.");
    AddOutput("MaxIndex",
              "(Tensor<int>) This tensor is used for the sequence max-pooling "
              "to record the max indexes.")
        .AsIntermediate();
    AddAttr<bool>("is_test",
                  "(bool, default false) Set to true for inference only, false "
                  "for training. Some layers may run faster when this is true.")
        .SetDefault(false);
    AddAttr<std::string>(
        "pooltype",
        "(string, default 'AVERAGE') the pooling pooltype of SequencePoolOp.")
        .SetDefault("AVERAGE")
        .InEnum({"AVERAGE", "SUM", "SQRT", "LAST", "FIRST", "MAX"});
    AddAttr<float>("pad_value",
                   "(float, default 0.0) The value to pad for empty sequence.")
        .SetDefault(0.0);
    AddComment(R"DOC(
Sequence Pool Operator.

The SequencePoolOp pools features of all time-steps of each instance.
It supports six pooling types:
1. AVERAGE: $$Out[i] = \frac{\sum_i X_i}{N}$$
2. SUM:     $$Out[i] = \sum_jX_{ij}$$
3. SQRT:    $$Out[i] = \frac{\sum_jX_{ij}}{\sqrt{len(X_i)}}$$
4. LAST:    Out[i] = last instance in i-th sequence X[i]
5. FIRST:   Out[i] = first instance in i-th sequence X[i]
6. MAX:     $$Out[i] = max(X_i)$$

and for the empty sequence Out[i] = attr(pad_value).

The following example explains how this works:
For a mini-batch of 3 variable-length sentences,
containing 2, 3, and 2 time-steps:

Assume X is a [7,M,N] LoDTensor, and X->lod()[0] = [0, 2, 5, 7], 7=2+3+2.
Besides, for the sake of simplicity, we assume M=1 and N=1,
and the value of X = [[1, 3], [2, 4, 6], [5, 1]].

Thus, Out is a [3,1,1] Tensor without LoD infomation.
And for different pooltype, the value of Out is as follows:

- AVERAGE: [2, 4, 3], where 2=(1+3)/2, 4=(2+4+6)/3, 3=(5+1)/2
- SUM: [4, 12, 6], where 4=1+3, 12=2+4+6, 6=5+1
- SQRT: [2.82, 6.93, 4.24], where 2.82=(1+3)/sqrt(2),
           6.93=(2+4+6)/sqrt(3), 4.24=(5+1)/sqrt(2)
- MAX: [3, 6, 5], where 3=max(1,3), 6=max(2,4,6), 5=max(5,1)
- LAST: [3, 6, 1], where 3=last(1,3), 6=last(2,4,6), 1=last(5,1)
- FIRST: [1, 2, 5], where 1=first(1,3), 2=first(2,4,6), 5=first(5,1)

    )DOC");
  }
};

class SequencePoolGradOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE_EQ(ctx->HasInput(framework::GradVarName("Out")), true,
                      "Gradient of Out should not be null.");
    PADDLE_ENFORCE_EQ(ctx->HasInput("X"), true,
                      "The input X should not be null.");
    auto og_dims = ctx->GetInputDim(framework::GradVarName("Out"));
    auto x_dims = ctx->GetInputDim("X");
    PADDLE_ENFORCE_EQ(og_dims.size(), x_dims.size(),
                      "The rank of output grad must equal to Input(X).");
    for (int64_t i = 1; i < og_dims.size(); ++i) {
      PADDLE_ENFORCE_EQ(og_dims[i], x_dims[i], "The dimension mismatch.");
    }

    ctx->ShareDim("X", /*->*/ framework::GradVarName("X"));
    ctx->ShareLoD("X", /*->*/ framework::GradVarName("X"));
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    return framework::OpKernelType(OperatorWithKernel::IndicateVarDataType(
                                       ctx, framework::GradVarName("Out")),
                                   ctx.device_context());
  }
};

template <typename T>
class SequencePoolGradOpMaker : public framework::SingleGradOpMaker<T> {
 public:
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;

 protected:
  std::unique_ptr<T> Apply() const override {
    auto* op_desc_ptr = new T();
    op_desc_ptr->SetType("sequence_pool_grad");
    op_desc_ptr->SetInput("X", this->Input("X"));
    if (boost::get<std::string>(this->GetAttr("pooltype")) == "MAX") {
      op_desc_ptr->SetInput("MaxIndex", this->Output("MaxIndex"));
    }
    op_desc_ptr->SetInput(framework::GradVarName("Out"),
                          this->OutputGrad("Out"));
    op_desc_ptr->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
    op_desc_ptr->SetAttrMap(this->Attrs());
    return std::unique_ptr<T>(op_desc_ptr);
  }
};

DECLARE_NO_NEED_BUFFER_VARS_INFERENCE(
    SequencePoolGradOpNoNeedBufferVarsInference, "X");

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OPERATOR(sequence_pool, ops::SequencePoolOp, ops::SequencePoolOpMaker,
                  ops::SequencePoolGradOpMaker<paddle::framework::OpDesc>,
                  ops::SequencePoolGradOpMaker<paddle::imperative::OpBase>);
REGISTER_OPERATOR(sequence_pool_grad, ops::SequencePoolGradOp,
                  ops::SequencePoolGradOpNoNeedBufferVarsInference);
REGISTER_OP_CPU_KERNEL(
    sequence_pool,
    ops::SequencePoolKernel<paddle::platform::CPUDeviceContext, float>);
REGISTER_OP_CPU_KERNEL(
    sequence_pool_grad,
    ops::SequencePoolGradKernel<paddle::platform::CPUDeviceContext, float>);
<commit_msg>Set lod_level of Out in compile time of sequence_pool_op (#21604)<commit_after>/* Copyright (c) 2016 PaddlePaddle 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 "paddle/fluid/operators/sequence_ops/sequence_pool_op.h"
#include <memory>
#include <string>

namespace paddle {
namespace operators {

class SequencePoolOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE_EQ(ctx->HasInput("X"), true,
                      "Input(X) of SequencePoolOp should not be null.");
    PADDLE_ENFORCE_EQ(ctx->HasOutput("Out"), true,
                      "Output(Out) of SequencePoolOp should not be null.");

    if (!ctx->IsRuntime()) {
      // Check the lod_level for compile-time.
      auto in_lod_level = ctx->GetLoDLevel("X");
      PADDLE_ENFORCE_GT(
          in_lod_level, 0,
          "The LoD level Input(X) of sequence_pool should be larger than 0.");
      ctx->SetLoDLevel("Out", in_lod_level - 1);
    }

    ctx->SetOutputDim("Out", ctx->GetInputDim("X"));
    if (ctx->Attrs().Get<std::string>("pooltype") == "MAX") {
      PADDLE_ENFORCE_EQ(
          ctx->HasOutput("MaxIndex"), true,
          "Output(MaxIndex) of SequencePoolOp should not be null.");
      ctx->SetOutputDim("MaxIndex", ctx->GetInputDim("X"));
    }
  }
};

class SequencePoolOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  void Make() override {
    AddInput("X", "(LoDTensor) The variable-length input of SequencePoolOp");
    AddOutput("Out",
              "(Tensor) The output of SequencePoolOp does not contain LoD "
              "infomation.");
    AddOutput("MaxIndex",
              "(Tensor<int>) This tensor is used for the sequence max-pooling "
              "to record the max indexes.")
        .AsIntermediate();
    AddAttr<bool>("is_test",
                  "(bool, default false) Set to true for inference only, false "
                  "for training. Some layers may run faster when this is true.")
        .SetDefault(false);
    AddAttr<std::string>(
        "pooltype",
        "(string, default 'AVERAGE') the pooling pooltype of SequencePoolOp.")
        .SetDefault("AVERAGE")
        .InEnum({"AVERAGE", "SUM", "SQRT", "LAST", "FIRST", "MAX"});
    AddAttr<float>("pad_value",
                   "(float, default 0.0) The value to pad for empty sequence.")
        .SetDefault(0.0);
    AddComment(R"DOC(
Sequence Pool Operator.

The SequencePoolOp pools features of all time-steps of each instance.
It supports six pooling types:
1. AVERAGE: $$Out[i] = \frac{\sum_i X_i}{N}$$
2. SUM:     $$Out[i] = \sum_jX_{ij}$$
3. SQRT:    $$Out[i] = \frac{\sum_jX_{ij}}{\sqrt{len(X_i)}}$$
4. LAST:    Out[i] = last instance in i-th sequence X[i]
5. FIRST:   Out[i] = first instance in i-th sequence X[i]
6. MAX:     $$Out[i] = max(X_i)$$

and for the empty sequence Out[i] = attr(pad_value).

The following example explains how this works:
For a mini-batch of 3 variable-length sentences,
containing 2, 3, and 2 time-steps:

Assume X is a [7,M,N] LoDTensor, and X->lod()[0] = [0, 2, 5, 7], 7=2+3+2.
Besides, for the sake of simplicity, we assume M=1 and N=1,
and the value of X = [[1, 3], [2, 4, 6], [5, 1]].

Thus, Out is a [3,1,1] Tensor without LoD infomation.
And for different pooltype, the value of Out is as follows:

- AVERAGE: [2, 4, 3], where 2=(1+3)/2, 4=(2+4+6)/3, 3=(5+1)/2
- SUM: [4, 12, 6], where 4=1+3, 12=2+4+6, 6=5+1
- SQRT: [2.82, 6.93, 4.24], where 2.82=(1+3)/sqrt(2),
           6.93=(2+4+6)/sqrt(3), 4.24=(5+1)/sqrt(2)
- MAX: [3, 6, 5], where 3=max(1,3), 6=max(2,4,6), 5=max(5,1)
- LAST: [3, 6, 1], where 3=last(1,3), 6=last(2,4,6), 1=last(5,1)
- FIRST: [1, 2, 5], where 1=first(1,3), 2=first(2,4,6), 5=first(5,1)

    )DOC");
  }
};

class SequencePoolGradOp : public framework::OperatorWithKernel {
 public:
  using framework::OperatorWithKernel::OperatorWithKernel;

  void InferShape(framework::InferShapeContext* ctx) const override {
    PADDLE_ENFORCE_EQ(ctx->HasInput(framework::GradVarName("Out")), true,
                      "Gradient of Out should not be null.");
    PADDLE_ENFORCE_EQ(ctx->HasInput("X"), true,
                      "The input X should not be null.");
    auto og_dims = ctx->GetInputDim(framework::GradVarName("Out"));
    auto x_dims = ctx->GetInputDim("X");
    PADDLE_ENFORCE_EQ(og_dims.size(), x_dims.size(),
                      "The rank of output grad must equal to Input(X).");
    for (int64_t i = 1; i < og_dims.size(); ++i) {
      PADDLE_ENFORCE_EQ(og_dims[i], x_dims[i], "The dimension mismatch.");
    }

    ctx->ShareDim("X", /*->*/ framework::GradVarName("X"));
    ctx->ShareLoD("X", /*->*/ framework::GradVarName("X"));
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext& ctx) const override {
    return framework::OpKernelType(OperatorWithKernel::IndicateVarDataType(
                                       ctx, framework::GradVarName("Out")),
                                   ctx.device_context());
  }
};

template <typename T>
class SequencePoolGradOpMaker : public framework::SingleGradOpMaker<T> {
 public:
  using framework::SingleGradOpMaker<T>::SingleGradOpMaker;

 protected:
  std::unique_ptr<T> Apply() const override {
    auto* op_desc_ptr = new T();
    op_desc_ptr->SetType("sequence_pool_grad");
    op_desc_ptr->SetInput("X", this->Input("X"));
    if (boost::get<std::string>(this->GetAttr("pooltype")) == "MAX") {
      op_desc_ptr->SetInput("MaxIndex", this->Output("MaxIndex"));
    }
    op_desc_ptr->SetInput(framework::GradVarName("Out"),
                          this->OutputGrad("Out"));
    op_desc_ptr->SetOutput(framework::GradVarName("X"), this->InputGrad("X"));
    op_desc_ptr->SetAttrMap(this->Attrs());
    return std::unique_ptr<T>(op_desc_ptr);
  }
};

DECLARE_NO_NEED_BUFFER_VARS_INFERENCE(
    SequencePoolGradOpNoNeedBufferVarsInference, "X");

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;
REGISTER_OPERATOR(sequence_pool, ops::SequencePoolOp, ops::SequencePoolOpMaker,
                  ops::SequencePoolGradOpMaker<paddle::framework::OpDesc>,
                  ops::SequencePoolGradOpMaker<paddle::imperative::OpBase>);
REGISTER_OPERATOR(sequence_pool_grad, ops::SequencePoolGradOp,
                  ops::SequencePoolGradOpNoNeedBufferVarsInference);
REGISTER_OP_CPU_KERNEL(
    sequence_pool,
    ops::SequencePoolKernel<paddle::platform::CPUDeviceContext, float>);
REGISTER_OP_CPU_KERNEL(
    sequence_pool_grad,
    ops::SequencePoolGradKernel<paddle::platform::CPUDeviceContext, float>);
<|endoftext|>


<commit_before>#ifndef LUCE_HEADER_UTILITY_HH
#define LUCE_HEADER_UTILITY_HH

#include <Luce/Utility/Blank.hh>
#include <Luce/Utility/Integer.hh>
#include <Luce/Utility/LabledLoop.hh>
#include <Luce/Utility/NonComparable.hh>
#include <Luce/Utility/NonCopyable.hh>
#include <Luce/Utility/Property.hh>
#include <Luce/Utility/Real.hh>

#endif<commit_msg>Update Luce-Utility<commit_after>#ifndef LUCE_HEADER_UTILITY_HH
#define LUCE_HEADER_UTILITY_HH

#include <Luce/Utility/AlwaysInline.hh>
#include <Luce/Utility/Blank.hh>
#include <Luce/Utility/Integer.hh>
#include <Luce/Utility/LabledLoop.hh>
#include <Luce/Utility/NonComparable.hh>
#include <Luce/Utility/NonCopyable.hh>
#include <Luce/Utility/Property.hh>
#include <Luce/Utility/Real.hh>

#endif<|endoftext|>


<commit_before>// MathPresso - Mathematical Expression Parser and JIT Compiler.

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

#include <MathPresso/MathPresso.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

struct TestExpression
{
  const char* expression;
  MathPresso::mreal_t expected;
};

#define TABLE_SIZE(table) \
  (sizeof(table) / sizeof(table[0]))

#define TEST_EXPRESSION(expression) \
  { #expression, (MathPresso::mreal_t)(expression) }

int main(int argc, char* argv[])
{
  MathPresso::mreal_t x = 5.1f;
  MathPresso::mreal_t y = 6.7f;
  MathPresso::mreal_t z = 9.9f;
  MathPresso::mreal_t PI = 3.14159265358979323846f;

  MathPresso::Context ctx;
  MathPresso::Expression e0;
  MathPresso::Expression e1;

  ctx.addEnvironment(MathPresso::MENVIRONMENT_ALL);
  ctx.addVariable("x", 0 * sizeof(MathPresso::mreal_t));
  ctx.addVariable("y", 1 * sizeof(MathPresso::mreal_t));
  ctx.addVariable("z", 2 * sizeof(MathPresso::mreal_t));

  MathPresso::mreal_t variables[] = { x, y, z };

  TestExpression tests[] = {
    TEST_EXPRESSION( (x+y) ),
    TEST_EXPRESSION( -x ),
    TEST_EXPRESSION( -(x+y) ),
    TEST_EXPRESSION( -x ),
    TEST_EXPRESSION( -1 + x ),
    TEST_EXPRESSION( -(-(-1)) ),
    TEST_EXPRESSION( -(-(-x)) ),
    TEST_EXPRESSION( (x+y)*x ),
    TEST_EXPRESSION( (x+y)*y ),
    TEST_EXPRESSION( (x+y)*(1.19+z) ),
    TEST_EXPRESSION( ((x+(x+2.13))*y) ),
    TEST_EXPRESSION( (x+y+z*2+(x*z+z*1.5)) ),
    TEST_EXPRESSION( (((((((x-0.28)+y)+x)+x)*x)/1.12)*y) ),
    TEST_EXPRESSION( ((((x*((((y-1.50)+1.82)-x)/PI))/x)*x)+z) ),
    TEST_EXPRESSION( (((((((((x+1.35)+PI)/PI)-y)+z)-z)+y)/x)+0.81) )
  };

  for (int i = 0; i < TABLE_SIZE(tests); i++)
  {
    printf("EXP: %s\n", tests[i].expression);

    if (e0.create(ctx, tests[i].expression, MathPresso::MOPTION_NO_JIT) != MathPresso::MRESULT_OK)
    {
      printf("     Failure: Compilation error (no-jit).\n");
      continue;
    }

    if (e1.create(ctx, tests[i].expression, MathPresso::MOPTION_NONE) != MathPresso::MRESULT_OK)
    {
      printf("     Failure: Compilation error (use-jit).\n");
      continue;
    }

    MathPresso::mreal_t res0 = e0.evaluate(variables);
    MathPresso::mreal_t res1 = e1.evaluate(variables);
    MathPresso::mreal_t expected = tests[i].expected;

    const char* msg0 = fabs((double)res0 - (double)expected) < 0.001 ? "Ok" : "Failure";
    const char* msg1 = fabs((double)res1 - (double)expected) < 0.001 ? "Ok" : "Failure";

    printf(
      "     expected=%f\n"
      "     eval    =%f (%s)\n"
      "     jit     =%f (%s)\n"
      "\n",
      (double)expected,
      (double)res0, msg0,
      (double)res1, msg1);
  }

  return 0;
}
<commit_msg>more tests, more output<commit_after>// MathPresso - Mathematical Expression Parser and JIT Compiler.

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

#include <MathPresso/MathPresso.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

struct TestExpression
{
  const char* expression;
  MathPresso::mreal_t expected;
};

// Some test values
#define INITVARS (x = 5.1f, y = 6.7f, z = 9.9f, t = 0)

#define TABLE_SIZE(table) \
  (sizeof(table) / sizeof(table[0]))

#define TEST_EXPRESSION(expression) \
  { #expression, (INITVARS, expression) }

#define ADDCONST(c) addConstant(#c, (c))

int main(int argc, char* argv[])
{
  MathPresso::mreal_t x = 5.1f;
  MathPresso::mreal_t y = 6.7f;
  MathPresso::mreal_t z = 9.9f;
  MathPresso::mreal_t t = 0;

  const double PI = 3.14159265358979323846;

  MathPresso::mreal_t cx = cos(PI/3);
  MathPresso::mreal_t cy = sin(PI/3);
  MathPresso::mreal_t ox = 0.5;
  MathPresso::mreal_t oy = 1.75;

  MathPresso::Context ctx;
  MathPresso::Expression e0, e1, e2;

  ctx.addEnvironment(MathPresso::MENVIRONMENT_ALL);
  ctx.addVariable("x", 0 * sizeof(MathPresso::mreal_t));
  ctx.addVariable("y", 1 * sizeof(MathPresso::mreal_t));
  ctx.addVariable("z", 2 * sizeof(MathPresso::mreal_t));
  ctx.addVariable("t", 3 * sizeof(MathPresso::mreal_t));

  ctx.ADDCONST(cx);
  ctx.ADDCONST(cy);
  ctx.ADDCONST(ox);
  ctx.ADDCONST(oy);

  MathPresso::mreal_t variables[] = { x, y, z, t };

  TestExpression tests[] = {
    TEST_EXPRESSION( (x+y) ),
    TEST_EXPRESSION( -(x-y) ),
    TEST_EXPRESSION( -1 + x ),
    TEST_EXPRESSION( -(-(-1)) ),
    TEST_EXPRESSION( -(-(-x)) ),
    TEST_EXPRESSION( (x+y)*x ),
    TEST_EXPRESSION( (x+y)*y ),
    TEST_EXPRESSION( (x+y)*(1.19+z) ),
    TEST_EXPRESSION( ((x+(x+2.13))*y) ),
    TEST_EXPRESSION( (x+y+z*2+(x*z+z*1.5)) ),
    TEST_EXPRESSION( (((((((x-0.28)+y)+x)+x)*x)/1.12)*y) ),
    TEST_EXPRESSION( ((((x*((((y-1.50)+1.82)-x)/PI))/x)*x)+z) ),
    TEST_EXPRESSION( (((((((((x+1.35)+PI)/PI)-y)+z)-z)+y)/x)+0.81) ),
    TEST_EXPRESSION( 1+(x+2)+3 ),
    TEST_EXPRESSION( 1+(x+y)+z ),
    TEST_EXPRESSION( x=2*3+1 ),
    TEST_EXPRESSION( (x+y)*z ),
    TEST_EXPRESSION( (x=y)*x ),
    TEST_EXPRESSION( x=y=z ),
    TEST_EXPRESSION( x=(y+(z=5)) ),
    // functions
    TEST_EXPRESSION( log(exp(x * PI/2)) ),
    TEST_EXPRESSION( hypot(x, y) ),
    TEST_EXPRESSION( cos(PI/4)*x - sin(PI/4)*y ),
    TEST_EXPRESSION( sqrt(x*x + y*y + z*z) ),
    // operator ^
    { "sqrt(x^2 + y^2 + z^2)", (INITVARS, sqrt(x*x + y*y + z*z)) },
    { "x^-2 + y^-3", (INITVARS, 1/(x*x) + pow(y, -3)) },
    // semicolon is comma in C++
    { "z=x;x=3*x+1*y;y=1*x-3*z", (INITVARS, z=x,x=3*x+1*y,y=1*x-3*z) },
    { "t = cx*x - cy*y + ox; y = cy*x + cx*y + oy; x = t", (INITVARS, t=cx*x - cy*y + ox, y = cy*x + cx*y + oy, x = t) },
    { "x=cx;y=cy;t=z;z=t;", (INITVARS, x=cx,y=cy,t=z,z=t) },
    // assignment
    { "z = 1*z - 0*z + 1", (INITVARS, z = 1*z - 0*z + 1) },
    { "t = cx*x - cy*y + ox", (INITVARS, t=cx*x - cy*y + ox) },
    { "t = (cx*x - cy*y + ox)", (INITVARS, t=cx*x - cy*y + ox) },
    // unary operators
    TEST_EXPRESSION( 2 * + x ),
    TEST_EXPRESSION( 2 * + + y ),
    TEST_EXPRESSION( -x * -z ),
    TEST_EXPRESSION( 2 * - -t ),
    TEST_EXPRESSION( -2 * - - -3.5 ),
    // optimization tests
    TEST_EXPRESSION( x = 2 * - - - + + - 2 + 0*y + z/1 ),
    { "1*x - 0*y + z^1 - t/-1 + 0", (INITVARS, 1*x - 0*y + pow(z, 1) - t/-1 + 0) },
    { "sin(x*1^t) - cos(0*y + PI) + z^(-4/(-2-2))", (INITVARS, sin(x*pow(1,t)) - cos(0*y + PI) + pow(z, -4/(-2-2)) ) }
  };

  int numok0 = 0,
      numok1 = 0,
      numok2 = 0;

  int n = TABLE_SIZE(tests);
  for (int i = 0; i < n; ++i)
  {
    printf("EXP #%d: %s\n", i+1, tests[i].expression);

    if (e0.create(ctx, tests[i].expression, MathPresso::MOPTION_NO_JIT | MathPresso::MOPTION_NO_OPTIMIZE
        | MathPresso::MOPTION_VERBOSE) != MathPresso::MRESULT_OK)
    {
      printf("     Failure: Compilation error (no JIT).\n");
	  getchar();
      continue;
    }
    printf("\nUnoptimized RPN : %s\n", e0.getRPN().c_str());

    if (e1.create(ctx, tests[i].expression, MathPresso::MOPTION_NO_OPTIMIZE) != MathPresso::MRESULT_OK)
    {
      printf("     Failure: Compilation error (JIT).\n");
	  getchar();
      continue;
    }

    if (e2.create(ctx, tests[i].expression, MathPresso::MOPTION_VERBOSE) != MathPresso::MRESULT_OK)
    {
      printf("     Failure: Compilation error (optimized JIT).\n");
	  getchar();
      continue;
    }
    printf("\nOptimized RPN   : %s\n", e2.getRPN().c_str());

    INITVARS;
    printf("\nBefore:    x= %f  y= %f  z= %f  t= %f\n", x, y, z, t);
    variables[0] = x; variables[1] = y; variables[2] = z; variables[3] = t;
    MathPresso::mreal_t res0 = e0.evaluate(variables);

    INITVARS;
    variables[0] = x; variables[1] = y; variables[2] = z; variables[3] = t;
    MathPresso::mreal_t res1 = e1.evaluate(variables);

    INITVARS;
    variables[0] = x; variables[1] = y; variables[2] = z; variables[3] = t;
    MathPresso::mreal_t res2 = e2.evaluate(variables);

    printf("\nAfter:     x= %f  y= %f  z= %f  t= %f\n", variables[0], variables[1], variables[2], variables[3]);

    MathPresso::mreal_t expected = tests[i].expected;

    bool ok0 = fabs((double)res0 - (double)expected) < 0.0000001;
    bool ok1 = fabs((double)res1 - (double)expected) < 0.0000001;
    bool ok2 = fabs((double)res2 - (double)expected) < 0.0000001;
    if (ok0) numok0++;
    if (ok1) numok1++;
    if (ok2) numok2++;

    printf("\n"
      "     expected      = %f\n"
      "     eval          = %f (%s)\n"
      "     JIT           = %f (%s)\n"
      "     optimized JIT = %f (%s)\n"
      "\n",
      (double)expected,
      (double)res0, ok0 ? "Ok" : "Failure",
      (double)res1, ok1 ? "Ok" : "Failure",
      (double)res2, ok2 ? "Ok" : "Failure");
      //getchar();
  }

  printf("eval:    %d of %d ok\n"
         "jit:     %d of %d ok\n"
         "op_jit:  %d of %d ok\n", numok0, n, numok1, n, numok2, n);
  //getchar();

  MathPresso::mresult_t result;
  do {
    char buffer[4096];
    fgets(buffer, 4095, stdin);
    if (buffer[0] == 0) break;

    MathPresso::Expression e;
    result = e.create(ctx, buffer, MathPresso::MOPTION_VERBOSE);
    if (result == MathPresso::MRESULT_NO_EXPRESSION)
      printf("No expression\n");

    if (result != MathPresso::MRESULT_OK)
    {
      //printf("%s\n", buffer);
      int errorPos = e.getErrorPos();
      for (int j = 0; j < errorPos; ++j) printf(" ");
      printf("^\n");
      printf("Error: %s at pos=%d\n", e.getErrorMessage(), errorPos);
    }
    else
    {
      printf("\nOptimized RPN   : %s\n", e.getRPN().c_str());
      printf("\n%s\n", e.getJitLog().c_str());
      printf("Result = %9.20g\n", e.evaluate(&variables));
    }
  } while(result != MathPresso::MRESULT_NO_EXPRESSION);

  return 0;
}
<|endoftext|>


<commit_before>//
// Copyright (C) 2017 University of Amsterdam
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include "appinfo.h"

const Version AppInfo::version = Version(0, 8, 5, 255);
const std::string AppInfo::name = "JASP";
const std::string AppInfo::builddate = __DATE__ " " __TIME__ " (Netherlands)" ;

std::string AppInfo::getShortDesc()
{
	return AppInfo::name + " " + AppInfo::version.asString();
}

std::string AppInfo::getBuildYear()
{
	std::string datum = __DATE__;
	return datum.substr(datum.length() - 4);
}

<commit_msg>Set version to 0.8.5.1<commit_after>//
// Copyright (C) 2017 University of Amsterdam
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include "appinfo.h"

const Version AppInfo::version = Version(0, 8, 5, 256);
const std::string AppInfo::name = "JASP";
const std::string AppInfo::builddate = __DATE__ " " __TIME__ " (Netherlands)" ;

std::string AppInfo::getShortDesc()
{
	return AppInfo::name + " " + AppInfo::version.asString();
}

std::string AppInfo::getBuildYear()
{
	std::string datum = __DATE__;
	return datum.substr(datum.length() - 4);
}

<|endoftext|>