<commit_before>// Copyright 2017 Google, Inc.
//
//  simple JPEG compressor or re-compressor
//
// usage:
//   sjpeg input.{jpg,png} [-o output.jpg] [-q quality]
//
// 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.
//
// Author: Skal (pascal.massimino@gmail.com)
//

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <vector>
using std::vector;

#include "sjpeg.h"
#include "./utils.h"

///////////////////////////////////////////////////////////////////////////////

void PrintMatrix(const char name[], const uint8_t m[64], bool for_chroma) {
  fprintf(stdout, " %s quantization matrix (estimated quality: %d)\n",
          name, SjpegEstimateQuality(m, for_chroma));
  for (int j = 0; j < 8; ++j) {
    for (int i = 0; i < 8; ++i) fprintf(stdout, "%3d ", m[i + j * 8]);
    fprintf(stdout, "\n");
  }
  fprintf(stdout, "------\n");
}

///////////////////////////////////////////////////////////////////////////////

static const char* kYUVModeNames[4] = {
  "automatic", "YUV420", "SharpYUV420", "YUV444"
};
static const char* kNoYes[2] = { "no", "yes" };

int main(int argc, char * argv[]) {
  const char* input_file = NULL;
  const char* output_file = NULL;
  SjpegEncodeParam param;
  int reduction = 100;
  int quality = 75;
  bool use_reduction = true;  // until '-q' is used...
  bool no_metadata = false;
  bool estimate = false;
  bool limit_quantization = true;
  int info = 0;
  bool quiet = false;
  bool short_output = false;
  float riskiness = 0;
  int yuv_mode_rec = 0;
  const char* const usage =
    "sjpeg: Commandline utility to recompress or compress pictures to JPEG.\n"
    "Usage:  sjpeg infile [-o outfile.jpg] [-q quality] ...\n"
    "  -q quality ...... Quality factor in [0..100] range.\n"
    "                    Value of 100 gives the best quality, largest file.\n"
    "                    Default value is 75.\n"
    "  -r reduction .... Reduction factor in [0..100] range.\n"
    "                    Default value is 100. Lower value will reduce the \n"
    "                    file size.\n"
    "  -o filename ..... specifies the output file name.\n"
    "  -size <int> ..... target size\n"
    "  -psnr <float> ... target YUV-PSNR\n"
    "  -estimate ....... Just estimate and print the JPEG source quality.\n"
    "  -i .............. Just print some information about the input file.\n"
    "  -version ........ Print the version and exit.\n"
    "  -quiet .......... Quiet mode. Just save the file.\n"
    "  -short .......... Print shorter 1-line info.\n"
    "\n"
    "Advanced options:\n"
    "  -yuv_mode .......... YUV mode to use:\n"
    "                       0: automatic decision (default)\n"
    "                       1: use YUV 4:2:0\n"
    "                       2: use 'Sharp' YUV 4:2:0 conversion\n"
    "                       3: use YUV 4:4:4 (full resolution for U/V planes)\n"
    "  -no_limit .......... If true, allow the quality factor to be larger\n"
    "                       than the original (JPEG input only).\n"
    "  -no_optim .......... Don't use Huffman optimization (=faster)\n"
    "  -no_adapt .......... Don't use adaptive quantization (=faster)\n"
    "  -trellis ........... use trellis-based quantization (=slower)\n"
    "  -no_metadata ....... Ignore metadata from the source.\n"
    "  -pass <int> ........ number of passes for -size or -psnr (default: 10\n"
    "  -qmin <int> ........ minimum acceptable quality factor during search\n"
    "  -qmax <int> ........ maximum acceptable quality factor during search\n"
    "  -tolerance <float> . tolerance for convergence during search\n"
    "\n"
    "\n"
    "If the input format is JPEG, the recompression will not go beyond the\n"
    "original quality, *except* if '-no_limit' option is used."
    "\n"
  ;

  // parse command line
  if (argc <= 1) {
    fprintf(stderr, usage);
    return 0;
  }
  for (int c = 1; c < argc; ++c) {
    if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "--help")) {
      fprintf(stdout, usage);
      return 0;
    } else if (!strcmp(argv[c], "-o") && c + 1 < argc) {
      output_file = argv[++c];
    } else if (!strcmp(argv[c], "-q") && c + 1 < argc) {
      quality = atoi(argv[++c]);
      use_reduction = false;
      if (quality < 0 || quality > 100) {
        fprintf(stdout, "Error: invalid range for option '%s': %s\n",
                argv[c - 1], argv[c]);
        return 1;
      }
    } else if (!strcmp(argv[c], "-r") && c + 1 < argc) {
      reduction = atoi(argv[++c]);
      use_reduction = true;
      if (reduction <= 0 || reduction > 100) {
        fprintf(stdout, "Error: invalid range for option '%s': %s\n",
                argv[c - 1], argv[c]);
        return 1;
      }
    } else if (!strcmp(argv[c], "-estimate")) {
      estimate = true;
    } else if (!strcmp(argv[c], "-no_limit")) {
      limit_quantization = false;
    } else if (!strcmp(argv[c], "-no_adapt")) {
      param.adaptive_quantization = false;
    } else if (!strcmp(argv[c], "-no_optim")) {
      param.Huffman_compress = false;
    } else if (!strcmp(argv[c], "-adapt_bias")) {
      param.adaptive_bias = true;
    } else if (!strcmp(argv[c], "-trellis")) {
      param.use_trellis = true;
    } else if (!strcmp(argv[c], "-psnr") && c + 1 < argc) {
      param.target_mode = SjpegEncodeParam::TARGET_PSNR;
      param.target_value = atof(argv[++c]);
    } else if (!strcmp(argv[c], "-tolerance")) {
      param.tolerance = atof(argv[++c]);
    } else if (!strcmp(argv[c], "-qmin")) {
      param.qmin = atof(argv[++c]);
    } else if (!strcmp(argv[c], "-qmax")) {
      param.qmax = atof(argv[++c]);
    } else if (!strcmp(argv[c], "-size") && c + 1 < argc) {
      param.target_mode = SjpegEncodeParam::TARGET_SIZE;
      param.target_value = atof(argv[++c]);
    } else if (!strcmp(argv[c], "-pass") && c + 1 < argc) {
      param.passes = atoi(argv[++c]);
    } else if (!strcmp(argv[c], "-no_metadata")) {
      no_metadata = true;
    } else if (!strcmp(argv[c], "-yuv_mode") && c + 1 < argc) {
      param.yuv_mode = atoi(argv[++c]);
      if (param.yuv_mode < 0 || param.yuv_mode > 3) {
        fprintf(stdout, "Error: invalid range for option '%s': %s\n",
                argv[c - 1], argv[c]);
        return 1;
      }
    } else if (!strcmp(argv[c], "-i") || !strcmp(argv[c], "-info")) {
      info = true;
    } else if (!strcmp(argv[c], "-quiet")) {
      quiet = true;
    } else if (!strcmp(argv[c], "-short")) {
      short_output = true;
    } else if (!strcmp(argv[c], "-version")) {
      const uint32_t version = SjpegVersion();
      fprintf(stdout, "%d.%d.%d\n",
              (version >> 16) & 0xff,
              (version >>  8) & 0xff,
              (version >>  0) & 0xff);
      return 0;
    } else {
      input_file = argv[c];
    }
  }
  if (input_file == NULL) {
    fprintf(stderr, "Missing input file.\n");
    if (!quiet) fprintf(stderr, usage);
    return -1;
  }
  // finish param set up
  if (param.target_mode != SjpegEncodeParam::TARGET_NONE && param.passes <= 1) {
    param.passes = 10;
  }
  // Read input file into the buffer in_bytes[]
  std::string input = ReadFile(input_file);
  if (input.size() == 0) return 1;

  const ImageType input_type = GuessImageType(input);
  uint8_t quant_matrices[2][64];
  const int nb_matrices =
    (input_type == SJPEG_JPEG) ? SjpegFindQuantizer(input, quant_matrices)
                               : 0;
  const bool is_jpeg = (input_type == SJPEG_JPEG) && (nb_matrices > 0);
  if (use_reduction && !is_jpeg) {
    if (!quiet && !short_output) {
      fprintf(stdout, "Warning! reduction factor (-r option) disabled"
                      " (only applies to JPEG source).\n");
      fprintf(stdout, "         Please use the -q option to set the"
                      " quality factor.\n\n");
    }
    use_reduction = false;
  }
  if (use_reduction) {   // use 'reduction' factor for JPEG source
    param.SetQuantMatrix(quant_matrices[0], 0, reduction);
    param.SetQuantMatrix(quant_matrices[1], 1, reduction);
    param.SetLimitQuantization(true);
  } else {    // the '-q' option has been used.
    param.SetQuality(quality);
    param.SetLimitQuantization(false);
  }

  if (estimate) {
    const int q = is_jpeg ? SjpegEstimateQuality(quant_matrices[0], 0) : 100;
    fprintf(stdout, "%d\n", q);
    return 0;
  }
  int W, H;
  vector<uint8_t> in_bytes = ReadImage(input, &W, &H, &param);
  if (in_bytes.size() == 0) return 1;

  if (!short_output && !quiet) {
    fprintf(stdout, "Input [%s]: %s (%ld bytes, %d x %d)\n",
            ImageTypeName(input_type), input_file,
            static_cast<long>(input.size()),
            W, H);
    if (info) {
      yuv_mode_rec = SjpegRiskiness(&in_bytes[0], W, H, 3 * W, &riskiness);
      fprintf(stdout, "Riskiness:   %.1f (recommended yuv_mode: %s)\n",
              riskiness, kYUVModeNames[yuv_mode_rec]);

      if (is_jpeg) {
        fprintf(stdout, "Input is JPEG w/ %d matrices:\n", nb_matrices);
        if (nb_matrices > 0) {
          PrintMatrix("Luma", quant_matrices[0], false);
        }
        if (nb_matrices > 1) {
          PrintMatrix("UV-chroma", quant_matrices[1], true);
        }
      }
    }
  }
  if (info) return 0;   // done

  // finish setting up the quantization matrices
  if (limit_quantization == false) param.SetLimitQuantization(false);

  if (no_metadata) param.ResetMetadata();

  const double start = GetStopwatchTime();
  const std::string out = SjpegEncode(&in_bytes[0], W, H, 3 * W, param);
  const double encode_time = GetStopwatchTime() - start;

  if (out.size() == 0) {
    fprintf(stderr, "ERROR: call to SjpegEncode() failed");
    return -1;
  }

  if (!short_output && !quiet) {
    yuv_mode_rec = SjpegRiskiness(&in_bytes[0], W, H, 3 * W, &riskiness);
    fprintf(stdout, "new size:   %ld bytes (%.2lf%% of original)\n"
                    "%s%d (adaptive: %s, Huffman: %s)\n"
                    "yuv mode:   %s (riskiness: %.1lf%%)\n"
                    "elapsed:    %d ms\n",
                    (long)out.size(), 100. * out.size() / input.size(),
                    use_reduction ? "reduction:  r=" : "quality:    q=",
                    use_reduction ? reduction : quality,
                    kNoYes[param.adaptive_quantization],
                    kNoYes[param.Huffman_compress],
                    kYUVModeNames[yuv_mode_rec], riskiness,
                    (int)(1000. * encode_time));
    if (param.iccp.size()) {
      fprintf(stdout, "ICCP:       %ld bytes\n", (long)param.iccp.size());
    }
    if (param.exif.size()) {
      fprintf(stdout, "EXIF:       %ld bytes\n", (long)param.exif.size());
    }
    if (param.xmp.size()) {
      fprintf(stdout, "XMP:        %ld bytes\n", (long)param.xmp.size());
    }
  } else if (!quiet) {
    fprintf(stdout, "%ld %ld %.2lf %%\n",
           static_cast<long>(input.size()), static_cast<long>(out.size()),
           100. * out.size() / input.size());
  }

  // Save the result.
  if (!SaveFile(output_file, out, quiet)) return 1;

  return 0;     // ok.
}

///////////////////////////////////////////////////////////////////////////////
<commit_msg>Add possibility for using special dichotomy hook<commit_after>// Copyright 2017 Google, Inc.
//
//  simple JPEG compressor or re-compressor
//
// usage:
//   sjpeg input.{jpg,png} [-o output.jpg] [-q quality]
//
// 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.
//
// Author: Skal (pascal.massimino@gmail.com)
//

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <vector>
using std::vector;

#include "sjpeg.h"
#include "./utils.h"

///////////////////////////////////////////////////////////////////////////////

void PrintMatrix(const char name[], const uint8_t m[64], bool for_chroma) {
  fprintf(stdout, " %s quantization matrix (estimated quality: %d)\n",
          name, SjpegEstimateQuality(m, for_chroma));
  for (int j = 0; j < 8; ++j) {
    for (int i = 0; i < 8; ++i) fprintf(stdout, "%3d ", m[i + j * 8]);
    fprintf(stdout, "\n");
  }
  fprintf(stdout, "------\n");
}

///////////////////////////////////////////////////////////////////////////////

static const char* kYUVModeNames[4] = {
  "automatic", "YUV420", "SharpYUV420", "YUV444"
};
static const char* kNoYes[2] = { "no", "yes" };

int main(int argc, char * argv[]) {
  const char* input_file = NULL;
  const char* output_file = NULL;
  SjpegEncodeParam param;
  int reduction = 100;
  int quality = 75;
  bool use_reduction = true;  // until '-q' is used...
  bool no_metadata = false;
  bool estimate = false;
  bool limit_quantization = true;
  int info = 0;
  bool quiet = false;
  bool short_output = false;
  float riskiness = 0;
  int yuv_mode_rec = 0;
  const char* const usage =
    "sjpeg: Commandline utility to recompress or compress pictures to JPEG.\n"
    "Usage:  sjpeg infile [-o outfile.jpg] [-q quality] ...\n"
    "  -q quality ...... Quality factor in [0..100] range.\n"
    "                    Value of 100 gives the best quality, largest file.\n"
    "                    Default value is 75.\n"
    "  -r reduction .... Reduction factor in [0..100] range.\n"
    "                    Default value is 100. Lower value will reduce the \n"
    "                    file size.\n"
    "  -o filename ..... specifies the output file name.\n"
    "  -size <int> ..... target size\n"
    "  -psnr <float> ... target YUV-PSNR\n"
    "  -estimate ....... Just estimate and print the JPEG source quality.\n"
    "  -i .............. Just print some information about the input file.\n"
    "  -version ........ Print the version and exit.\n"
    "  -quiet .......... Quiet mode. Just save the file.\n"
    "  -short .......... Print shorter 1-line info.\n"
    "\n"
    "Advanced options:\n"
    "  -yuv_mode .......... YUV mode to use:\n"
    "                       0: automatic decision (default)\n"
    "                       1: use YUV 4:2:0\n"
    "                       2: use 'Sharp' YUV 4:2:0 conversion\n"
    "                       3: use YUV 4:4:4 (full resolution for U/V planes)\n"
    "  -no_limit .......... If true, allow the quality factor to be larger\n"
    "                       than the original (JPEG input only).\n"
    "  -no_optim .......... Don't use Huffman optimization (=faster)\n"
    "  -no_adapt .......... Don't use adaptive quantization (=faster)\n"
    "  -trellis ........... use trellis-based quantization (=slower)\n"
    "  -no_metadata ....... Ignore metadata from the source.\n"
    "  -pass <int> ........ number of passes for -size or -psnr (default: 10\n"
    "  -qmin <int> ........ minimum acceptable quality factor during search\n"
    "  -qmax <int> ........ maximum acceptable quality factor during search\n"
    "  -tolerance <float> . tolerance for convergence during search\n"
    "\n"
    "\n"
    "If the input format is JPEG, the recompression will not go beyond the\n"
    "original quality, *except* if '-no_limit' option is used."
    "\n"
  ;

#if defined(ALT_HOOK_CLASS)
  ALT_HOOK_CLASS hook;
  param.search_hook = &hook;
#endif

  // parse command line
  if (argc <= 1) {
    fprintf(stderr, usage);
    return 0;
  }
  for (int c = 1; c < argc; ++c) {
    if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "--help")) {
      fprintf(stdout, usage);
      return 0;
    } else if (!strcmp(argv[c], "-o") && c + 1 < argc) {
      output_file = argv[++c];
    } else if (!strcmp(argv[c], "-q") && c + 1 < argc) {
      quality = atoi(argv[++c]);
      use_reduction = false;
      if (quality < 0 || quality > 100) {
        fprintf(stdout, "Error: invalid range for option '%s': %s\n",
                argv[c - 1], argv[c]);
        return 1;
      }
    } else if (!strcmp(argv[c], "-r") && c + 1 < argc) {
      reduction = atoi(argv[++c]);
      use_reduction = true;
      if (reduction <= 0 || reduction > 100) {
        fprintf(stdout, "Error: invalid range for option '%s': %s\n",
                argv[c - 1], argv[c]);
        return 1;
      }
    } else if (!strcmp(argv[c], "-estimate")) {
      estimate = true;
    } else if (!strcmp(argv[c], "-no_limit")) {
      limit_quantization = false;
    } else if (!strcmp(argv[c], "-no_adapt")) {
      param.adaptive_quantization = false;
    } else if (!strcmp(argv[c], "-no_optim")) {
      param.Huffman_compress = false;
    } else if (!strcmp(argv[c], "-adapt_bias")) {
      param.adaptive_bias = true;
    } else if (!strcmp(argv[c], "-trellis")) {
      param.use_trellis = true;
    } else if (!strcmp(argv[c], "-psnr") && c + 1 < argc) {
      param.target_mode = SjpegEncodeParam::TARGET_PSNR;
      param.target_value = atof(argv[++c]);
    } else if (!strcmp(argv[c], "-tolerance")) {
      param.tolerance = atof(argv[++c]);
    } else if (!strcmp(argv[c], "-qmin")) {
      param.qmin = atof(argv[++c]);
    } else if (!strcmp(argv[c], "-qmax")) {
      param.qmax = atof(argv[++c]);
    } else if (!strcmp(argv[c], "-size") && c + 1 < argc) {
      param.target_mode = SjpegEncodeParam::TARGET_SIZE;
      param.target_value = atof(argv[++c]);
    } else if (!strcmp(argv[c], "-pass") && c + 1 < argc) {
      param.passes = atoi(argv[++c]);
    } else if (!strcmp(argv[c], "-no_metadata")) {
      no_metadata = true;
    } else if (!strcmp(argv[c], "-yuv_mode") && c + 1 < argc) {
      param.yuv_mode = atoi(argv[++c]);
      if (param.yuv_mode < 0 || param.yuv_mode > 3) {
        fprintf(stdout, "Error: invalid range for option '%s': %s\n",
                argv[c - 1], argv[c]);
        return 1;
      }
    } else if (!strcmp(argv[c], "-i") || !strcmp(argv[c], "-info")) {
      info = true;
    } else if (!strcmp(argv[c], "-quiet")) {
      quiet = true;
    } else if (!strcmp(argv[c], "-short")) {
      short_output = true;
    } else if (!strcmp(argv[c], "-version")) {
      const uint32_t version = SjpegVersion();
      fprintf(stdout, "%d.%d.%d\n",
              (version >> 16) & 0xff,
              (version >>  8) & 0xff,
              (version >>  0) & 0xff);
      return 0;
    } else {
      input_file = argv[c];
    }
  }
  if (input_file == NULL) {
    fprintf(stderr, "Missing input file.\n");
    if (!quiet) fprintf(stderr, usage);
    return -1;
  }
  // finish param set up
  if (param.target_mode != SjpegEncodeParam::TARGET_NONE && param.passes <= 1) {
    param.passes = 10;
  }
  // Read input file into the buffer in_bytes[]
  std::string input = ReadFile(input_file);
  if (input.size() == 0) return 1;

  const ImageType input_type = GuessImageType(input);
  uint8_t quant_matrices[2][64];
  const int nb_matrices =
    (input_type == SJPEG_JPEG) ? SjpegFindQuantizer(input, quant_matrices)
                               : 0;
  const bool is_jpeg = (input_type == SJPEG_JPEG) && (nb_matrices > 0);
  if (use_reduction && !is_jpeg) {
    if (!quiet && !short_output) {
      fprintf(stdout, "Warning! reduction factor (-r option) disabled"
                      " (only applies to JPEG source).\n");
      fprintf(stdout, "         Please use the -q option to set the"
                      " quality factor.\n\n");
    }
    use_reduction = false;
  }
  if (use_reduction) {   // use 'reduction' factor for JPEG source
    param.SetQuantMatrix(quant_matrices[0], 0, reduction);
    param.SetQuantMatrix(quant_matrices[1], 1, reduction);
    param.SetLimitQuantization(true);
  } else {    // the '-q' option has been used.
    param.SetQuality(quality);
    param.SetLimitQuantization(false);
  }

  if (estimate) {
    const int q = is_jpeg ? SjpegEstimateQuality(quant_matrices[0], 0) : 100;
    fprintf(stdout, "%d\n", q);
    return 0;
  }
  int W, H;
  vector<uint8_t> in_bytes = ReadImage(input, &W, &H, &param);
  if (in_bytes.size() == 0) return 1;

  if (!short_output && !quiet) {
    fprintf(stdout, "Input [%s]: %s (%ld bytes, %d x %d)\n",
            ImageTypeName(input_type), input_file,
            static_cast<long>(input.size()),
            W, H);
    if (info) {
      yuv_mode_rec = SjpegRiskiness(&in_bytes[0], W, H, 3 * W, &riskiness);
      fprintf(stdout, "Riskiness:   %.1f (recommended yuv_mode: %s)\n",
              riskiness, kYUVModeNames[yuv_mode_rec]);

      if (is_jpeg) {
        fprintf(stdout, "Input is JPEG w/ %d matrices:\n", nb_matrices);
        if (nb_matrices > 0) {
          PrintMatrix("Luma", quant_matrices[0], false);
        }
        if (nb_matrices > 1) {
          PrintMatrix("UV-chroma", quant_matrices[1], true);
        }
      }
    }
  }
  if (info) return 0;   // done

  // finish setting up the quantization matrices
  if (limit_quantization == false) param.SetLimitQuantization(false);

  if (no_metadata) param.ResetMetadata();

  const double start = GetStopwatchTime();
  const std::string out = SjpegEncode(&in_bytes[0], W, H, 3 * W, param);
  const double encode_time = GetStopwatchTime() - start;

  if (out.size() == 0) {
    fprintf(stderr, "ERROR: call to SjpegEncode() failed");
    return -1;
  }

  if (!short_output && !quiet) {
    yuv_mode_rec = SjpegRiskiness(&in_bytes[0], W, H, 3 * W, &riskiness);
    fprintf(stdout, "new size:   %ld bytes (%.2lf%% of original)\n"
                    "%s%d (adaptive: %s, Huffman: %s)\n"
                    "yuv mode:   %s (riskiness: %.1lf%%)\n"
                    "elapsed:    %d ms\n",
                    (long)out.size(), 100. * out.size() / input.size(),
                    use_reduction ? "reduction:  r=" : "quality:    q=",
                    use_reduction ? reduction : quality,
                    kNoYes[param.adaptive_quantization],
                    kNoYes[param.Huffman_compress],
                    kYUVModeNames[yuv_mode_rec], riskiness,
                    (int)(1000. * encode_time));
    if (param.iccp.size()) {
      fprintf(stdout, "ICCP:       %ld bytes\n", (long)param.iccp.size());
    }
    if (param.exif.size()) {
      fprintf(stdout, "EXIF:       %ld bytes\n", (long)param.exif.size());
    }
    if (param.xmp.size()) {
      fprintf(stdout, "XMP:        %ld bytes\n", (long)param.xmp.size());
    }
  } else if (!quiet) {
    fprintf(stdout, "%ld %ld %.2lf %%\n",
           static_cast<long>(input.size()), static_cast<long>(out.size()),
           100. * out.size() / input.size());
  }

  // Save the result.
  if (!SaveFile(output_file, out, quiet)) return 1;

  return 0;     // ok.
}

///////////////////////////////////////////////////////////////////////////////
<|endoftext|>


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

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/mlir/lite/flatbuffer_operator.h"

#include <vector>

#include "absl/strings/str_cat.h"
#include "flatbuffers/flatbuffers.h"  // from @flatbuffers
#include "flatbuffers/flexbuffers.h"  // from @flatbuffers
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "mlir/IR/Attributes.h"  // from @llvm-project
#include "mlir/IR/Builders.h"  // from @llvm-project
#include "mlir/IR/BuiltinTypes.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/lite/ir/tfl_ops.h"
#include "tensorflow/compiler/mlir/lite/utils/convert_type.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_types.h"
#include "tensorflow/compiler/xla/statusor.h"
#include "tensorflow/core/platform/errors.h"
#include "tensorflow/lite/kernels/internal/kernel_utils.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/schema/schema_utils.h"

namespace {

using ::tensorflow::Status;
using ::tensorflow::errors::InvalidArgument;
using ::xla::StatusOr;

StatusOr<mlir::StringAttr> GetPaddingAttr(TfLitePadding pad_params,
                                          mlir::Builder builder,
                                          mlir::Location loc) {
  auto padding = tflite::Padding::Padding_VALID;
  if (pad_params == TfLitePadding::kTfLitePaddingSame) {
    padding = tflite::Padding_SAME;
  } else if (pad_params == TfLitePadding::kTfLitePaddingValid) {
    padding = tflite::Padding_VALID;
  } else {
    return InvalidArgument(
        absl::StrCat("Invalid padding type", std::to_string(pad_params)));
  }

  const char* option_name = tflite::EnumNamePadding(padding);
  return builder.getStringAttr(option_name);
}

}  // namespace

std::string mlir::GetMlirOpNameFromOpCode(
    const tflite::OperatorCodeT& op_code) {
  auto builtin_code = tflite::GetBuiltinCode(&op_code);
  if (builtin_code == tflite::BuiltinOperator_CUSTOM) {
    return std::string("tfl.custom");
  }
  if (builtin_code == tflite::BuiltinOperator_IF) {
    return std::string("tf.If");
  }
  if (builtin_code == tflite::BuiltinOperator_WHILE) {
    return std::string("tfl.while");
  }

  llvm::StringRef op_name(tflite::EnumNameBuiltinOperator(builtin_code));
  return llvm::Twine("tfl.", op_name.lower()).str();
}

// TODO(jpienaar): This is a placeholder. This should be done in more efficient
// way when part of the translation of module.
static tflite::ActivationFunctionType ConvertTFL_AFAttrForOptionWriter(
    llvm::StringRef str, flatbuffers::FlatBufferBuilder* builder) {
  return llvm::StringSwitch<tflite::ActivationFunctionType>(str)
      .Case("NONE", tflite::ActivationFunctionType_NONE)
      .Case("RELU", tflite::ActivationFunctionType_RELU)
      .Case("RELU_N1_TO_1", tflite::ActivationFunctionType_RELU_N1_TO_1)
      .Case("RELU6", tflite::ActivationFunctionType_RELU6)
      .Case("TANH", tflite::ActivationFunctionType_TANH)
      .Case("SIGN_BIT", tflite::ActivationFunctionType_SIGN_BIT);
}

static tflite::TensorType ConvertDerivedTFLiteTypeAttrForOptionWriter(
    tflite::TensorType type, flatbuffers::FlatBufferBuilder* builder) {
  if (type == tflite::TensorType_INT64) {
    return tflite::TensorType_INT64;
  } else if (type == tflite::TensorType_INT32) {
    return tflite::TensorType_INT32;
  }
  llvm_unreachable("invalid type in conversion.");
}

static tflite::Padding ConvertTFL_PaddingAttrForOptionWriter(
    llvm::StringRef str, flatbuffers::FlatBufferBuilder* builder) {
  return llvm::StringSwitch<tflite::Padding>(str)
      .Case("SAME", tflite::Padding_SAME)
      .Case("VALID", tflite::Padding_VALID);
}

static tflite::MirrorPadMode ConvertTFL_MirrorPaddingAttrForOptionWriter(
    llvm::StringRef str, flatbuffers::FlatBufferBuilder* builder) {
  return llvm::StringSwitch<tflite::MirrorPadMode>(str)
      .Case("REFLECT", tflite::MirrorPadMode_REFLECT)
      .Case("SYMMETRIC", tflite::MirrorPadMode_SYMMETRIC);
}

static tflite::TensorType ConvertDerivedTypeAttrForOptionWriter(
    mlir::Type type, flatbuffers::FlatBufferBuilder* builder) {
  return tflite::ConvertTypeToTensorType(type);
}

// I32Attr already returns an int as required by flatbuffer builders.
static int ConvertI32AttrForOptionWriter(
    int i, flatbuffers::FlatBufferBuilder* builder) {
  return i;
}

static int ConvertPositiveI32AttrForOptionWriter(
    int i, flatbuffers::FlatBufferBuilder* builder) {
  return ConvertI32AttrForOptionWriter(i, builder);
}

static flatbuffers::Offset<flatbuffers::Vector<int32_t>>
ConvertI64ArrayAttrForOptionWriter(mlir::ArrayAttr attrArray,
                                   flatbuffers::FlatBufferBuilder* builder) {
  std::vector<int32_t> intVec;
  intVec.reserve(attrArray.getValue().size());
  for (auto attr : attrArray.getValue()) {
    intVec.push_back(attr.cast<mlir::IntegerAttr>().getInt());
  }
  return builder->CreateVector(intVec);
}

static flatbuffers::Offset<flatbuffers::Vector<float>>
ConvertF32ArrayAttrForOptionWriter(mlir::ArrayAttr attrArray,
                                   flatbuffers::FlatBufferBuilder* builder) {
  std::vector<float> floatVec;
  floatVec.reserve(attrArray.getValue().size());
  for (auto attr : attrArray.getValue()) {
    floatVec.push_back(
        attr.cast<mlir::FloatAttr>().getValue().convertToFloat());
  }
  return builder->CreateVector(floatVec);
}

// F32Attr already returns a float as required by flatbuffer builders.
static float ConvertF32AttrForOptionWriter(
    llvm::APFloat f, flatbuffers::FlatBufferBuilder* builder) {
  return f.convertToFloat();
}

// BoolAttr already returns a bool as required by flatbuffer builders.
static bool ConvertBoolAttrForOptionWriter(
    bool b, flatbuffers::FlatBufferBuilder* builder) {
  return b;
}

static flatbuffers::Offset<flatbuffers::String> ConvertStrAttrForOptionWriter(
    llvm::StringRef str, flatbuffers::FlatBufferBuilder* builder) {
  return builder->CreateString(str.str());
}

static tflite::TensorType ConvertTypeAttrForOptionWriter(
    mlir::Type type, flatbuffers::FlatBufferBuilder* builder) {
  return tflite::ConvertTypeToTensorType(type);
}

static flatbuffers::Offset<flatbuffers::Vector<int32_t>>
ConvertDerivedShapeAttrForOptionWriter(
    llvm::ArrayRef<int64_t> r, flatbuffers::FlatBufferBuilder* builder) {
  std::vector<int> intVec(r.begin(), r.end());
  return builder->CreateVector(intVec);
}

static tflite::FullyConnectedOptionsWeightsFormat
ConvertTFL_FullyConnectedOptionsWeightFormatAttrForOptionWriter(
    llvm::StringRef str, flatbuffers::FlatBufferBuilder* builder) {
  return llvm::StringSwitch<tflite::FullyConnectedOptionsWeightsFormat>(str)
      .Case("DEFAULT", tflite::FullyConnectedOptionsWeightsFormat_DEFAULT)
      .Case("SHUFFLED4x16INT8",
            tflite::FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8);
}

static tflite::LSTMKernelType ConvertTFL_LSTMKernelTypeAttrForOptionWriter(
    llvm::StringRef str, flatbuffers::FlatBufferBuilder* builder) {
  return llvm::StringSwitch<tflite::LSTMKernelType>(str)
      .Case("FULL", tflite::LSTMKernelType_FULL)
      .Case("BASIC", tflite::LSTMKernelType_BASIC);
}

static mlir::Attribute BuildBoolAttr(bool value, mlir::Builder builder) {
  return builder.getBoolAttr(value);
}

static mlir::Attribute BuildStrAttr(llvm::StringRef str,
                                    mlir::Builder builder) {
  return builder.getStringAttr(str);
}

static mlir::Attribute BuildF32Attr(float value, mlir::Builder builder) {
  return builder.getF32FloatAttr(value);
}

static mlir::Attribute BuildI32Attr(int32_t value, mlir::Builder builder) {
  return builder.getI32IntegerAttr(value);
}

static mlir::Attribute BuildI64Attr(int64_t value, mlir::Builder builder) {
  return builder.getI64IntegerAttr(value);
}

static mlir::Attribute BuildI64ArrayAttr(std::vector<int32_t> value,
                                         mlir::Builder builder) {
  std::vector<int64_t> typecast(value.begin(), value.end());
  return builder.getI64ArrayAttr(typecast);
}

static mlir::Attribute BuildF32ArrayAttr(std::vector<float> value,
                                         mlir::Builder builder) {
  std::vector<float> typecast(value.begin(), value.end());
  return builder.getF32ArrayAttr(typecast);
}

static mlir::Attribute BuildPositiveI32Attr(int32_t value,
                                            mlir::Builder builder) {
  return builder.getI32IntegerAttr(value);
}

static mlir::Attribute BuildTypeAttr(tflite::TensorType value,
                                     mlir::Builder builder) {
  return mlir::TypeAttr::get(ConvertElementType(value, builder));
}

static mlir::Attribute BuildTFL_AFAttr(tflite::ActivationFunctionType value,
                                       mlir::Builder builder) {
  const char* option_name = tflite::EnumNameActivationFunctionType(value);
  return builder.getStringAttr(option_name);
}

static mlir::Attribute BuildTFL_FullyConnectedOptionsWeightFormatAttr(
    tflite::FullyConnectedOptionsWeightsFormat value, mlir::Builder builder) {
  const char* option_name =
      tflite::EnumNameFullyConnectedOptionsWeightsFormat(value);
  return builder.getStringAttr(option_name);
}

static mlir::Attribute BuildTFL_LSTMKernelTypeAttr(tflite::LSTMKernelType value,
                                                   mlir::Builder builder) {
  const char* option_name = tflite::EnumNameLSTMKernelType(value);
  return builder.getStringAttr(option_name);
}

static mlir::Attribute BuildTFL_MirrorPaddingAttr(tflite::MirrorPadMode value,
                                                  mlir::Builder builder) {
  const char* option_name = tflite::EnumNameMirrorPadMode(value);
  return builder.getStringAttr(option_name);
}

static mlir::Attribute BuildTFL_PaddingAttr(tflite::Padding value,
                                            mlir::Builder builder) {
  const char* option_name = tflite::EnumNamePadding(value);
  return builder.getStringAttr(option_name);
}

Status mlir::CustomOptionsToAttributes(
    const std::string& custom_code, const std::vector<uint8_t>& custom_options,
    mlir::Builder builder, mlir::Location loc,
    llvm::SmallVectorImpl<mlir::NamedAttribute>* attributes) {
  attributes->emplace_back(
      builder.getNamedAttr("custom_code", builder.getStringAttr(custom_code)));
  std::string content;
  content.assign(reinterpret_cast<const char*>(custom_options.data()),
                 custom_options.size());
  ShapedType type = RankedTensorType::get(
      {static_cast<int64_t>(custom_options.size())}, builder.getIntegerType(8));
  attributes->emplace_back(builder.getNamedAttr(
      "custom_option",
      OpaqueElementsAttr::get(builder.getContext()->getLoadedDialect("tfl"),
                              type, content)));

  return Status::OK();
}

// Pull in FlatBuffer writers for TFLite generated using TableGen
#include "tensorflow/compiler/mlir/lite/operator_converters.inc"
<commit_msg>[Minor fix] Support MLIR Int64Attr for TFLite random built-in ops<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/mlir/lite/flatbuffer_operator.h"

#include <vector>

#include "absl/strings/str_cat.h"
#include "flatbuffers/flatbuffers.h"  // from @flatbuffers
#include "flatbuffers/flexbuffers.h"  // from @flatbuffers
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "mlir/IR/Attributes.h"  // from @llvm-project
#include "mlir/IR/Builders.h"  // from @llvm-project
#include "mlir/IR/BuiltinTypes.h"  // from @llvm-project
#include "tensorflow/compiler/mlir/lite/ir/tfl_ops.h"
#include "tensorflow/compiler/mlir/lite/utils/convert_type.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_types.h"
#include "tensorflow/compiler/xla/statusor.h"
#include "tensorflow/core/platform/errors.h"
#include "tensorflow/lite/kernels/internal/kernel_utils.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/schema/schema_utils.h"

namespace {

using ::tensorflow::Status;
using ::tensorflow::errors::InvalidArgument;
using ::xla::StatusOr;

StatusOr<mlir::StringAttr> GetPaddingAttr(TfLitePadding pad_params,
                                          mlir::Builder builder,
                                          mlir::Location loc) {
  auto padding = tflite::Padding::Padding_VALID;
  if (pad_params == TfLitePadding::kTfLitePaddingSame) {
    padding = tflite::Padding_SAME;
  } else if (pad_params == TfLitePadding::kTfLitePaddingValid) {
    padding = tflite::Padding_VALID;
  } else {
    return InvalidArgument(
        absl::StrCat("Invalid padding type", std::to_string(pad_params)));
  }

  const char* option_name = tflite::EnumNamePadding(padding);
  return builder.getStringAttr(option_name);
}

}  // namespace

std::string mlir::GetMlirOpNameFromOpCode(
    const tflite::OperatorCodeT& op_code) {
  auto builtin_code = tflite::GetBuiltinCode(&op_code);
  if (builtin_code == tflite::BuiltinOperator_CUSTOM) {
    return std::string("tfl.custom");
  }
  if (builtin_code == tflite::BuiltinOperator_IF) {
    return std::string("tf.If");
  }
  if (builtin_code == tflite::BuiltinOperator_WHILE) {
    return std::string("tfl.while");
  }

  llvm::StringRef op_name(tflite::EnumNameBuiltinOperator(builtin_code));
  return llvm::Twine("tfl.", op_name.lower()).str();
}

// TODO(jpienaar): This is a placeholder. This should be done in more efficient
// way when part of the translation of module.
static tflite::ActivationFunctionType ConvertTFL_AFAttrForOptionWriter(
    llvm::StringRef str, flatbuffers::FlatBufferBuilder* builder) {
  return llvm::StringSwitch<tflite::ActivationFunctionType>(str)
      .Case("NONE", tflite::ActivationFunctionType_NONE)
      .Case("RELU", tflite::ActivationFunctionType_RELU)
      .Case("RELU_N1_TO_1", tflite::ActivationFunctionType_RELU_N1_TO_1)
      .Case("RELU6", tflite::ActivationFunctionType_RELU6)
      .Case("TANH", tflite::ActivationFunctionType_TANH)
      .Case("SIGN_BIT", tflite::ActivationFunctionType_SIGN_BIT);
}

static tflite::TensorType ConvertDerivedTFLiteTypeAttrForOptionWriter(
    tflite::TensorType type, flatbuffers::FlatBufferBuilder* builder) {
  if (type == tflite::TensorType_INT64) {
    return tflite::TensorType_INT64;
  } else if (type == tflite::TensorType_INT32) {
    return tflite::TensorType_INT32;
  }
  llvm_unreachable("invalid type in conversion.");
}

static tflite::Padding ConvertTFL_PaddingAttrForOptionWriter(
    llvm::StringRef str, flatbuffers::FlatBufferBuilder* builder) {
  return llvm::StringSwitch<tflite::Padding>(str)
      .Case("SAME", tflite::Padding_SAME)
      .Case("VALID", tflite::Padding_VALID);
}

static tflite::MirrorPadMode ConvertTFL_MirrorPaddingAttrForOptionWriter(
    llvm::StringRef str, flatbuffers::FlatBufferBuilder* builder) {
  return llvm::StringSwitch<tflite::MirrorPadMode>(str)
      .Case("REFLECT", tflite::MirrorPadMode_REFLECT)
      .Case("SYMMETRIC", tflite::MirrorPadMode_SYMMETRIC);
}

static tflite::TensorType ConvertDerivedTypeAttrForOptionWriter(
    mlir::Type type, flatbuffers::FlatBufferBuilder* builder) {
  return tflite::ConvertTypeToTensorType(type);
}

// I32Attr already returns an int as required by flatbuffer builders.
static int ConvertI32AttrForOptionWriter(
    int i, flatbuffers::FlatBufferBuilder* builder) {
  return i;
}

// I64Attr already returns a int64_t as required by flatbuffer builders.
static int64_t ConvertI64AttrForOptionWriter(
    int64_t i, flatbuffers::FlatBufferBuilder* builder) {
  return i;
}

static int ConvertPositiveI32AttrForOptionWriter(
    int i, flatbuffers::FlatBufferBuilder* builder) {
  return ConvertI32AttrForOptionWriter(i, builder);
}

static flatbuffers::Offset<flatbuffers::Vector<int32_t>>
ConvertI64ArrayAttrForOptionWriter(mlir::ArrayAttr attrArray,
                                   flatbuffers::FlatBufferBuilder* builder) {
  std::vector<int32_t> intVec;
  intVec.reserve(attrArray.getValue().size());
  for (auto attr : attrArray.getValue()) {
    intVec.push_back(attr.cast<mlir::IntegerAttr>().getInt());
  }
  return builder->CreateVector(intVec);
}

static flatbuffers::Offset<flatbuffers::Vector<float>>
ConvertF32ArrayAttrForOptionWriter(mlir::ArrayAttr attrArray,
                                   flatbuffers::FlatBufferBuilder* builder) {
  std::vector<float> floatVec;
  floatVec.reserve(attrArray.getValue().size());
  for (auto attr : attrArray.getValue()) {
    floatVec.push_back(
        attr.cast<mlir::FloatAttr>().getValue().convertToFloat());
  }
  return builder->CreateVector(floatVec);
}

// F32Attr already returns a float as required by flatbuffer builders.
static float ConvertF32AttrForOptionWriter(
    llvm::APFloat f, flatbuffers::FlatBufferBuilder* builder) {
  return f.convertToFloat();
}

// BoolAttr already returns a bool as required by flatbuffer builders.
static bool ConvertBoolAttrForOptionWriter(
    bool b, flatbuffers::FlatBufferBuilder* builder) {
  return b;
}

static flatbuffers::Offset<flatbuffers::String> ConvertStrAttrForOptionWriter(
    llvm::StringRef str, flatbuffers::FlatBufferBuilder* builder) {
  return builder->CreateString(str.str());
}

static tflite::TensorType ConvertTypeAttrForOptionWriter(
    mlir::Type type, flatbuffers::FlatBufferBuilder* builder) {
  return tflite::ConvertTypeToTensorType(type);
}

static flatbuffers::Offset<flatbuffers::Vector<int32_t>>
ConvertDerivedShapeAttrForOptionWriter(
    llvm::ArrayRef<int64_t> r, flatbuffers::FlatBufferBuilder* builder) {
  std::vector<int> intVec(r.begin(), r.end());
  return builder->CreateVector(intVec);
}

static tflite::FullyConnectedOptionsWeightsFormat
ConvertTFL_FullyConnectedOptionsWeightFormatAttrForOptionWriter(
    llvm::StringRef str, flatbuffers::FlatBufferBuilder* builder) {
  return llvm::StringSwitch<tflite::FullyConnectedOptionsWeightsFormat>(str)
      .Case("DEFAULT", tflite::FullyConnectedOptionsWeightsFormat_DEFAULT)
      .Case("SHUFFLED4x16INT8",
            tflite::FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8);
}

static tflite::LSTMKernelType ConvertTFL_LSTMKernelTypeAttrForOptionWriter(
    llvm::StringRef str, flatbuffers::FlatBufferBuilder* builder) {
  return llvm::StringSwitch<tflite::LSTMKernelType>(str)
      .Case("FULL", tflite::LSTMKernelType_FULL)
      .Case("BASIC", tflite::LSTMKernelType_BASIC);
}

static mlir::Attribute BuildBoolAttr(bool value, mlir::Builder builder) {
  return builder.getBoolAttr(value);
}

static mlir::Attribute BuildStrAttr(llvm::StringRef str,
                                    mlir::Builder builder) {
  return builder.getStringAttr(str);
}

static mlir::Attribute BuildF32Attr(float value, mlir::Builder builder) {
  return builder.getF32FloatAttr(value);
}

static mlir::Attribute BuildI32Attr(int32_t value, mlir::Builder builder) {
  return builder.getI32IntegerAttr(value);
}

static mlir::Attribute BuildI64Attr(int64_t value, mlir::Builder builder) {
  return builder.getI64IntegerAttr(value);
}

static mlir::Attribute BuildI64ArrayAttr(std::vector<int32_t> value,
                                         mlir::Builder builder) {
  std::vector<int64_t> typecast(value.begin(), value.end());
  return builder.getI64ArrayAttr(typecast);
}

static mlir::Attribute BuildF32ArrayAttr(std::vector<float> value,
                                         mlir::Builder builder) {
  std::vector<float> typecast(value.begin(), value.end());
  return builder.getF32ArrayAttr(typecast);
}

static mlir::Attribute BuildPositiveI32Attr(int32_t value,
                                            mlir::Builder builder) {
  return builder.getI32IntegerAttr(value);
}

static mlir::Attribute BuildTypeAttr(tflite::TensorType value,
                                     mlir::Builder builder) {
  return mlir::TypeAttr::get(ConvertElementType(value, builder));
}

static mlir::Attribute BuildTFL_AFAttr(tflite::ActivationFunctionType value,
                                       mlir::Builder builder) {
  const char* option_name = tflite::EnumNameActivationFunctionType(value);
  return builder.getStringAttr(option_name);
}

static mlir::Attribute BuildTFL_FullyConnectedOptionsWeightFormatAttr(
    tflite::FullyConnectedOptionsWeightsFormat value, mlir::Builder builder) {
  const char* option_name =
      tflite::EnumNameFullyConnectedOptionsWeightsFormat(value);
  return builder.getStringAttr(option_name);
}

static mlir::Attribute BuildTFL_LSTMKernelTypeAttr(tflite::LSTMKernelType value,
                                                   mlir::Builder builder) {
  const char* option_name = tflite::EnumNameLSTMKernelType(value);
  return builder.getStringAttr(option_name);
}

static mlir::Attribute BuildTFL_MirrorPaddingAttr(tflite::MirrorPadMode value,
                                                  mlir::Builder builder) {
  const char* option_name = tflite::EnumNameMirrorPadMode(value);
  return builder.getStringAttr(option_name);
}

static mlir::Attribute BuildTFL_PaddingAttr(tflite::Padding value,
                                            mlir::Builder builder) {
  const char* option_name = tflite::EnumNamePadding(value);
  return builder.getStringAttr(option_name);
}

Status mlir::CustomOptionsToAttributes(
    const std::string& custom_code, const std::vector<uint8_t>& custom_options,
    mlir::Builder builder, mlir::Location loc,
    llvm::SmallVectorImpl<mlir::NamedAttribute>* attributes) {
  attributes->emplace_back(
      builder.getNamedAttr("custom_code", builder.getStringAttr(custom_code)));
  std::string content;
  content.assign(reinterpret_cast<const char*>(custom_options.data()),
                 custom_options.size());
  ShapedType type = RankedTensorType::get(
      {static_cast<int64_t>(custom_options.size())}, builder.getIntegerType(8));
  attributes->emplace_back(builder.getNamedAttr(
      "custom_option",
      OpaqueElementsAttr::get(builder.getContext()->getLoadedDialect("tfl"),
                              type, content)));

  return Status::OK();
}

// Pull in FlatBuffer writers for TFLite generated using TableGen
#include "tensorflow/compiler/mlir/lite/operator_converters.inc"
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: Aaron Kennedy <aaron.kennedy@jollamobile.com>
**
** This file is part of lipstick.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QCoreApplication>
#include <QWaylandCompositor>
#include <QWaylandInputDevice>
#include <QTimer>
#include <sys/types.h>
#include <signal.h>
#include "lipstickcompositor.h"
#include "lipstickcompositorwindow.h"

LipstickCompositorWindow::LipstickCompositorWindow(int windowId, const QString &category,
                                                   QWaylandSurface *surface, QQuickItem *parent)
: QWaylandSurfaceItem(surface, parent), m_windowId(windowId), m_category(category), m_ref(0),
  m_delayRemove(false), m_windowClosed(false), m_removePosted(false), m_mouseRegionValid(false),
  m_interceptingTouch(false)
{
    setFlags(QQuickItem::ItemIsFocusScope | flags());
    refreshMouseRegion();

    // Handle ungrab situations
    connect(this, SIGNAL(visibleChanged()), SLOT(handleTouchCancel()));
    connect(this, SIGNAL(enabledChanged()), SLOT(handleTouchCancel()));
    connect(this, SIGNAL(touchEventsEnabledChanged()), SLOT(handleTouchCancel()));

    connect(this, SIGNAL(surfaceChanged()), SLOT(connectSurfaceSignals()));
    connectSurfaceSignals();
}

QVariant LipstickCompositorWindow::userData() const
{
    return m_data;
}

void LipstickCompositorWindow::setUserData(QVariant data)
{
    if (m_data == data)
        return;

    m_data = data;
    emit userDataChanged();
}

int LipstickCompositorWindow::windowId() const
{
    return m_windowId;
}

qint64 LipstickCompositorWindow::processId() const
{
    if (surface()) return surface()->processId();
    else return 0;
}

bool LipstickCompositorWindow::delayRemove() const
{
    return m_delayRemove;
}

void LipstickCompositorWindow::setDelayRemove(bool delay)
{
    if (delay == m_delayRemove)
        return;

    m_delayRemove = delay;
    emit delayRemoveChanged();

    tryRemove();
}

QString LipstickCompositorWindow::category() const
{
    return m_category;
}

QString LipstickCompositorWindow::title() const
{
    if (surface())
        return surface()->title();
    return QString();
}

void LipstickCompositorWindow::imageAddref()
{
    ++m_ref;
}

void LipstickCompositorWindow::imageRelease()
{
    Q_ASSERT(m_ref);
    --m_ref;
    tryRemove();
}

bool LipstickCompositorWindow::canRemove() const
{
    return m_windowClosed && !m_delayRemove && m_ref == 0;
}

void LipstickCompositorWindow::tryRemove()
{
    if (canRemove() && !m_removePosted) {
        m_removePosted = true;
        QCoreApplication::postEvent(this, new QEvent(QEvent::User));
    }
}

QRect LipstickCompositorWindow::mouseRegionBounds() const
{
    if (m_mouseRegionValid)
        return m_mouseRegion.boundingRect();
    else
        return QRect(0, 0, width(), height());
}

void LipstickCompositorWindow::refreshMouseRegion()
{
    QWaylandSurface *s = surface();
    if (s) {
        QVariantMap properties = s->windowProperties();
        if (properties.contains(QLatin1String("MOUSE_REGION"))) {
            m_mouseRegion = s->windowProperties().value("MOUSE_REGION").value<QRegion>();
            m_mouseRegionValid = true;
            if (LipstickCompositor::instance()->debug())
                qDebug() << "Window" << windowId() << "mouse region set:" << m_mouseRegion;
        } else {
            m_mouseRegionValid = false;
            if (LipstickCompositor::instance()->debug())
                qDebug() << "Window" << windowId() << "mouse region cleared";
        }

        emit mouseRegionBoundsChanged();
    }
}

void LipstickCompositorWindow::refreshGrabbedKeys()
{
    QWaylandSurface *s = surface();
    if (s) {
        const QStringList grabbedKeys = s->windowProperties().value(
                    QLatin1String("GRABBED_KEYS")).value<QStringList>();

        if (m_grabbedKeys.isEmpty() && !grabbedKeys.isEmpty()) {
            qApp->installEventFilter(this);
        } else if (!m_grabbedKeys.isEmpty() && grabbedKeys.isEmpty()) {
            qApp->removeEventFilter(this);
        }

        m_grabbedKeys.clear();
        foreach (const QString &key, grabbedKeys)
            m_grabbedKeys.append(key.toInt());

        if (LipstickCompositor::instance()->debug())
            qDebug() << "Window" << windowId() << "grabbed keys changed:" << grabbedKeys;
    }
}

bool LipstickCompositorWindow::eventFilter(QObject *obj, QEvent *event)
{
#if QT_VERSION >= 0x050202
    if (obj == window() && m_interceptingTouch) {
        switch (event->type()) {
        case QEvent::TouchUpdate: {
            QTouchEvent *te = static_cast<QTouchEvent *>(event);
            // If we get press/release, don't intercept the event, but send it through QQuickWindow.
            // These are sent through to QQuickWindow so that the integrity of the touch
            // handling is maintained.
            if (te->touchPointStates() & (Qt::TouchPointPressed | Qt::TouchPointReleased))
                return false;
            handleTouchEvent(static_cast<QTouchEvent *>(event));
            return true;
        }
        case QEvent::TouchEnd: // Intentional fall through...
        case QEvent::TouchCancel:
            obj->removeEventFilter(this);
            m_interceptingTouch = false;
        default:
            break;
        }
        return false;
    }
#else
    Q_UNUSED(obj);
#endif
    if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        QWaylandSurface *m_surface = surface();
        if (m_surface && m_grabbedKeys.contains(ke->key())) {
            QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
            inputDevice->sendFullKeyEvent(m_surface, ke);

            return true;
        }
    }
    return false;
}

bool LipstickCompositorWindow::isInProcess() const
{
    return false;
}

bool LipstickCompositorWindow::event(QEvent *e)
{
    bool rv = QWaylandSurfaceItem::event(e);
    if (e->type() == QEvent::User) {
        m_removePosted = false;
        if (canRemove()) delete this;
    }
    return rv;
}

void LipstickCompositorWindow::mousePressEvent(QMouseEvent *event)
{
    QWaylandSurface *m_surface = surface();
    if (m_surface && (!m_mouseRegionValid || m_mouseRegion.contains(event->pos()))) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        if (inputDevice->mouseFocus() != m_surface)
            inputDevice->setMouseFocus(m_surface, event->pos(), event->globalPos());
        inputDevice->sendMousePressEvent(event->button(), event->pos(), event->globalPos());
    } else {
        event->ignore();
    }
}

void LipstickCompositorWindow::mouseMoveEvent(QMouseEvent *event)
{
    QWaylandSurface *m_surface = surface();
    if (m_surface){
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendMouseMoveEvent(m_surface, event->pos(), event->globalPos());
    } else {
        event->ignore();
    }
}

void LipstickCompositorWindow::mouseReleaseEvent(QMouseEvent *event)
{
    QWaylandSurface *m_surface = surface();
    if (m_surface){
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendMouseReleaseEvent(event->button(), event->pos(), event->globalPos());
    } else {
        event->ignore();
    }
}

void LipstickCompositorWindow::wheelEvent(QWheelEvent *event)
{
    QWaylandSurface *m_surface = surface();
    if (m_surface) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendMouseWheelEvent(event->orientation(), event->delta());
    } else {
        event->ignore();
    }
}

void LipstickCompositorWindow::touchEvent(QTouchEvent *event)
{
    if (touchEventsEnabled() && surface()) {
        handleTouchEvent(event);

#if QT_VERSION >= 0x050202
        static bool lipstick_touch_interception = qEnvironmentVariableIsEmpty("LIPSTICK_NO_TOUCH_INTERCEPTION");
        if (lipstick_touch_interception && event->type() == QEvent::TouchBegin) {
            // On TouchBegin, start intercepting
            if (event->isAccepted() && !m_interceptingTouch) {
                m_interceptingTouch = true;
                window()->installEventFilter(this);
            }
        }
#endif
    } else {
        event->ignore();
    }
}

void LipstickCompositorWindow::handleTouchEvent(QTouchEvent *event)
{
    QList<QTouchEvent::TouchPoint> points = event->touchPoints();

    if (m_mouseRegionValid && points.count() == 1 &&
        event->touchPointStates() & Qt::TouchPointPressed &&
        !m_mouseRegion.contains(points.at(0).pos().toPoint())) {
        event->ignore();
        return;
    }

    QWaylandSurface *m_surface = surface();
    QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
    event->accept();
    if (inputDevice->mouseFocus() != m_surface) {
        QPoint pointPos;
        if (!points.isEmpty())
            pointPos = points.at(0).pos().toPoint();
        inputDevice->setMouseFocus(m_surface, pointPos, pointPos);
    }
    inputDevice->sendFullTouchEvent(event);
}

void LipstickCompositorWindow::handleTouchCancel()
{
    QWaylandSurface *m_surface = surface();
    if (!m_surface)
        return;
    QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
    if (inputDevice->mouseFocus() == m_surface &&
            (!isVisible() || !isEnabled() || !touchEventsEnabled())) {
        inputDevice->sendTouchCancelEvent();
        inputDevice->setMouseFocus(0, QPointF());
    }
}

void LipstickCompositorWindow::terminateProcess(int killTimeout)
{
    kill(processId(), SIGTERM);

    QTimer::singleShot(killTimeout, this, SLOT(killProcess()));
}

void LipstickCompositorWindow::killProcess()
{
    kill(processId(), SIGKILL);
}

void LipstickCompositorWindow::connectSurfaceSignals()
{
    foreach (const QMetaObject::Connection &connection, m_surfaceConnections) {
        disconnect(connection);
    }

    m_surfaceConnections.clear();
    if (surface()) {
        m_surfaceConnections << connect(surface(), SIGNAL(titleChanged()), SIGNAL(titleChanged()));
    }
}
<commit_msg>[lipstick] Guard against using a null surface<commit_after>/***************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: Aaron Kennedy <aaron.kennedy@jollamobile.com>
**
** This file is part of lipstick.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QCoreApplication>
#include <QWaylandCompositor>
#include <QWaylandInputDevice>
#include <QTimer>
#include <sys/types.h>
#include <signal.h>
#include "lipstickcompositor.h"
#include "lipstickcompositorwindow.h"

LipstickCompositorWindow::LipstickCompositorWindow(int windowId, const QString &category,
                                                   QWaylandSurface *surface, QQuickItem *parent)
: QWaylandSurfaceItem(surface, parent), m_windowId(windowId), m_category(category), m_ref(0),
  m_delayRemove(false), m_windowClosed(false), m_removePosted(false), m_mouseRegionValid(false),
  m_interceptingTouch(false)
{
    setFlags(QQuickItem::ItemIsFocusScope | flags());
    refreshMouseRegion();

    // Handle ungrab situations
    connect(this, SIGNAL(visibleChanged()), SLOT(handleTouchCancel()));
    connect(this, SIGNAL(enabledChanged()), SLOT(handleTouchCancel()));
    connect(this, SIGNAL(touchEventsEnabledChanged()), SLOT(handleTouchCancel()));

    connect(this, SIGNAL(surfaceChanged()), SLOT(connectSurfaceSignals()));
    connectSurfaceSignals();
}

QVariant LipstickCompositorWindow::userData() const
{
    return m_data;
}

void LipstickCompositorWindow::setUserData(QVariant data)
{
    if (m_data == data)
        return;

    m_data = data;
    emit userDataChanged();
}

int LipstickCompositorWindow::windowId() const
{
    return m_windowId;
}

qint64 LipstickCompositorWindow::processId() const
{
    if (surface()) return surface()->processId();
    else return 0;
}

bool LipstickCompositorWindow::delayRemove() const
{
    return m_delayRemove;
}

void LipstickCompositorWindow::setDelayRemove(bool delay)
{
    if (delay == m_delayRemove)
        return;

    m_delayRemove = delay;
    emit delayRemoveChanged();

    tryRemove();
}

QString LipstickCompositorWindow::category() const
{
    return m_category;
}

QString LipstickCompositorWindow::title() const
{
    if (surface())
        return surface()->title();
    return QString();
}

void LipstickCompositorWindow::imageAddref()
{
    ++m_ref;
}

void LipstickCompositorWindow::imageRelease()
{
    Q_ASSERT(m_ref);
    --m_ref;
    tryRemove();
}

bool LipstickCompositorWindow::canRemove() const
{
    return m_windowClosed && !m_delayRemove && m_ref == 0;
}

void LipstickCompositorWindow::tryRemove()
{
    if (canRemove() && !m_removePosted) {
        m_removePosted = true;
        QCoreApplication::postEvent(this, new QEvent(QEvent::User));
    }
}

QRect LipstickCompositorWindow::mouseRegionBounds() const
{
    if (m_mouseRegionValid)
        return m_mouseRegion.boundingRect();
    else
        return QRect(0, 0, width(), height());
}

void LipstickCompositorWindow::refreshMouseRegion()
{
    QWaylandSurface *s = surface();
    if (s) {
        QVariantMap properties = s->windowProperties();
        if (properties.contains(QLatin1String("MOUSE_REGION"))) {
            m_mouseRegion = s->windowProperties().value("MOUSE_REGION").value<QRegion>();
            m_mouseRegionValid = true;
            if (LipstickCompositor::instance()->debug())
                qDebug() << "Window" << windowId() << "mouse region set:" << m_mouseRegion;
        } else {
            m_mouseRegionValid = false;
            if (LipstickCompositor::instance()->debug())
                qDebug() << "Window" << windowId() << "mouse region cleared";
        }

        emit mouseRegionBoundsChanged();
    }
}

void LipstickCompositorWindow::refreshGrabbedKeys()
{
    QWaylandSurface *s = surface();
    if (s) {
        const QStringList grabbedKeys = s->windowProperties().value(
                    QLatin1String("GRABBED_KEYS")).value<QStringList>();

        if (m_grabbedKeys.isEmpty() && !grabbedKeys.isEmpty()) {
            qApp->installEventFilter(this);
        } else if (!m_grabbedKeys.isEmpty() && grabbedKeys.isEmpty()) {
            qApp->removeEventFilter(this);
        }

        m_grabbedKeys.clear();
        foreach (const QString &key, grabbedKeys)
            m_grabbedKeys.append(key.toInt());

        if (LipstickCompositor::instance()->debug())
            qDebug() << "Window" << windowId() << "grabbed keys changed:" << grabbedKeys;
    }
}

bool LipstickCompositorWindow::eventFilter(QObject *obj, QEvent *event)
{
#if QT_VERSION >= 0x050202
    if (obj == window() && m_interceptingTouch) {
        switch (event->type()) {
        case QEvent::TouchUpdate: {
            QTouchEvent *te = static_cast<QTouchEvent *>(event);
            // If we get press/release, don't intercept the event, but send it through QQuickWindow.
            // These are sent through to QQuickWindow so that the integrity of the touch
            // handling is maintained.
            if (te->touchPointStates() & (Qt::TouchPointPressed | Qt::TouchPointReleased))
                return false;
            handleTouchEvent(static_cast<QTouchEvent *>(event));
            return true;
        }
        case QEvent::TouchEnd: // Intentional fall through...
        case QEvent::TouchCancel:
            obj->removeEventFilter(this);
            m_interceptingTouch = false;
        default:
            break;
        }
        return false;
    }
#else
    Q_UNUSED(obj);
#endif
    if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        QWaylandSurface *m_surface = surface();
        if (m_surface && m_grabbedKeys.contains(ke->key())) {
            QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
            inputDevice->sendFullKeyEvent(m_surface, ke);

            return true;
        }
    }
    return false;
}

bool LipstickCompositorWindow::isInProcess() const
{
    return false;
}

bool LipstickCompositorWindow::event(QEvent *e)
{
    bool rv = QWaylandSurfaceItem::event(e);
    if (e->type() == QEvent::User) {
        m_removePosted = false;
        if (canRemove()) delete this;
    }
    return rv;
}

void LipstickCompositorWindow::mousePressEvent(QMouseEvent *event)
{
    QWaylandSurface *m_surface = surface();
    if (m_surface && (!m_mouseRegionValid || m_mouseRegion.contains(event->pos()))) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        if (inputDevice->mouseFocus() != m_surface)
            inputDevice->setMouseFocus(m_surface, event->pos(), event->globalPos());
        inputDevice->sendMousePressEvent(event->button(), event->pos(), event->globalPos());
    } else {
        event->ignore();
    }
}

void LipstickCompositorWindow::mouseMoveEvent(QMouseEvent *event)
{
    QWaylandSurface *m_surface = surface();
    if (m_surface){
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendMouseMoveEvent(m_surface, event->pos(), event->globalPos());
    } else {
        event->ignore();
    }
}

void LipstickCompositorWindow::mouseReleaseEvent(QMouseEvent *event)
{
    QWaylandSurface *m_surface = surface();
    if (m_surface){
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendMouseReleaseEvent(event->button(), event->pos(), event->globalPos());
    } else {
        event->ignore();
    }
}

void LipstickCompositorWindow::wheelEvent(QWheelEvent *event)
{
    QWaylandSurface *m_surface = surface();
    if (m_surface) {
        QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
        inputDevice->sendMouseWheelEvent(event->orientation(), event->delta());
    } else {
        event->ignore();
    }
}

void LipstickCompositorWindow::touchEvent(QTouchEvent *event)
{
    if (touchEventsEnabled() && surface()) {
        handleTouchEvent(event);

#if QT_VERSION >= 0x050202
        static bool lipstick_touch_interception = qEnvironmentVariableIsEmpty("LIPSTICK_NO_TOUCH_INTERCEPTION");
        if (lipstick_touch_interception && event->type() == QEvent::TouchBegin) {
            // On TouchBegin, start intercepting
            if (event->isAccepted() && !m_interceptingTouch) {
                m_interceptingTouch = true;
                window()->installEventFilter(this);
            }
        }
#endif
    } else {
        event->ignore();
    }
}

void LipstickCompositorWindow::handleTouchEvent(QTouchEvent *event)
{
    QList<QTouchEvent::TouchPoint> points = event->touchPoints();

    if (m_mouseRegionValid && points.count() == 1 &&
        event->touchPointStates() & Qt::TouchPointPressed &&
        !m_mouseRegion.contains(points.at(0).pos().toPoint())) {
        event->ignore();
        return;
    }

    QWaylandSurface *m_surface = surface();
    if (!m_surface) {
        event->ignore();
        return;
    }
    QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
    event->accept();
    if (inputDevice->mouseFocus() != m_surface) {
        QPoint pointPos;
        if (!points.isEmpty())
            pointPos = points.at(0).pos().toPoint();
        inputDevice->setMouseFocus(m_surface, pointPos, pointPos);
    }
    inputDevice->sendFullTouchEvent(event);
}

void LipstickCompositorWindow::handleTouchCancel()
{
    QWaylandSurface *m_surface = surface();
    if (!m_surface)
        return;
    QWaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
    if (inputDevice->mouseFocus() == m_surface &&
            (!isVisible() || !isEnabled() || !touchEventsEnabled())) {
        inputDevice->sendTouchCancelEvent();
        inputDevice->setMouseFocus(0, QPointF());
    }
}

void LipstickCompositorWindow::terminateProcess(int killTimeout)
{
    kill(processId(), SIGTERM);

    QTimer::singleShot(killTimeout, this, SLOT(killProcess()));
}

void LipstickCompositorWindow::killProcess()
{
    kill(processId(), SIGKILL);
}

void LipstickCompositorWindow::connectSurfaceSignals()
{
    foreach (const QMetaObject::Connection &connection, m_surfaceConnections) {
        disconnect(connection);
    }

    m_surfaceConnections.clear();
    if (surface()) {
        m_surfaceConnections << connect(surface(), SIGNAL(titleChanged()), SIGNAL(titleChanged()));
    }
}
<|endoftext|>


<commit_before>
#include "core/deep_flow.h"
#include "core/session.h"

#include <gflags/gflags.h>

DEFINE_string(mnist, "./data/mnist", "Path to MNIST data folder");
DEFINE_string(image1, "D:/Projects/deepflow/data/image/lena-256x256.jpg", "Input test image");
DEFINE_string(image2, "D:/Projects/deepflow/data/style_transfer/sanfrancisco.jpg", "Another input test image");
DEFINE_string(model, "D:/Projects/deepflow/models/VGG_ILSVRC_16_layers.caffemodel", "Caffe model to load");

DEFINE_string(i, "", "Trained network model to load");
DEFINE_string(o, "", "Trained network model to save");
DEFINE_bool(text, false, "Save model as text");
DEFINE_bool(includeweights, false, "Also save weights in text mode");
DEFINE_bool(includeinits, false, "Also save initial values");
DEFINE_int32(batch, 100, "Batch size");
DEFINE_string(run,"", "Phase to execute graph");
DEFINE_bool(printiter, false, "Print iteration message");
DEFINE_bool(printepoch, true, "Print epoch message");
DEFINE_int32(debug, 0, "Level of debug");
DEFINE_int32(epoch, 1000, "Maximum epochs");
DEFINE_int32(iter, -1, "Maximum iterations");
DEFINE_bool(cpp, false, "Print C++ code");
DEFINE_bool(x1, false, "Eucliean image reconstruction");
DEFINE_bool(x2, false, "Transposed convolution gray image reconstruction");
DEFINE_bool(x3, false, "Transposed convolution color image reconstruction");
DEFINE_bool(x4, false, "Random selector double image reconstruction");
DEFINE_bool(x5, false, "Test of image_batch_reader");
DEFINE_bool(x6, false, "Test reading caffe model");
DEFINE_bool(x7, false, "Test convolution forward with bias");
DEFINE_bool(x8, false, "Test color image display");

void main(int argc, char** argv) {
	gflags::ParseCommandLineFlags(&argc, &argv, true);

	CudaHelper::setOptimalThreadsPerBlock();

	int batch_size = FLAGS_batch;

	DeepFlow df;

	if (FLAGS_i.empty()) {
		if (FLAGS_x1) {
			auto train = df.define_train_phase("Train");
			auto solver = df.gain_solver(1.0f, 0.01f, 100, 0.000000001f, 0.05f, 0.95f);
			auto image = df.image_reader(FLAGS_image1, deepflow::ImageReaderParam_Type_COLOR_IF_AVAILABLE);
			auto generator = df.data_generator(df.random_uniform({ 1, 3, 256, 256 }, -1, 1), 1, solver, "gen");
			df.euclidean_loss(generator, image);
			df.display(image, 2, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "input", { train });
			df.display(generator, 2, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "approximation", { train });
			df.psnr(image, generator, DeepFlow::EVERY_PASS);
		}
		else if (FLAGS_x2) {
			auto train = df.define_train_phase("Train");
			auto solver = df.gain_solver(0.999f, 0.0001f, 100, 0.000000001f, 0.05f, 0.95f);
			auto image = df.image_reader(FLAGS_image1, deepflow::ImageReaderParam_Type_GRAY_ONLY, "image");
			auto recon = df.variable(df.step({ 1,1,256,256 }, 0, 1), solver, "recon");
			auto f1 = df.variable(df.step({ 11,1,5,5 }, 0, 1), "" , "w");
			auto conv = df.conv2d(image, f1, "", 2, 2, 1, 1, 1, 1);
			auto f2 = df.variable(df.step({ 1,11,5,5 }, 0, 1), "", "w");
			auto tconv = df.transposed_conv2d(recon, f2, 2, 2, 1, 1, 1, 1);
			df.euclidean_loss(conv, tconv);
			df.display(recon, 20, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "input", { train });
			df.psnr(recon, image, DeepFlow::EVERY_PASS, "psnr", { train });
		}
		else if (FLAGS_x3) {
			auto train = df.define_train_phase("Train");
			//auto solver = df.gain_solver(0.999f, 0.0001f, 100, 0.000000001f, 0.05f, 0.95f);
			auto solver = df.adadelta_solver(0.01f);
			auto image = df.image_reader(FLAGS_image1, deepflow::ImageReaderParam_Type_COLOR_IF_AVAILABLE, "image");
			auto recon = df.variable(df.random_uniform({ 1,3,256,256 }, 0, 1), solver, "recon");
			auto f1 = df.data_generator(df.random_uniform({ 1,3,3,3 }, -1, 1), 11, "", "f1");
			auto f2 = df.reshape(f1, { 3, 1, 3, 3 });
			auto conv = df.conv2d(image, f1, "", 1, 1, 1, 1, 1, 1);
			auto tconv = df.transposed_conv2d(recon, f2, 1, 1, 1, 1, 1, 1);
			df.euclidean_loss(tconv, conv);
			df.display(recon, 5, DeepFlow::END_OF_EPOCH, DeepFlow::VALUES, "input", { train });
			df.psnr(recon, image, DeepFlow::EVERY_PASS, "psnr", { train });
		}
		else if (FLAGS_x4) {
			auto train = df.define_train_phase("Train");
			auto solver = df.gain_solver(1.0f, 0.01f, 100, 0.000000001f, 0.05f, 0.95f);
			auto image = df.image_reader(FLAGS_image1, deepflow::ImageReaderParam_Type_COLOR_IF_AVAILABLE);
			auto generator1 = df.data_generator(df.random_uniform({ 1, 3, 256, 256 }, -0.1, 0.1), 1, solver, "gen1");
			auto generator2 = df.data_generator(df.random_normal({ 1, 3, 256, 256 }, 0, 0.1), 1, solver, "gen2");
			auto selector = df.random_selector(generator1, generator2, 0.5);
			df.euclidean_loss(selector, image);
			df.display(generator1, 2, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "approx1", { train });
			df.display(generator2, 2, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "approx2", { train });
		}
		else if (FLAGS_x5) {
			auto train = df.define_train_phase("Train");
			auto imbar = df.image_batch_reader("./data/face", { 1, 1, 27, 18 });
			df.display(imbar, 1000, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "approx1", { train });
		}
		else if (FLAGS_x6) {
			df.load_from_caffe_model(FLAGS_model, { std::pair<std::string, std::array<int,4>>("data", {4,3,224,224}) }, FLAGS_debug > 0);
			df.block()->remove_node_params({ "fc6_ip", "fc6_w", "fc6_b", "fc7_w", "fc7_b", "fc8_w", "fc8_b" });
			auto train = df.define_train_phase("Train");
			auto solver = df.gain_solver(1.0f, 0.01f, 100, 0.000000001f, 0.05f, 0.95f);
			df.block()->set_solver_for_variable_params(solver, {});
			df.block()->set_phase_for_node_params( train, {});
		}
		else if (FLAGS_x7) {
			auto train = df.define_train_phase("Train");
			auto image = df.image_reader(FLAGS_image1, deepflow::ImageReaderParam_Type_COLOR_IF_AVAILABLE);
			auto b = df.variable(df.zeros({ 1,3,1,1 }), "", "b", {});
			auto f = df.variable(df.ones({ 3,3,5,5 }), "", "f", {});
			auto conv = df.conv2d(image, f, b, "conv");
			df.display(conv, 20, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "input", { train });
		}
		else if (FLAGS_x8) {
			auto train = df.define_train_phase("Train");
			auto image = df.image_reader(FLAGS_image1, deepflow::ImageReaderParam_Type_COLOR_IF_AVAILABLE);
			df.display(image, 10000, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "input", { train });
		}
	}
	else {
		df.block()->load_from_binary(FLAGS_i);
	}

	if (FLAGS_debug > 0) {
		df.block()->print_node_params();
		df.block()->print_phase_params();
	}

	auto session = df.session();

	if (FLAGS_cpp) {
		session->initialize();
		std::cout << session->to_cpp() << std::endl;
		if (FLAGS_debug == 1) {
			session->printMemory();
		}
	}

	if (!FLAGS_run.empty()) {
		session->initialize();
		session->run(FLAGS_run, FLAGS_epoch, FLAGS_iter, FLAGS_printiter, FLAGS_printepoch, FLAGS_debug);
	}

	if (!FLAGS_o.empty())
	{
		if (FLAGS_text)
			df.block()->save_as_text(FLAGS_o);
		else
			df.block()->save_as_binary(FLAGS_o);
	}

}

<commit_msg>Improved color image reconstruction example<commit_after>
#include "core/deep_flow.h"
#include "core/session.h"

#include <gflags/gflags.h>

DEFINE_string(mnist, "./data/mnist", "Path to MNIST data folder");
DEFINE_string(image1, "D:/Projects/deepflow/data/image/lena-256x256.jpg", "Input test image");
DEFINE_string(image2, "D:/Projects/deepflow/data/style_transfer/sanfrancisco.jpg", "Another input test image");
DEFINE_string(model, "D:/Projects/deepflow/models/VGG_ILSVRC_16_layers.caffemodel", "Caffe model to load");

DEFINE_string(i, "", "Trained network model to load");
DEFINE_string(o, "", "Trained network model to save");
DEFINE_bool(text, false, "Save model as text");
DEFINE_bool(includeweights, false, "Also save weights in text mode");
DEFINE_bool(includeinits, false, "Also save initial values");
DEFINE_int32(batch, 100, "Batch size");
DEFINE_string(run,"", "Phase to execute graph");
DEFINE_bool(printiter, false, "Print iteration message");
DEFINE_bool(printepoch, true, "Print epoch message");
DEFINE_int32(debug, 0, "Level of debug");
DEFINE_int32(epoch, 1000, "Maximum epochs");
DEFINE_int32(iter, -1, "Maximum iterations");
DEFINE_bool(cpp, false, "Print C++ code");
DEFINE_bool(x1, false, "Eucliean image reconstruction");
DEFINE_bool(x2, false, "Transposed convolution gray image reconstruction");
DEFINE_bool(x3, false, "Transposed convolution color image reconstruction");
DEFINE_bool(x4, false, "Random selector double image reconstruction");
DEFINE_bool(x5, false, "Test of image_batch_reader");
DEFINE_bool(x6, false, "Test reading caffe model");
DEFINE_bool(x7, false, "Test convolution forward with bias");
DEFINE_bool(x8, false, "Test color image display");

void main(int argc, char** argv) {
	gflags::ParseCommandLineFlags(&argc, &argv, true);

	CudaHelper::setOptimalThreadsPerBlock();

	int batch_size = FLAGS_batch;

	DeepFlow df;

	if (FLAGS_i.empty()) {
		if (FLAGS_x1) {
			auto train = df.define_train_phase("Train");
			auto solver = df.gain_solver(1.0f, 0.01f, 100, 0.000000001f, 0.05f, 0.95f);
			auto image = df.image_reader(FLAGS_image1, deepflow::ImageReaderParam_Type_COLOR_IF_AVAILABLE);
			auto generator = df.data_generator(df.random_uniform({ 1, 3, 256, 256 }, -1, 1), 1, solver, "gen");
			df.euclidean_loss(generator, image);
			df.display(image, 2, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "input", { train });
			df.display(generator, 2, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "approximation", { train });
			df.psnr(image, generator, DeepFlow::EVERY_PASS);
		}
		else if (FLAGS_x2) {
			auto train = df.define_train_phase("Train");
			auto solver = df.gain_solver(0.999f, 0.0001f, 100, 0.000000001f, 0.05f, 0.95f);
			auto image = df.image_reader(FLAGS_image1, deepflow::ImageReaderParam_Type_GRAY_ONLY, "image");
			auto recon = df.variable(df.step({ 1,1,256,256 }, 0, 1), solver, "recon");
			auto f1 = df.variable(df.step({ 11,1,5,5 }, 0, 1), "" , "w");
			auto conv = df.conv2d(image, f1, "", 2, 2, 1, 1, 1, 1);
			auto f2 = df.variable(df.step({ 1,11,5,5 }, 0, 1), "", "w");
			auto tconv = df.transposed_conv2d(recon, f2, 2, 2, 1, 1, 1, 1);
			df.euclidean_loss(conv, tconv);
			df.display(recon, 20, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "input", { train });
			df.psnr(recon, image, DeepFlow::EVERY_PASS, "psnr", { train });
		}
		else if (FLAGS_x3) {
			auto train = df.define_train_phase("Train");
			auto solver = df.adadelta_solver(0.05f);
			auto image = df.image_reader(FLAGS_image1, deepflow::ImageReaderParam_Type_COLOR_IF_AVAILABLE, "image");
			auto recon = df.variable(df.random_uniform({ 1,3,256,256 }, 0, 1), solver, "recon");
			auto f1 = df.data_generator(df.random_uniform({ 1,3,3,3 }, -1, 1), 1, "", "f1");
			auto f2 = df.reshape(f1, { 3, 1, 3, 3 });
			auto conv = df.conv2d(image, f1, "", 1, 1, 1, 1, 1, 1);
			auto tconv = df.transposed_conv2d(recon, f2, 1, 1, 1, 1, 1, 1);
			df.euclidean_loss(tconv, conv);
			df.display(recon, 5, DeepFlow::END_OF_EPOCH, DeepFlow::VALUES, "input", { train });
			df.psnr(recon, image, DeepFlow::EVERY_PASS, "psnr", { train });
		}
		else if (FLAGS_x4) {
			auto train = df.define_train_phase("Train");
			auto solver = df.gain_solver(1.0f, 0.01f, 100, 0.000000001f, 0.05f, 0.95f);
			auto image = df.image_reader(FLAGS_image1, deepflow::ImageReaderParam_Type_COLOR_IF_AVAILABLE);
			auto generator1 = df.data_generator(df.random_uniform({ 1, 3, 256, 256 }, -0.1, 0.1), 1, solver, "gen1");
			auto generator2 = df.data_generator(df.random_normal({ 1, 3, 256, 256 }, 0, 0.1), 1, solver, "gen2");
			auto selector = df.random_selector(generator1, generator2, 0.5);
			df.euclidean_loss(selector, image);
			df.display(generator1, 2, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "approx1", { train });
			df.display(generator2, 2, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "approx2", { train });
		}
		else if (FLAGS_x5) {
			auto train = df.define_train_phase("Train");
			auto imbar = df.image_batch_reader("./data/face", { 1, 1, 27, 18 });
			df.display(imbar, 1000, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "approx1", { train });
		}
		else if (FLAGS_x6) {
			df.load_from_caffe_model(FLAGS_model, { std::pair<std::string, std::array<int,4>>("data", {4,3,224,224}) }, FLAGS_debug > 0);
			df.block()->remove_node_params({ "fc6_ip", "fc6_w", "fc6_b", "fc7_w", "fc7_b", "fc8_w", "fc8_b" });
			auto train = df.define_train_phase("Train");
			auto solver = df.gain_solver(1.0f, 0.01f, 100, 0.000000001f, 0.05f, 0.95f);
			df.block()->set_solver_for_variable_params(solver, {});
			df.block()->set_phase_for_node_params( train, {});
		}
		else if (FLAGS_x7) {
			auto train = df.define_train_phase("Train");
			auto image = df.image_reader(FLAGS_image1, deepflow::ImageReaderParam_Type_COLOR_IF_AVAILABLE);
			auto b = df.variable(df.zeros({ 1,3,1,1 }), "", "b", {});
			auto f = df.variable(df.ones({ 3,3,5,5 }), "", "f", {});
			auto conv = df.conv2d(image, f, b, "conv");
			df.display(conv, 20, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "input", { train });
		}
		else if (FLAGS_x8) {
			auto train = df.define_train_phase("Train");
			auto image = df.image_reader(FLAGS_image1, deepflow::ImageReaderParam_Type_COLOR_IF_AVAILABLE);
			df.display(image, 10000, DeepFlow::EVERY_PASS, DeepFlow::VALUES, "input", { train });
		}
	}
	else {
		df.block()->load_from_binary(FLAGS_i);
	}

	if (FLAGS_debug > 0) {
		df.block()->print_node_params();
		df.block()->print_phase_params();
	}

	auto session = df.session();

	if (FLAGS_cpp) {
		session->initialize();
		std::cout << session->to_cpp() << std::endl;
		if (FLAGS_debug == 1) {
			session->printMemory();
		}
	}

	if (!FLAGS_run.empty()) {
		session->initialize();
		session->run(FLAGS_run, FLAGS_epoch, FLAGS_iter, FLAGS_printiter, FLAGS_printepoch, FLAGS_debug);
	}

	if (!FLAGS_o.empty())
	{
		if (FLAGS_text)
			df.block()->save_as_text(FLAGS_o);
		else
			df.block()->save_as_binary(FLAGS_o);
	}

}

<|endoftext|>


<commit_before>// RUN: %clangxx_asan -O0 %s -o %t
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL

// UNSUPPORTED: android

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

extern void *aligned_alloc(size_t alignment, size_t size);

int main() {
  void *p = aligned_alloc(17, 100);
  // CHECK: ERROR: AddressSanitizer: invalid allocation alignment: 17
  // CHECK: {{#0 0x.* in .*aligned_alloc}}
  // CHECK: {{#1 0x.* in main .*aligned_alloc-alignment.cc:}}[[@LINE-3]]
  // CHECK: SUMMARY: AddressSanitizer: invalid-allocation-alignment

  printf("pointer after failed aligned_alloc: %zd\n", (size_t)p);
  // CHECK-NULL: pointer after failed aligned_alloc: 0

  return 0;
}
<commit_msg>[ASan] Disable aligned_alloc-alignment.cc test on gcc.<commit_after>// RUN: %clangxx_asan -O0 %s -o %t
// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s
// RUN: %env_asan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL

// UNSUPPORTED: android

// FIXME(alekseyshl): Fix this test under GCC.
// REQUIRES: Clang

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

extern void *aligned_alloc(size_t alignment, size_t size);

int main() {
  void *p = aligned_alloc(17, 100);
  // CHECK: ERROR: AddressSanitizer: invalid allocation alignment: 17
  // CHECK: {{#0 0x.* in .*aligned_alloc}}
  // CHECK: {{#1 0x.* in main .*aligned_alloc-alignment.cc:}}[[@LINE-3]]
  // CHECK: SUMMARY: AddressSanitizer: invalid-allocation-alignment

  printf("pointer after failed aligned_alloc: %zd\n", (size_t)p);
  // CHECK-NULL: pointer after failed aligned_alloc: 0

  return 0;
}
<|endoftext|>


<commit_before>#ifndef MJOLNIR_CORE_BOUNDARY_CONDITION_HPP
#define MJOLNIR_CORE_BOUNDARY_CONDITION_HPP
#include <mjolnir/math/math.hpp>
#include <cstddef>
#include <cassert>

namespace mjolnir
{

template<typename realT, typename coordT>
struct UnlimitedBoundary
{
  public:
    using real_type       = realT;
    using coordinate_type = coordT;

    static constexpr real_type inf = std::numeric_limits<real_type>::infinity();

  public:
    UnlimitedBoundary() = default;
    ~UnlimitedBoundary() = default;

    // r1 -> r2
    coordinate_type adjust_direction(coordinate_type from, coordinate_type to) const noexcept
    {
        return to - from;
    }
    coordinate_type adjust_position(coordinate_type r) const noexcept
    {
        return r;
    }

    void set_boundary(const coordinate_type&, const coordinate_type&) noexcept {assert(false);}
    void set_lower_bound(const coordinate_type&) noexcept {assert(false);}
    void set_upper_bound(const coordinate_type&) noexcept {assert(false);}

    coordinate_type lower_bound() const noexcept
    {
        return math::make_coordinate<coordinate_type>(-inf, -inf, -inf);
    }
    coordinate_type upper_bound() const noexcept
    {
        return math::make_coordinate<coordinate_type>( inf,  inf,  inf);
    }
    coordinate_type width()       const noexcept
    {
        return math::make_coordinate<coordinate_type>( inf,  inf,  inf);
    }

    constexpr bool is_inside_of(const coordinate_type& r) const noexcept {return true;}
};
template<typename realT, typename coordT>
constexpr typename UnlimitedBoundary<realT, coordT>::real_type UnlimitedBoundary<realT, coordT>::inf;

template<typename realT, typename coordT>
struct CuboidalPeriodicBoundary
{
  public:
    using real_type       = realT;
    using coordinate_type = coordT;

  public:

    CuboidalPeriodicBoundary() noexcept: CuboidalPeriodicBoundary(
            math::make_coordinate<coordinate_type>(0, 0, 0),
            math::make_coordinate<coordinate_type>(0, 0, 0))
    {}

    CuboidalPeriodicBoundary(
            const coordinate_type& lw, const coordinate_type& up) noexcept
        : lower_(lw), upper_(up), width_(up - lw), halfw_((up - lw) / 2)
    {}
    ~CuboidalPeriodicBoundary() = default;

    coordinate_type adjust_direction(coordinate_type from, coordinate_type to) const noexcept
    {
        coordinate_type dr = to - from;
        if     (math::X(dr) < -math::X(halfw_)) {math::X(dr) += math::X(width_);}
        else if(math::X(dr) >= math::X(halfw_)) {math::X(dr) -= math::X(width_);}
        if     (math::Y(dr) < -math::Y(halfw_)) {math::Y(dr) += math::Y(width_);}
        else if(math::Y(dr) >= math::Y(halfw_)) {math::Y(dr) -= math::Y(width_);}
        if     (math::Z(dr) < -math::Z(halfw_)) {math::Z(dr) += math::Z(width_);}
        else if(math::Z(dr) >= math::Z(halfw_)) {math::Z(dr) -= math::Z(width_);}
        return dr;
    }

    coordinate_type adjust_position(coordinate_type pos) const noexcept
    {
        if     (math::X(pos) <  math::X(lower_)) {math::X(pos) += math::X(width_);}
        else if(math::X(pos) >= math::X(upper_)) {math::X(pos) -= math::X(width_);}
        if     (math::Y(pos) <  math::Y(lower_)) {math::Y(pos) += math::Y(width_);}
        else if(math::Y(pos) >= math::Y(upper_)) {math::Y(pos) -= math::Y(width_);}
        if     (math::Z(pos) <  math::Z(lower_)) {math::Z(pos) += math::Z(width_);}
        else if(math::Z(pos) >= math::Z(upper_)) {math::Z(pos) -= math::Z(width_);}
        return pos;
    }

    coordinate_type const& lower_bound() const noexcept {return lower_;}
    coordinate_type const& upper_bound() const noexcept {return upper_;}
    coordinate_type const& width()       const noexcept {return width_;}

    void set_boundary(const coordinate_type& lw,
                      const coordinate_type& up) noexcept
    {
        this->lower_ = lw;
        this->upper_ = up;
        this->width_ = this->upper_ - this->lower_;
        this->halfw_ = this->width_ * 0.5;
        return;
    }

    void set_lower_bound(const coordinate_type& lw) noexcept
    {
        this->lower_ = lw;
        this->width_ = this->upper_ - this->lower_;
        this->halfw_ = this->width_ * 0.5;
        return;
    }
    void set_upper_bound(const coordinate_type& up) noexcept
    {
        this->upper_ = up;
        this->width_ = this->upper_ - this->lower_;
        this->halfw_ = this->width_ * 0.5;
        return;
    }

    bool is_inside_of(const coordinate_type& r) const noexcept
    {
        if     (math::X(r) <  math::X(lower_)) {return false;}
        else if(math::X(r) >= math::X(upper_)) {return false;}
        if     (math::Y(r) <  math::Y(lower_)) {return false;}
        else if(math::Y(r) >= math::Y(upper_)) {return false;}
        if     (math::Z(r) <  math::Z(lower_)) {return false;}
        else if(math::Z(r) >= math::Z(upper_)) {return false;}
        return true;
    }

  private:

    coordinate_type lower_;
    coordinate_type upper_;
    coordinate_type width_;
    coordinate_type halfw_;
};

template<typename T>
struct is_unlimited_boundary: std::false_type{};
template<typename realT, typename coordT>
struct is_unlimited_boundary<UnlimitedBoundary<realT, coordT>>: std::true_type{};

template<typename T>
struct is_cuboidal_periodic_boundary: public std::false_type{};
template<typename realT, typename coordT>
struct is_cuboidal_periodic_boundary<CuboidalPeriodicBoundary<realT, coordT>>: std::true_type{};

}//mjolnir
#endif /* MJOLNIR_BOUNDARY_CONDITION */
<commit_msg>refactor: remove unused variable name in func arg<commit_after>#ifndef MJOLNIR_CORE_BOUNDARY_CONDITION_HPP
#define MJOLNIR_CORE_BOUNDARY_CONDITION_HPP
#include <mjolnir/math/math.hpp>
#include <cstddef>
#include <cassert>

namespace mjolnir
{

template<typename realT, typename coordT>
struct UnlimitedBoundary
{
  public:
    using real_type       = realT;
    using coordinate_type = coordT;

    static constexpr real_type inf = std::numeric_limits<real_type>::infinity();

  public:
    UnlimitedBoundary() = default;
    ~UnlimitedBoundary() = default;

    // r1 -> r2
    coordinate_type adjust_direction(coordinate_type from, coordinate_type to) const noexcept
    {
        return to - from;
    }
    coordinate_type adjust_position(coordinate_type r) const noexcept
    {
        return r;
    }

    void set_boundary(const coordinate_type&, const coordinate_type&) noexcept {assert(false);}
    void set_lower_bound(const coordinate_type&) noexcept {assert(false);}
    void set_upper_bound(const coordinate_type&) noexcept {assert(false);}

    coordinate_type lower_bound() const noexcept
    {
        return math::make_coordinate<coordinate_type>(-inf, -inf, -inf);
    }
    coordinate_type upper_bound() const noexcept
    {
        return math::make_coordinate<coordinate_type>( inf,  inf,  inf);
    }
    coordinate_type width()       const noexcept
    {
        return math::make_coordinate<coordinate_type>( inf,  inf,  inf);
    }

    constexpr bool is_inside_of(const coordinate_type&) const noexcept {return true;}
};
template<typename realT, typename coordT>
constexpr typename UnlimitedBoundary<realT, coordT>::real_type UnlimitedBoundary<realT, coordT>::inf;

template<typename realT, typename coordT>
struct CuboidalPeriodicBoundary
{
  public:
    using real_type       = realT;
    using coordinate_type = coordT;

  public:

    CuboidalPeriodicBoundary() noexcept: CuboidalPeriodicBoundary(
            math::make_coordinate<coordinate_type>(0, 0, 0),
            math::make_coordinate<coordinate_type>(0, 0, 0))
    {}

    CuboidalPeriodicBoundary(
            const coordinate_type& lw, const coordinate_type& up) noexcept
        : lower_(lw), upper_(up), width_(up - lw), halfw_((up - lw) / 2)
    {}
    ~CuboidalPeriodicBoundary() = default;

    coordinate_type adjust_direction(coordinate_type from, coordinate_type to) const noexcept
    {
        coordinate_type dr = to - from;
        if     (math::X(dr) < -math::X(halfw_)) {math::X(dr) += math::X(width_);}
        else if(math::X(dr) >= math::X(halfw_)) {math::X(dr) -= math::X(width_);}
        if     (math::Y(dr) < -math::Y(halfw_)) {math::Y(dr) += math::Y(width_);}
        else if(math::Y(dr) >= math::Y(halfw_)) {math::Y(dr) -= math::Y(width_);}
        if     (math::Z(dr) < -math::Z(halfw_)) {math::Z(dr) += math::Z(width_);}
        else if(math::Z(dr) >= math::Z(halfw_)) {math::Z(dr) -= math::Z(width_);}
        return dr;
    }

    coordinate_type adjust_position(coordinate_type pos) const noexcept
    {
        if     (math::X(pos) <  math::X(lower_)) {math::X(pos) += math::X(width_);}
        else if(math::X(pos) >= math::X(upper_)) {math::X(pos) -= math::X(width_);}
        if     (math::Y(pos) <  math::Y(lower_)) {math::Y(pos) += math::Y(width_);}
        else if(math::Y(pos) >= math::Y(upper_)) {math::Y(pos) -= math::Y(width_);}
        if     (math::Z(pos) <  math::Z(lower_)) {math::Z(pos) += math::Z(width_);}
        else if(math::Z(pos) >= math::Z(upper_)) {math::Z(pos) -= math::Z(width_);}
        return pos;
    }

    coordinate_type const& lower_bound() const noexcept {return lower_;}
    coordinate_type const& upper_bound() const noexcept {return upper_;}
    coordinate_type const& width()       const noexcept {return width_;}

    void set_boundary(const coordinate_type& lw,
                      const coordinate_type& up) noexcept
    {
        this->lower_ = lw;
        this->upper_ = up;
        this->width_ = this->upper_ - this->lower_;
        this->halfw_ = this->width_ * 0.5;
        return;
    }

    void set_lower_bound(const coordinate_type& lw) noexcept
    {
        this->lower_ = lw;
        this->width_ = this->upper_ - this->lower_;
        this->halfw_ = this->width_ * 0.5;
        return;
    }
    void set_upper_bound(const coordinate_type& up) noexcept
    {
        this->upper_ = up;
        this->width_ = this->upper_ - this->lower_;
        this->halfw_ = this->width_ * 0.5;
        return;
    }

    bool is_inside_of(const coordinate_type& r) const noexcept
    {
        if     (math::X(r) <  math::X(lower_)) {return false;}
        else if(math::X(r) >= math::X(upper_)) {return false;}
        if     (math::Y(r) <  math::Y(lower_)) {return false;}
        else if(math::Y(r) >= math::Y(upper_)) {return false;}
        if     (math::Z(r) <  math::Z(lower_)) {return false;}
        else if(math::Z(r) >= math::Z(upper_)) {return false;}
        return true;
    }

  private:

    coordinate_type lower_;
    coordinate_type upper_;
    coordinate_type width_;
    coordinate_type halfw_;
};

template<typename T>
struct is_unlimited_boundary: std::false_type{};
template<typename realT, typename coordT>
struct is_unlimited_boundary<UnlimitedBoundary<realT, coordT>>: std::true_type{};

template<typename T>
struct is_cuboidal_periodic_boundary: public std::false_type{};
template<typename realT, typename coordT>
struct is_cuboidal_periodic_boundary<CuboidalPeriodicBoundary<realT, coordT>>: std::true_type{};

}//mjolnir
#endif /* MJOLNIR_BOUNDARY_CONDITION */
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>

#include "triangulation/triangulation.hpp"
#include "calculation/calculation.hpp"

struct Task : public FigureDefinition, public BoundaryConditionsDefinition, public FunctionDefinition {
	int x_max = 9;
	int y_max = 9;

	// Figure definition
	bool parameter(double x, double y) {
		return !(  9 - y < x - 3  );
	}

	// Boundary conditions
	double stream(double x, double y) {
		if(x == 0) // g2
			return 0.15; // p1

		if (x == 9) // g4
			return -0.1; // p2

		return 0;
	}

	double fixed_value(double x, double y) {
		if(y == 0) // g1
			return 2; // u1

		if(y == 9 || (9 - y == x - 3)) // g3
			return 1.5; // u2

		return 0;
	}

	bool is_locked(double x, double y) {
		// Lock if non-zero initially
		return fixed_value(x, y) != 0;
	}

	// Function definition
	double call(double x, double y) {
		double A = 1.5, alpha = 0.15, beta = 1;
		return A * exp( -alpha * x ) *  cos( beta * x );
	}

} task;

void print(Dumpable * d, const char * filename) {
	FILE *gmain;
	bool is3d = typeid(Triangulation) != typeid(*d);

	const char * drawproc;
	if(is3d) {
		drawproc = "set view map\nsplot 'data' with lines palette\n";
	} else{
		drawproc = "plot 'data' with lines\n";
	}

	gmain = fopen("main", "w");
	fprintf(gmain, "set terminal png size %d,%d\nset output \"%s\"\nset key off\n%s", 50 * task.x_max, 50 * task.y_max, filename, drawproc);
	fclose(gmain);

	d->dump("data");

	system("gnuplot main");
	unlink("main");
	//unlink("data");
}

void calculate_and_print(Triangulation &t, const char * filename) {
	Calculation calculation(&task);
	calculation.boundary_conditions = &task;
	calculation.import(&t);
	calculation.init_boundary_conditions();
	calculation.calculate();
	print(&calculation, filename);
}

int main() {
	Triangulation triangulation(&task);

	triangulation.make_grid(task.x_max + 1, task.y_max + 1);
	print(&triangulation, "triangulation.png");
	calculate_and_print(triangulation, "calculation.png");

	for(int i = 0; i < 2; i++) {
		triangulation.make_it_smaller();
		char filename[256];

		snprintf(filename, 255, "triangulation_%d.png", i);
		print(&triangulation, filename);

		snprintf(filename, 255, "calculation_%d.png", i);
		calculate_and_print(triangulation, filename);
	}

	return 0;
}
<commit_msg>Added padding compensation to generator example<commit_after>#include <cstdio>
#include <cstdlib>

#include "triangulation/triangulation.hpp"
#include "calculation/calculation.hpp"

struct Task : public FigureDefinition, public BoundaryConditionsDefinition, public FunctionDefinition {
	int x_max = 9;
	int y_max = 9;

	// Figure definition
	bool parameter(double x, double y) {
		return !(  9 - y < x - 3  );
	}

	// Boundary conditions
	double stream(double x, double y) {
		if(x == 0) // g2
			return 0.15; // p1

		if (x == 9) // g4
			return -0.1; // p2

		return 0;
	}

	double fixed_value(double x, double y) {
		if(y == 0) // g1
			return 2; // u1

		if(y == 9 || (9 - y == x - 3)) // g3
			return 1.5; // u2

		return 0;
	}

	bool is_locked(double x, double y) {
		// Lock if non-zero initially
		return fixed_value(x, y) != 0;
	}

	// Function definition
	double call(double x, double y) {
		double A = 1.5, alpha = 0.15, beta = 1;
		return A * exp( -alpha * x ) *  cos( beta * x );
	}

} task;

void print(Dumpable * d, const char * filename) {
	FILE *gmain;
	int gnuplot_padding_x, gnuplot_padding_y;
	bool is3d = typeid(Triangulation) != typeid(*d);

	const char * drawproc;
	if(is3d) {
		gnuplot_padding_x = 77+76;
		gnuplot_padding_y = 78+97;
		drawproc = "set view map\nsplot 'data' with lines palette lw 2.5\n";
	} else {
		gnuplot_padding_x = 55;
		gnuplot_padding_y = 40;
		drawproc = "unset ytics\nunset xtics\nplot 'data' with lines lw 1\n";
	}

	gmain = fopen("main", "w");
	fprintf(gmain, "set terminal png size %d,%d\nset output \"%s\"\nset key off\n%s",
		50 * task.x_max + gnuplot_padding_x, 50 * task.y_max + gnuplot_padding_y, filename, drawproc);
	fclose(gmain);

	d->dump("data");

	system("gnuplot main");
	unlink("main");
	//unlink("data");
}

void calculate_and_print(Triangulation &t, const char * filename) {
	Calculation calculation(&task);
	calculation.boundary_conditions = &task;
	calculation.import(&t);
	calculation.init_boundary_conditions();
	calculation.calculate();
	print(&calculation, filename);
}

int main() {
	Triangulation triangulation(&task);

	triangulation.make_grid(task.x_max + 1, task.y_max + 1);
	print(&triangulation, "triangulation.png");
	calculate_and_print(triangulation, "calculation.png");

	for(int i = 0; i < 2; i++) {
		triangulation.make_it_smaller();
		char filename[256];

		snprintf(filename, 255, "triangulation_%d.png", i);
		print(&triangulation, filename);

		snprintf(filename, 255, "calculation_%d.png", i);
		calculate_and_print(triangulation, filename);
	}

	return 0;
}
<|endoftext|>