text:
#include "tensorflow/lite/tools/optimize/modify_model_interface.h"

#include <memory>

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/memory/memory.h"
#include "tensorflow/lite/model.h"
#include "tensorflow/lite/schema/schema_generated.h"

namespace tflite {
namespace optimize {
namespace {

using ::testing::ElementsAreArray;

// Create a model with 1 quant, 1 FC, 1 dequant
std::unique_ptr<ModelT> CreateModelSingleInputOutput() {
  auto model = absl::make_unique<ModelT>();
  auto subgraph = absl::make_unique<tflite::SubGraphT>();
  auto buffer = absl::make_unique<tflite::BufferT>();
  auto quant_op_code = absl::make_unique<OperatorCodeT>();
  auto quant_op = absl::make_unique<OperatorT>();
  auto fc_op_code = absl::make_unique<OperatorCodeT>();
  auto fc_op = absl::make_unique<OperatorT>();
  auto dequant_op_code = absl::make_unique<OperatorCodeT>();
  auto dequant_op = absl::make_unique<OperatorT>();

  model->subgraphs.push_back(std::move(subgraph));

  // Op code
  quant_op_code->builtin_code = BuiltinOperator_QUANTIZE;
  quant_op_code->version = 2;

  fc_op_code->builtin_code = BuiltinOperator_FULLY_CONNECTED;
  fc_op_code->version = 2;

  dequant_op_code->builtin_code = BuiltinOperator_DEQUANTIZE;
  dequant_op_code->version = 2;

  // Op.
  quant_op->opcode_index = 0;
  quant_op->inputs = {2};
  quant_op->outputs = {0};

  fc_op->opcode_index = 1;
  fc_op->inputs = {0};
  fc_op->outputs = {1};

  dequant_op->opcode_index = 2;
  dequant_op->inputs = {1};
  dequant_op->outputs = {3};

  model->subgraphs[0]->operators.push_back(std::move(quant_op));
  model->subgraphs[0]->operators.push_back(std::move(fc_op));
  model->subgraphs[0]->operators.push_back(std::move(dequant_op));

  model->operator_codes.push_back(std::move(quant_op_code));
  model->operator_codes.push_back(std::move(fc_op_code));
  model->operator_codes.push_back(std::move(dequant_op_code));

  // Model input/otuput.
  model->subgraphs[0]->inputs = {2};
  model->subgraphs[0]->outputs = {3};

  // Tensors. Float tensors are at the end of the tensor list.

  auto tensor_0 = absl::make_unique<TensorT>();
  tensor_0->quantization = absl::make_unique<QuantizationParametersT>();
  tensor_0->quantization->scale.push_back(0.35);
  tensor_0->quantization->zero_point.push_back(28);
  tensor_0->name = "tensor_0";
  tensor_0->shape = {};
  tensor_0->type = TensorType_INT8;

  auto tensor_1 = absl::make_unique<TensorT>();
  tensor_1->quantization = absl::make_unique<QuantizationParametersT>();
  tensor_1->quantization->scale.push_back(0.12);
  tensor_1->quantization->zero_point.push_back(50);
  tensor_1->name = "tensor_1";
  tensor_1->shape = {};
  tensor_1->type = TensorType_INT8;

  auto tensor_2 = absl::make_unique<TensorT>();
  tensor_2->name = "tensor_2";
  tensor_2->shape = {};
  tensor_2->type = TensorType_FLOAT32;

  auto tensor_3 = absl::make_unique<TensorT>();
  tensor_3->name = "tensor_3";
  tensor_3->shape = {};
  tensor_3->type = TensorType_FLOAT32;

  model->subgraphs[0]->tensors.push_back(std::move(tensor_0));
  model->subgraphs[0]->tensors.push_back(std::move(tensor_1));
  model->subgraphs[0]->tensors.push_back(std::move(tensor_2));
  model->subgraphs[0]->tensors.push_back(std::move(tensor_3));

  // Buffer
  model->buffers.push_back(std::move(buffer));

  return model;
}

// Create a model with 2 quant, 1 FC, 2 dequant
// The model mimics the behavior of the quantize_model.cc.
std::unique_ptr<ModelT> CreateModelMultipleInputOutput() {
  auto model = absl::make_unique<ModelT>();
  auto subgraph = absl::make_unique<tflite::SubGraphT>();
  auto buffer = absl::make_unique<tflite::BufferT>();
  auto quant_op_code = absl::make_unique<OperatorCodeT>();
  auto quant_op_1 = absl::make_unique<OperatorT>();
  auto quant_op_2 = absl::make_unique<OperatorT>();
  auto fc_op_code = absl::make_unique<OperatorCodeT>();
  auto fc_op = absl::make_unique<OperatorT>();
  auto dequant_op_code = absl::make_unique<OperatorCodeT>();
  auto dequant_op_1 = absl::make_unique<OperatorT>();
  auto dequant_op_2 = absl::make_unique<OperatorT>();

  model->subgraphs.push_back(std::move(subgraph));

  // Op code
  quant_op_code->builtin_code = BuiltinOperator_QUANTIZE;
  quant_op_code->version = 2;

  fc_op_code->builtin_code = BuiltinOperator_FULLY_CONNECTED;
  fc_op_code->version = 2;

  dequant_op_code->builtin_code = BuiltinOperator_DEQUANTIZE;
  dequant_op_code->version = 2;

  // Op.
  quant_op_1->opcode_index = 0;
  quant_op_1->inputs = {4};
  quant_op_1->outputs = {0};
  quant_op_2->opcode_index = 0;
  quant_op_2->inputs = {5};
  quant_op_2->outputs = {1};

  fc_op->opcode_index = 1;
  fc_op->inputs = {0, 1};
  fc_op->outputs = {2, 3};

  dequant_op_1->opcode_index = 2;
  dequant_op_1->inputs = {2};
  dequant_op_1->outputs = {6};
  dequant_op_2->opcode_index = 2;
  dequant_op_2->inputs = {3};
  dequant_op_2->outputs = {7};

  model->subgraphs[0]->operators.push_back(std::move(quant_op_1));
  model->subgraphs[0]->operators.push_back(std::move(quant_op_2));
  model->subgraphs[0]->operators.push_back(std::move(fc_op));
  model->subgraphs[0]->operators.push_back(std::move(dequant_op_1));
  model->subgraphs[0]->operators.push_back(std::move(dequant_op_2));

  model->operator_codes.push_back(std::move(quant_op_code));
  model->operator_codes.push_back(std::move(fc_op_code));
  model->operator_codes.push_back(std::move(dequant_op_code));

  // Model input/otuput.
  model->subgraphs[0]->inputs = {4, 5};
  model->subgraphs[0]->outputs = {6, 7};

  // Tensors
  auto tensor_0 = absl::make_unique<TensorT>();
  tensor_0->quantization = absl::make_unique<QuantizationParametersT>();
  tensor_0->quantization->scale.push_back(0.35);
  tensor_0->quantization->zero_point.push_back(28);
  tensor_0->name = "tensor_0";
  tensor_0->shape = {};
  tensor_0->type = TensorType_INT8;

  auto tensor_1 = absl::make_unique<TensorT>();
  tensor_1->quantization = absl::make_unique<QuantizationParametersT>();
  tensor_1->quantization->scale.push_back(0.12);
  tensor_1->quantization->zero_point.push_back(50);
  tensor_1->name = "tensor_1";
  tensor_1->shape = {};
  tensor_1->type = TensorType_INT8;

  auto tensor_2 = absl::make_unique<TensorT>();
  tensor_2->quantization = absl::make_unique<QuantizationParametersT>();
  tensor_2->quantization->scale.push_back(0.45);
  tensor_2->quantization->zero_point.push_back(28);
  tensor_2->name = "tensor_2";
  tensor_2->shape = {};
  tensor_2->type = TensorType_INT8;

  auto tensor_3 = absl::make_unique<TensorT>();
  tensor_3->quantization = absl::make_unique<QuantizationParametersT>();
  tensor_3->quantization->scale.push_back(0.22);
  tensor_3->quantization->zero_point.push_back(50);
  tensor_3->name = "tensor_3";
  tensor_3->shape = {};
  tensor_3->type = TensorType_INT8;

  auto tensor_4 = absl::make_unique<TensorT>();
  tensor_4->name = "tensor_4";
  tensor_4->shape = {};
  tensor_4->type = TensorType_FLOAT32;

  auto tensor_5 = absl::make_unique<TensorT>();
  tensor_5->name = "tensor_5";
  tensor_5->shape = {};
  tensor_5->type = TensorType_FLOAT32;

  auto tensor_6 = absl::make_unique<TensorT>();
  tensor_6->name = "tensor_6";
  tensor_6->shape = {};
  tensor_6->type = TensorType_FLOAT32;

  auto tensor_7 = absl::make_unique<TensorT>();
  tensor_7->name = "tensor_7";
  tensor_7->shape = {};
  tensor_7->type = TensorType_FLOAT32;

  model->subgraphs[0]->tensors.push_back(std::move(tensor_0));
  model->subgraphs[0]->tensors.push_back(std::move(tensor_1));
  model->subgraphs[0]->tensors.push_back(std::move(tensor_2));
  model->subgraphs[0]->tensors.push_back(std::move(tensor_3));
  model->subgraphs[0]->tensors.push_back(std::move(tensor_4));
  model->subgraphs[0]->tensors.push_back(std::move(tensor_5));
  model->subgraphs[0]->tensors.push_back(std::move(tensor_6));
  model->subgraphs[0]->tensors.push_back(std::move(tensor_7));

  // Buffer
  model->buffers.push_back(std::move(buffer));

  return model;
}

// Create a model with 1 FC.
std::unique_ptr<ModelT> CreateFloatModel() {
  auto model = absl::make_unique<ModelT>();
  auto subgraph = absl::make_unique<tflite::SubGraphT>();
  auto buffer = absl::make_unique<tflite::BufferT>();
  auto fc_op_code = absl::make_unique<OperatorCodeT>();
  auto fc_op = absl::make_unique<OperatorT>();

  model->subgraphs.push_back(std::move(subgraph));

  // Op code
  fc_op_code->builtin_code = BuiltinOperator_FULLY_CONNECTED;
  fc_op_code->version = 2;

  // Op.
  fc_op->opcode_index = 0;
  fc_op->inputs = {0};
  fc_op->outputs = {1};

  model->subgraphs[0]->operators.push_back(std::move(fc_op));
  model->operator_codes.push_back(std::move(fc_op_code));

  // Model input/otuput.
  model->subgraphs[0]->inputs = {0};
  model->subgraphs[0]->outputs = {1};

  // Tensors
  auto tensor_0 = absl::make_unique<TensorT>();
  tensor_0->name = "tensor_0";
  tensor_0->shape = {};
  tensor_0->type = TensorType_FLOAT32;

  auto tensor_1 = absl::make_unique<TensorT>();
  tensor_1->name = "tensor_1";
  tensor_1->shape = {};
  tensor_1->type = TensorType_FLOAT32;

  model->subgraphs[0]->tensors.push_back(std::move(tensor_0));
  model->subgraphs[0]->tensors.push_back(std::move(tensor_1));

  // Buffer
  model->buffers.push_back(std::move(buffer));

  return model;
}

TEST(ModelInterface, Uint8SingleInputOutput) {
  auto model = CreateModelSingleInputOutput();

  // Ops.
  EXPECT_EQ(model->subgraphs[0]->operators[0]->opcode_index, 0);
  EXPECT_EQ(model->subgraphs[0]->operators[1]->opcode_index, 1);
  EXPECT_EQ(model->subgraphs[0]->operators[2]->opcode_index, 2);

  // Change model type.
  flatbuffers::FlatBufferBuilder builder;
  EXPECT_EQ(ModifyModelInterface(&builder, model.get(), TensorType_UINT8,
                                 TensorType_UINT8),
            kTfLiteOk);

  // Verify results.
  EXPECT_EQ(model->operator_codes.size(), 3);
  EXPECT_EQ(model->subgraphs.size(), 1);
  EXPECT_EQ(model->subgraphs[0]->operators.size(), 3);
  EXPECT_EQ(model->subgraphs[0]->tensors.size(), 4);
  EXPECT_EQ(model->buffers.size(), 1);

  EXPECT_EQ(model->subgraphs[0]->tensors[2]->name, "tensor_2");
  EXPECT_EQ(model->subgraphs[0]->tensors[2]->type, TensorType_UINT8);
  EXPECT_FLOAT_EQ(model->subgraphs[0]->tensors[2]->quantization->scale[0],
                  0.35);
  EXPECT_EQ(model->subgraphs[0]->tensors[2]->quantization->zero_point[0], 156);

  EXPECT_EQ(model->subgraphs[0]->tensors[3]->name, "tensor_3");
  EXPECT_EQ(model->subgraphs[0]->tensors[3]->type, TensorType_UINT8);
  EXPECT_FLOAT_EQ(model->subgraphs[0]->tensors[3]->quantization->scale[0],
                  0.12);
  EXPECT_EQ(model->subgraphs[0]->tensors[3]->quantization->zero_point[0], 178);

  // Ops.
  EXPECT_EQ(model->subgraphs[0]->operators[0]->opcode_index, 0);
  EXPECT_EQ(model->subgraphs[0]->operators[1]->opcode_index, 1);
  EXPECT_EQ(model->subgraphs[0]->operators[2]->opcode_index, 0);
}

TEST(ModelInterface, Int8SingleInputOutput) {
  auto model = CreateModelSingleInputOutput();

  // Change model type.
  flatbuffers::FlatBufferBuilder builder;
  EXPECT_EQ(ModifyModelInterface(&builder, model.get(), TensorType_INT8,
                                 TensorType_INT8),
            kTfLiteOk);

  // Verify results.
  EXPECT_EQ(model->operator_codes.size(), 3);
  EXPECT_EQ(model->subgraphs.size(), 1);
  EXPECT_EQ(model->subgraphs[0]->operators.size(), 1);
  EXPECT_EQ(model->subgraphs[0]->tensors.size(), 2);
  EXPECT_EQ(model->buffers.size(), 1);

  EXPECT_EQ(model->subgraphs[0]->inputs.size(), 1);
  EXPECT_EQ(model->subgraphs[0]->inputs[0], 0);
  EXPECT_EQ(model->subgraphs[0]->outputs.size(), 1);
  EXPECT_EQ(model->subgraphs[0]->outputs[0], 1);
}

TEST(ModelInterface, MixedTypeSingleInputOutput) {
  auto model = CreateModelSingleInputOutput();

  // Change model type.
  flatbuffers::FlatBufferBuilder builder;
  EXPECT_EQ(ModifyModelInterface(&builder, model.get(), TensorType_UINT8,
                                 TensorType_INT8),
            kTfLiteOk);

  // Verify results.
  EXPECT_EQ(model->operator_codes.size(), 3);
  EXPECT_EQ(model->subgraphs.size(), 1);
  EXPECT_EQ(model->subgraphs[0]->operators.size(), 2);
  EXPECT_EQ(model->subgraphs[0]->tensors.size(), 3);
  EXPECT_EQ(model->buffers.size(), 1);

  EXPECT_EQ(model->subgraphs[0]->inputs.size(), 1);
  EXPECT_EQ(model->subgraphs[0]->inputs[0], 2);
  EXPECT_EQ(model->subgraphs[0]->outputs.size(), 1);
  EXPECT_EQ(model->subgraphs[0]->outputs[0], 1);
}

TEST(ModelInterface, Uint8MutipleInputOutput) {
  auto model = CreateModelMultipleInputOutput();

  // Ops.
  EXPECT_EQ(model->subgraphs[0]->operators[0]->opcode_index, 0);
  EXPECT_EQ(model->subgraphs[0]->operators[1]->opcode_index, 0);
  EXPECT_EQ(model->subgraphs[0]->operators[2]->opcode_index, 1);
  EXPECT_EQ(model->subgraphs[0]->operators[3]->opcode_index, 2);
  EXPECT_EQ(model->subgraphs[0]->operators[4]->opcode_index, 2);

  // Change model type.
  flatbuffers::FlatBufferBuilder builder;
  EXPECT_EQ(ModifyModelInterface(&builder, model.get(), TensorType_UINT8,
                                 TensorType_UINT8),
            kTfLiteOk);

  // Verify results.
  // Model.
  EXPECT_EQ(model->operator_codes.size(), 3);
  EXPECT_EQ(model->subgraphs.size(), 1);
  EXPECT_EQ(model->subgraphs[0]->operators.size(), 5);
  EXPECT_EQ(model->subgraphs[0]->tensors.size(), 8);
  EXPECT_EQ(model->subgraphs[0]->inputs.size(), 2);
  EXPECT_EQ(model->subgraphs[0]->inputs[0], 4);
  EXPECT_EQ(model->subgraphs[0]->inputs[1], 5);
  EXPECT_EQ(model->subgraphs[0]->outputs.size(), 2);
  EXPECT_EQ(model->subgraphs[0]->outputs[0], 6);
  EXPECT_EQ(model->subgraphs[0]->outputs[1], 7);
  EXPECT_EQ(model->buffers.size(), 1);

  // Tensors,
  EXPECT_EQ(model->subgraphs[0]->tensors[4]->name, "tensor_4");
  EXPECT_EQ(model->subgraphs[0]->tensors[4]->type, TensorType_UINT8);
  EXPECT_FLOAT_EQ(model->subgraphs[0]->tensors[4]->quantization->scale[0],
                  0.35);
  EXPECT_EQ(model->subgraphs[0]->tensors[4]->quantization->zero_point[0], 156);

  EXPECT_EQ(model->subgraphs[0]->tensors[5]->name, "tensor_5");
  EXPECT_EQ(model->subgraphs[0]->tensors[5]->type, TensorType_UINT8);
  EXPECT_FLOAT_EQ(model->subgraphs[0]->tensors[5]->quantization->scale[0],
                  0.12);
  EXPECT_EQ(model->subgraphs[0]->tensors[5]->quantization->zero_point[0], 178);

  EXPECT_EQ(model->subgraphs[0]->tensors[6]->name, "tensor_6");
  EXPECT_EQ(model->subgraphs[0]->tensors[6]->type, TensorType_UINT8);
  EXPECT_FLOAT_EQ(model->subgraphs[0]->tensors[6]->quantization->scale[0],
                  0.45);
  EXPECT_EQ(model->subgraphs[0]->tensors[6]->quantization->zero_point[0], 156);

  EXPECT_EQ(model->subgraphs[0]->tensors[7]->name, "tensor_7");
  EXPECT_EQ(model->subgraphs[0]->tensors[7]->type, TensorType_UINT8);
  EXPECT_FLOAT_EQ(model->subgraphs[0]->tensors[7]->quantization->scale[0],
                  0.22);
  EXPECT_EQ(model->subgraphs[0]->tensors[7]->quantization->zero_point[0], 178);

  // Ops.
  EXPECT_EQ(model->subgraphs[0]->operators[0]->opcode_index, 0);
  EXPECT_EQ(model->subgraphs[0]->operators[1]->opcode_index, 0);
  EXPECT_EQ(model->subgraphs[0]->operators[2]->opcode_index, 1);
  EXPECT_EQ(model->subgraphs[0]->operators[3]->opcode_index, 0);
  EXPECT_EQ(model->subgraphs[0]->operators[4]->opcode_index, 0);
}

TEST(ModelInterface, Int8MutipleInputOutput) {
  auto model = CreateModelMultipleInputOutput();

  // Change model type.
  flatbuffers::FlatBufferBuilder builder;
  EXPECT_EQ(ModifyModelInterface(&builder, model.get(), TensorType_INT8,
                                 TensorType_INT8),
            kTfLiteOk);

  // Verify results.
  EXPECT_EQ(model->operator_codes.size(), 3);
  EXPECT_EQ(model->subgraphs.size(), 1);
  EXPECT_EQ(model->subgraphs[0]->operators.size(), 1);
  EXPECT_EQ(model->subgraphs[0]->tensors.size(), 4);
  EXPECT_EQ(model->subgraphs[0]->inputs.size(), 2);
  EXPECT_EQ(model->subgraphs[0]->inputs[0], 0);
  EXPECT_EQ(model->subgraphs[0]->inputs[1], 1);
  EXPECT_EQ(model->subgraphs[0]->outputs.size(), 2);
  EXPECT_EQ(model->subgraphs[0]->outputs[0], 2);
  EXPECT_EQ(model->subgraphs[0]->outputs[1], 3);
  EXPECT_EQ(model->buffers.size(), 1);

  // Tensors,
  EXPECT_EQ(model->subgraphs[0]->tensors[0]->name, "tensor_0");
  EXPECT_EQ(model->subgraphs[0]->tensors[0]->type, TensorType_INT8);
  EXPECT_FLOAT_EQ(model->subgraphs[0]->tensors[0]->quantization->scale[0],
                  0.35);
  EXPECT_EQ(model->subgraphs[0]->tensors[0]->quantization->zero_point[0], 28);

  EXPECT_EQ(model->subgraphs[0]->tensors[1]->name, "tensor_1");
  EXPECT_EQ(model->subgraphs[0]->tensors[1]->type, TensorType_INT8);
  EXPECT_FLOAT_EQ(model->subgraphs[0]->tensors[1]->quantization->scale[0],
                  0.12);
  EXPECT_EQ(model->subgraphs[0]->tensors[1]->quantization->zero_point[0], 50);

  EXPECT_EQ(model->subgraphs[0]->tensors[2]->name, "tensor_2");
  EXPECT_EQ(model->subgraphs[0]->tensors[2]->type, TensorType_INT8);
  EXPECT_FLOAT_EQ(model->subgraphs[0]->tensors[2]->quantization->scale[0],
                  0.45);
  EXPECT_EQ(model->subgraphs[0]->tensors[2]->quantization->zero_point[0], 28);

  EXPECT_EQ(model->subgraphs[0]->tensors[3]->name, "tensor_3");
  EXPECT_EQ(model->subgraphs[0]->tensors[3]->type, TensorType_INT8);
  EXPECT_FLOAT_EQ(model->subgraphs[0]->tensors[3]->quantization->scale[0],
                  0.22);
  EXPECT_EQ(model->subgraphs[0]->tensors[3]->quantization->zero_point[0], 50);

  // Ops.
  EXPECT_EQ(model->subgraphs[0]->operators[0]->opcode_index, 1);
}

TEST(ModelInterface, Float) {
  // Create the model.
  std::unique_ptr<ModelT> input_model_t = CreateFloatModel();
  flatbuffers::FlatBufferBuilder builder_temp;
  flatbuffers::Offset<Model> output_model_location =
      Model::Pack(builder_temp, input_model_t.get());
  FinishModelBuffer(builder_temp, output_model_location);
  const uint8_t* buffer_temp = builder_temp.GetBufferPointer();
  const Model* input_model = GetModel(buffer_temp);

  // Change model type.
  flatbuffers::FlatBufferBuilder builder;
  EXPECT_EQ(Uint8QuantizeModelInputsOutputs(&builder, input_model,
                                            {{"tensor_0", {0.4, 2}}},
                                            {{"tensor_1", {0.5, -5}}}),
            kTfLiteOk);

  const uint8_t* buffer = builder.GetBufferPointer();
  const Model* output_model = GetModel(buffer);
  std::unique_ptr<ModelT> model;
  model.reset(output_model->UnPack());

  // Verify results.
  EXPECT_EQ(model->operator_codes.size(), 3);
  EXPECT_EQ(model->subgraphs.size(), 1);
  EXPECT_EQ(model->subgraphs[0]->operators.size(), 3);
  EXPECT_EQ(model->subgraphs[0]->tensors.size(), 4);
  EXPECT_EQ(model->buffers.size(), 1);

  // Ops.
  EXPECT_EQ(model->operator_codes[0]->builtin_code,
            BuiltinOperator_FULLY_CONNECTED);
  EXPECT_EQ(model->operator_codes[1]->builtin_code, BuiltinOperator_DEQUANTIZE);
  EXPECT_EQ(model->operator_codes[2]->builtin_code, BuiltinOperator_QUANTIZE);

  EXPECT_EQ(model->subgraphs[0]->operators[0]->opcode_index, 1);
  EXPECT_EQ(model->subgraphs[0]->operators[1]->opcode_index, 0);
  EXPECT_EQ(model->subgraphs[0]->operators[2]->opcode_index, 2);

  EXPECT_THAT(model->subgraphs[0]->operators[0]->inputs, ElementsAreArray({2}));
  EXPECT_THAT(model->subgraphs[0]->operators[0]->outputs,
              ElementsAreArray({0}));
  EXPECT_THAT(model->subgraphs[0]->operators[1]->inputs, ElementsAreArray({0}));
  EXPECT_THAT(model->subgraphs[0]->operators[1]->outputs,
              ElementsAreArray({1}));
  EXPECT_THAT(model->subgraphs[0]->operators[2]->inputs, ElementsAreArray({1}));
  EXPECT_THAT(model->subgraphs[0]->operators[2]->outputs,
              ElementsAreArray({3}));

  // Tensors.
  EXPECT_EQ(model->subgraphs[0]->tensors[0]->name, "tensor_0");
  EXPECT_EQ(model->subgraphs[0]->tensors[0]->type, TensorType_FLOAT32);
  EXPECT_EQ(model->subgraphs[0]->tensors[1]->name, "tensor_1");
  EXPECT_EQ(model->subgraphs[0]->tensors[1]->type, TensorType_FLOAT32);

  EXPECT_EQ(model->subgraphs[0]->tensors[2]->name, "tensor_0_uint8");
  EXPECT_EQ(model->subgraphs[0]->tensors[2]->type, TensorType_UINT8);
  EXPECT_FLOAT_EQ(model->subgraphs[0]->tensors[2]->quantization->scale[0], 0.4);
  EXPECT_EQ(model->subgraphs[0]->tensors[2]->quantization->zero_point[0], 2);

  EXPECT_EQ(model->subgraphs[0]->tensors[3]->name, "tensor_1_uint8");
  EXPECT_EQ(model->subgraphs[0]->tensors[3]->type, TensorType_UINT8);
  EXPECT_FLOAT_EQ(model->subgraphs[0]->tensors[3]->quantization->scale[0], 0.5);
  EXPECT_EQ(model->subgraphs[0]->tensors[3]->quantization->zero_point[0], -5);
}

}  // namespace
}  // namespace optimize
}  // namespace tflite

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}


BACKGROUND: We conducted a phase 3, randomized, double-blind, placebo-controlled trial of sorafenib, a multikinase inhibitor of tumor-cell proliferation and angiogenesis, in patients with advanced clear-cell renal-cell carcinoma. METHODS: From November 2003 to March 2005, we randomly assigned 903 patients with renal-cell carcinoma that was resistant to standard therapy to receive either continuous treatment with oral sorafenib (at a dose of 400 mg twice daily) or placebo; 451 patients received sorafenib and 452 received placebo. The primary end point was overall survival. A single planned analysis of progression-free survival in January 2005 showed a statistically significant benefit of sorafenib over placebo. Consequently, crossover was permitted from placebo to sorafenib, beginning in May 2005. RESULTS: At the January 2005 cutoff, the median progression-free survival was 5.5 months in the sorafenib group and 2.8 months in the placebo group (hazard ratio for disease progression in the sorafenib group, 0.44; 95% confidence interval [CI], 0.35 to 0.55; P<0.01). The first interim analysis of overall survival in May 2005 showed that sorafenib reduced the risk of death, as compared with placebo (hazard ratio, 0.72; 95% CI, 0.54 to 0.94; P=0.02), although this benefit was not statistically significant according to the O'Brien-Fleming threshold. Partial responses were reported as the best response in 10% of patients receiving sorafenib and in 2% of those receiving placebo (P<0.001). Diarrhea, rash, fatigue, and hand-foot skin reactions were the most common adverse events associated with sorafenib. Hypertension and cardiac ischemia were rare serious adverse events that were more common in patients receiving sorafenib than in those receiving placebo. CONCLUSIONS: As compared with placebo, treatment with sorafenib prolongs progression-free survival in patients with advanced clear-cell renal-cell carcinoma in whom previous therapy has failed; however, treatment is associated with increased toxic effects. (ClinicalTrials.gov number, NCT00073307 [ClinicalTrials.gov].). Copyright 2007 Massachusetts Medical Society.


text:
Miserey () is a commune in the Eure department in the Normandy region in Northern France. In 2017, it had a population of 629.

History
On 23 August 1944, the first Recon Platoon of the 823rd Tank Destroyer Bn., 30th Infantry Division was ordered to recon the village of Miserey, 8 km (5 mi) east of Évreux. Proceeding, the platoon found the town occupied by the German Army. A small-scale battle ensued, ending with 20 enemy KIA and 40 POWs. The Battalion Command Post (CP) was established in a small château there at 3:30 p.m.

The first Recon Platoon claims credit for the liberation of Miserey. The village has a monument to Ben Abruzzo, Maxie Anderson and Larry Newman, the pioneering balloonists who flew the Double Eagle II across the Atlantic Ocean from Presque Isle, Maine, United States, landing in Miserey on the 17 August 1978.

In popular culture
Miserey is portrayed in the 2017 thriller ministries La Mante as Damien Carrot's childhood hometown.

Population

See also
Communes of the Eure department

References

Communes of Eure

redpajama_set_name: RedPajamaWikipedia


1987 ALFA ROMEO 2000inj GRADUATE LTD EDT SPYDER (left hand drive)Very few cars beat the superb styling of Pininfarinas famous Italian cars and this one is definitely no exception. It is stunningly finished in Avorio Alfa Cream with full tan leather trim complemented by a black double duck hood which is as good as new. There have been only 3 owners from new, first was Alfonso Caporaso, 2nd was Charles Trapp and the 3rd was Gillian Goodwin who owned car for the last 22 years. The mileage of 47000 miles is warranted and supported by old MoTs, bills and servicing history. This Alfa is fitted with its original two litre twin overhead cam Alfa engine with a 5 speed gear box and is capable of 120mph and 0 to 60 in 9 seconds, astonishing for its day. These cars were only made in left hand drive, so this is a great opportunity to drive a fabulous car on continental holidays or to keep at a holiday home abroad or enjoy on the UK roads. However, if you feel the need for a right hand drive Alfa, for a relatively small amount of money this car can be converted to RHD.The history folder includes current and previous V5s, current and previous MoT certificates, MoT related paperwork, DVLA paperwork, insurance paperwork, original Handbook, service book and Alfa Europe map of Dealers book, business cards, write ups, Covercraft paperwork, Sony radio cassette manual, booklet and warranty leaflet, previous bills of sale and previous invoices circa £9000 spent on servicing and general upkeep. In addition, there is a wonderful cassette tape featuring music from OK Italia by Edorado Bennato just to get you in the mood when driving this wonderful sports car.Features include Sony radio cassette music system with electric aerial, overmats, tinted glass, chrome kit, chrome door handles inside and out, toolkit, door mirrors, reversing lights, centre console, leather adjustable seats with headrests, 15 inch wheels with chrome Alfa embossed centre caps, chrome tailpipe, Alfa embossed door mirrors, Alfa cloverleaf wing badges and other Alfa badges, hood cover, rear spoiler, sports steering wheel and locking petrol cap.This type of Alfa Romeo was made famous by the movie The Graduate and has since been a real favourite worldwide.
This advert is for an Alfa Romeo Spider, click Alfa Romeo Spider in Poole to see more cars like this in the local area.


text:
Lowcountry Live
Harlestons Heritage
Men's / By Andrea
Charleston is never short of creative forces in fashion and style. But there's always room to grow and a void in the market, especially in the men's department. Enter Harlestons, a menswear brand specializing in quality, fit, function, and comfort. Buddies Weston Mallon and Cason Hund, launched right before the pandemic hit and have successfully cultivated a brand rooted in Charleston heritage and style.
The name Harlestons, was inspired after Harleston Green; The birthplace of American Golf in 1786 in downtown Charleston now known as Harleston Village. Every detail around their brand was well thought out, incorporating Charleston history and its surroundings into their collection. Recognizable Charleston street names, landmarks (The Wentworth, The Ashley), and football coaches are used for style names. The Riggs polo is named after the first football coach for Clemson and The Sumter for the Carolina Gamecocks. They also referenced significant colors associated in Charleston's heritage such as Haint Blue, the famous blue on the porch ceilings, and Brenton Pink, named after the one of the oldest structures in Charleston.
The premium polos and pullovers offer a tailored fit for any body type, a structured collar to maintain its shape wash after wash and the perfect fit tucked or untucked. Everything is designed here in Charleston, SC with the weather and active lifestyle in mind. The moment my husband Gustavo put on a Harlestons polo he said "This is not your average polo, it's elevated." We've both worked in the fashion business for over 25 years and we've seen every level of quality and fit and we both agree that Harlestons delivers a high caliber of clothing at an attainable price. Gustavo's a huskier guy who likes a lot of stretch in his clothing while maintaining a tailored fit. He immediately fell in love with the polos.
Harlestons uses the highest quality materials and produce their clothing in the same factory as other well known menswear brands that are reputable in the industry. The branding and packaging is on point and it's the little details that go a long way. They even write a handwritten note with every package they send because they value their customers and want to make a long lasting relationship. They stand by everything they make, delivering quality, comfort, fit, and style. They also offer free shipping, returns, and exchanges.
Harlestons is also a multi-generational brand carrying boys polos in a size 3T to a men's size XXL. My little friend Luca here is wearing a size 8T and my brother and his sons enjoying testing out the gear before our dinner at Bowens Island. I love that I finally got my brother and nephews in a shoot, they're total naturals and loved wearing these incredibly comfortable polos.
Founders Weston and Cason are hard working professionals who wanted to "upgrade" the basic polo to bring a classy look that could be dressed up or down. No brazen logos on the front chest, just a subtle beautifully embroidered cormorant bird on the upper back of the polos and pullovers. Versatility in clothing is so important these days and with this collection you can take it to work to weekend seamlessly. Leave it untucked for a casual look or tuck it in for a more polished look, and even pair it with a blazer for work and date night. My brother is a busy entrepreneur juggling his chiropractor business during the coaching his son's soccer matches at night and the weekends. This clothing is perfect for his busy lifestyle.
Harlestons Rainbow Row inspired spring collection is underway and includes a new line of pullovers. Two new performance polos will be introduced in a few weeks in Navy & White and Seagrass Green & Blue.
Harlestons cares about their community and found a way to give back while tying in their brand and favorite sport. They have partnered up with The First Tee of Charleston to help shape the lives of youth from all backgrounds by supporting core values such as integrity, perseverance, and respect. They are currently sponsoring 5 children with scholarships and all the golf equipment they need to be successful. They are also excited to support and participate in the virtual and summer on course core programs that First Tee is planning. It's so important for brands to have a charitable component. It's not always about selling products, it's about sharing a message of empowerment, confidence and uplifting others to make a difference in someone's life.
For all of you moms, wives, girlfriends, and partners out there, make it easy on yourself this holiday season and buy him Harlestons. Most guys don't take the time to shop, so do them a favor and scoop up a polo or pullover and support small and local. I've teamed up with Harlestons to offer you 25% off with code ANDREA. Also, watch my segment on Lowcountry Live tomorrow at 10am for my gift guide including Harlestons.
Photos by Liza Malia
Recents Blog Posts
At Home For The Holidays
The Nice List at Citadel Mall
Support Small, Love Big
Shop & Getaway Stay at Bella Grace
At Home With Seawah Furniture
Build a Better Capsule Wardrobe
Merry Little Shop & Stroll at Citadel Mall
Freshfields Finds for the Holidays
Spirits & Spells: How to Halloween
Genres, Topics & Categories
Athletic Wear (7)
Consignment (15)
Men's Formal (17)
First Name Last Name Email address:
@charlestonshopcurator
Copyright © 2021 Charleston Shop Curator

redpajama_set_name: RedPajamaCommonCrawl


text:
Home / Life in the Art World: Life Magazine and Modern American Art
Life in the Art World: Life Magazine and Modern American Art
This is the fourth and final program in the Mid-Century Master lecture series.
LIFE magazine was a champion of American modernism, actively promoting the work of a wide range of twentieth-century artists and architects, including Thomas Hart Benton, Georgia O'Keeffe, Stuart Davis, Jackson Pollock, Robert Rauschenberg, and Frank Lloyd Wright. This lecture will place Alfred Eisenstaedt's photography in the context of both LIFE's commissions and weekly coverage of American art. Looking at the magazine's varied collaborations with artists, architects, curators, and critics, Dr. Renn will show how LIFE magazine shaped both the public and the critical reception of modern art and architecture in the United States.
5:30-6:30 p.m. | Mid-Century Master, mansion, gardens, and greenhouse open for self-guided touring.
6-6:30 p.m. | Members-only wine and cheese reception. Join today!
6:30-7:30 p.m. | Lecture
Melissa Renn is Collections Manager, HBS Art and Artifacts Collection, Harvard Business School. Dr. Renn has published on American art from the 18th to the 20th century, with a specialty in American modernism. She is co-author, with Theodore E. Stebbins, Jr., of American Paintings at Harvard, Volume One: Paintings, Watercolors, and Pastels by Artists Born Before 1826 (2014).
Dr. Renn has published widely on LIFE magazine, including, "Life's Pioneer Painters: Dorothy Seiberling and American Art in Life Magazine, 1949−1968," in Rachel Esner and Sandra Kisters, eds., The Mediatization of the Artist (2018); "'An Enduring Record': Peter Hurd's Art for Life Magazine," in Kirsten M. Jensen, ed., Magical and Real: Henriette Wyeth and Peter Hurd, A Retrospective (2018); "Life in Color: Life Magazine and the Color Reproduction of Works of Art," in Regina Lee Blaszczyk and Uwe Spiekermann, eds., Bright Modernity: Color, Commerce, and Consumer Culture (2017); and "'The Famous Iwo Flag-Raising': Iwo Jima Revisited," in History of Photography (2015). She is the co-author, with Adair Margo, of Tom Lea, Life Magazine, and World War II (2016).
Alfred Eisenstaedt was among a notable group of mid-century photographers who created a cohesive and vibrant understanding of American culture through photography, fine art, and fashion.
October 3 | Women Looking at Women: Life Magazine's Female Photographers and their Images of American Women in the Context of World War II with Alissa Schapiro
October 10 | Mid-Century Muses: Looking at Fashion in the Photography of Alfred Eisenstaedt with Megan J. Martinelli
October 16 | Ultimate Insiders: White House Photographers and How They Shape History with Kenneth T. Walsh
October 24 | Life in the Art World: Life Magazine and Modern American Art with Melissa Renn
Tickets in the Theater are sold out. Additional seating is available in a simulcast location for $5.
Purchase Simulcast