<commit_before>#include <Path2D.h>

#include <cmath>

using namespace canvas;

void
Path2D::arc(const Point & p, double radius, double sa, double ea, bool anticlockwise) {
  data.push_back(PathComponent(PathComponent::ARC, p.x, p.y, radius, sa, ea, anticlockwise));
  current_point = Point(p.x + radius * cos(ea), p.y + radius * sin(ea));
}

// Implementation by node-canvas (Node canvas is a Cairo backed Canvas implementation for NodeJS)
// Original implementation influenced by WebKit.
void
Path2D::arcTo(const Point & p1, const Point & p2, double radius) {
  Point p0 = current_point; // current point may be modified so make a copy

  if ((p1.x == p0.x && p1.y == p0.y) || (p1.x == p2.x && p1.y == p2.y) || radius == 0.f) {
    lineTo(p1);
    // p2?
    return;
  }

  Point p1p0((p0.x - p1.x), (p0.y - p1.y));
  Point p1p2((p2.x - p1.x), (p2.y - p1.y));
  float p1p0_length = sqrt(p1p0.x * p1p0.x + p1p0.y * p1p0.y);
  float p1p2_length = sqrt(p1p2.x * p1p2.x + p1p2.y * p1p2.y);

  double cos_phi = (p1p0.x * p1p2.x + p1p0.y * p1p2.y) / (p1p0_length * p1p2_length);
  // all points on a line logic
  if (-1 == cos_phi) {
    lineTo(p1);
    // p2?
    return;
  }

  if (1 == cos_phi) {
    // add infinite far away point
    unsigned int max_length = 65535;
    double factor_max = max_length / p1p0_length;
    Point ep((p0.x + factor_max * p1p0.x), (p0.y + factor_max * p1p0.y));
    lineTo(ep);
    return;
  }

  double tangent = radius / tan(acos(cos_phi) / 2);
  double factor_p1p0 = tangent / p1p0_length;
  Point t_p1p0((p1.x + factor_p1p0 * p1p0.x), (p1.y + factor_p1p0 * p1p0.y));

  Point orth_p1p0(p1p0.y, -p1p0.x);
  double orth_p1p0_length = sqrt(orth_p1p0.x * orth_p1p0.x + orth_p1p0.y * orth_p1p0.y);
  double factor_ra = radius / orth_p1p0_length;

  double cos_alpha = (orth_p1p0.x * p1p2.x + orth_p1p0.y * p1p2.y) / (orth_p1p0_length * p1p2_length);
  if (cos_alpha < 0.f) {
    orth_p1p0 = Point(-orth_p1p0.x, -orth_p1p0.y);
  }

  Point p((t_p1p0.x + factor_ra * orth_p1p0.x), (t_p1p0.y + factor_ra * orth_p1p0.y));

  orth_p1p0 = Point(-orth_p1p0.x, -orth_p1p0.y);
  double sa = acos(orth_p1p0.x / orth_p1p0_length);
  if (orth_p1p0.y < 0.f) {
    sa = 2 * M_PI - sa;
  }

  bool anticlockwise = false;

  double factor_p1p2 = tangent / p1p2_length;
  Point t_p1p2((p1.x + factor_p1p2 * p1p2.x), (p1.y + factor_p1p2 * p1p2.y));
  Point orth_p1p2((t_p1p2.x - p.x),(t_p1p2.y - p.y));
  double orth_p1p2_length = sqrt(orth_p1p2.x * orth_p1p2.x + orth_p1p2.y * orth_p1p2.y);
  double ea = acos(orth_p1p2.x / orth_p1p2_length);

  if (orth_p1p2.y < 0) ea = 2 * M_PI - ea;
  if ((sa > ea) && ((sa - ea) < M_PI)) anticlockwise = true;
  if ((sa < ea) && ((ea - sa) > M_PI)) anticlockwise = true;

  // cerr << "ARC " << int(t_p1p0.x) << " " << int(t_p1p0.y) << " " << int(p.x) << " " << int(p.y) << " " << radius << " " << int(sa * 180.0 / M_PI) << " " << int(ea * 180.0 / M_PI) << " " << (anticlockwise ? "acw" : "cw") << endl;

  lineTo(t_p1p0);
  arc(p, radius, sa, ea, anticlockwise); // && M_PI * 2 != radius);
  // current_point = p2;
}

static inline float determinant(float x1, float y1, float x2, float y2) {
  return x1 * y2 - x2 * y1;
}

#if 0
// returns vector cross product of vectors p1p2 and p1p3 using Cramer's rule
static inline float crossProduct(const glm::vec2 & p1, const glm::vec2 & p2, const glm::vec2 & p3) {
  float det_p2p3 = determinant(p2.x, p2.y, p3.x, p3.y);
  float det_p1p3 = determinant(p1.x, p1.y, p3.x, p3.y);
  float det_p1p2 = determinant(p1.x, p1.y, p2.x, p2.y);
  return det_p2p3 - det_p1p3 + det_p1p2;
}

// The winding number method has been used here. It counts the number
// of times a polygon winds around the point.  If the result is 0, the
// points is outside the polygon.
bool
Path2D::isInside(float x, float y) const {
  glm::vec2 point(x, y);
  int wn = 0;
  for (unsigned int i = 0; i < data.size(); i++) {
    glm::vec2 v1;
    if (i == 0) {
      v1 = glm::vec2( (float)data.back().x0, (float)data.back().y0 );
    } else {
      v1 = glm::vec2( (float)data[i - 1].x0, (float)data[i - 1].y0 );
    }
    glm::vec2 v2( (float)data[i].x0, (float)data[i].y0 );
    if (v1.y <= point.y) { // start y <= P.y
      if (v2.y > point.y) { // an upward crossing
	if (crossProduct(v1, v2, point) > 0) {
	  // point left of edge
	  wn++; // have a valid up intersect
	}
      }
    } else { // start y > P.y (no test needed)
      if (v2.y <= point.y) { // a downward crossing
	if (crossProduct(v1, v2, point) < 0) {
	  // point right of edge
	  wn--; // have a valid down intersect
	}
      }
    }
  }

  bool is_inside = wn != 0 ? true : false;

  // fprintf(stderr, "inside test for polygon %Ld: %s\n", id, is_inside ? "true" : "false" );
  return is_inside;
}
#endif
<commit_msg>refactor<commit_after>#include <Path2D.h>

#include <cmath>

using namespace canvas;

void
Path2D::arc(const Point & p, double radius, double sa, double ea, bool anticlockwise) {
  data.push_back(PathComponent(PathComponent::ARC, p.x, p.y, radius, sa, ea, anticlockwise));
  current_point = Point(p.x + radius * cos(ea), p.y + radius * sin(ea));
}

// Implementation by node-canvas (Node canvas is a Cairo backed Canvas implementation for NodeJS)
// Original implementation influenced by WebKit.
void
Path2D::arcTo(const Point & p1, const Point & p2, double radius) {
  auto p0 = current_point; // current point may be modified so make a copy

  if ((p1.x == p0.x && p1.y == p0.y) || (p1.x == p2.x && p1.y == p2.y) || radius == 0.f) {
    lineTo(p1);
    // p2?
    return;
  }

  Point p1p0((p0.x - p1.x), (p0.y - p1.y));
  Point p1p2((p2.x - p1.x), (p2.y - p1.y));
  float p1p0_length = sqrt(p1p0.x * p1p0.x + p1p0.y * p1p0.y);
  float p1p2_length = sqrt(p1p2.x * p1p2.x + p1p2.y * p1p2.y);

  double cos_phi = (p1p0.x * p1p2.x + p1p0.y * p1p2.y) / (p1p0_length * p1p2_length);
  // all points on a line logic
  if (-1 == cos_phi) {
    lineTo(p1);
    // p2?
    return;
  }

  if (1 == cos_phi) {
    // add infinite far away point
    unsigned int max_length = 65535;
    double factor_max = max_length / p1p0_length;
    Point ep((p0.x + factor_max * p1p0.x), (p0.y + factor_max * p1p0.y));
    lineTo(ep);
    return;
  }

  double tangent = radius / tan(acos(cos_phi) / 2);
  double factor_p1p0 = tangent / p1p0_length;
  Point t_p1p0((p1.x + factor_p1p0 * p1p0.x), (p1.y + factor_p1p0 * p1p0.y));

  Point orth_p1p0(p1p0.y, -p1p0.x);
  double orth_p1p0_length = sqrt(orth_p1p0.x * orth_p1p0.x + orth_p1p0.y * orth_p1p0.y);
  double factor_ra = radius / orth_p1p0_length;

  double cos_alpha = (orth_p1p0.x * p1p2.x + orth_p1p0.y * p1p2.y) / (orth_p1p0_length * p1p2_length);
  if (cos_alpha < 0.f) {
    orth_p1p0 = Point(-orth_p1p0.x, -orth_p1p0.y);
  }

  Point p((t_p1p0.x + factor_ra * orth_p1p0.x), (t_p1p0.y + factor_ra * orth_p1p0.y));

  orth_p1p0 = Point(-orth_p1p0.x, -orth_p1p0.y);
  double sa = acos(orth_p1p0.x / orth_p1p0_length);
  if (orth_p1p0.y < 0.f) {
    sa = 2 * M_PI - sa;
  }

  bool anticlockwise = false;

  double factor_p1p2 = tangent / p1p2_length;
  Point t_p1p2((p1.x + factor_p1p2 * p1p2.x), (p1.y + factor_p1p2 * p1p2.y));
  Point orth_p1p2((t_p1p2.x - p.x),(t_p1p2.y - p.y));
  double orth_p1p2_length = sqrt(orth_p1p2.x * orth_p1p2.x + orth_p1p2.y * orth_p1p2.y);
  double ea = acos(orth_p1p2.x / orth_p1p2_length);

  if (orth_p1p2.y < 0) ea = 2 * M_PI - ea;
  if ((sa > ea) && ((sa - ea) < M_PI)) anticlockwise = true;
  if ((sa < ea) && ((ea - sa) > M_PI)) anticlockwise = true;

  // cerr << "ARC " << int(t_p1p0.x) << " " << int(t_p1p0.y) << " " << int(p.x) << " " << int(p.y) << " " << radius << " " << int(sa * 180.0 / M_PI) << " " << int(ea * 180.0 / M_PI) << " " << (anticlockwise ? "acw" : "cw") << endl;

  lineTo(t_p1p0);
  arc(p, radius, sa, ea, anticlockwise); // && M_PI * 2 != radius);
  // current_point = p2;
}

static inline float determinant(float x1, float y1, float x2, float y2) {
  return x1 * y2 - x2 * y1;
}

#if 0
// returns vector cross product of vectors p1p2 and p1p3 using Cramer's rule
static inline float crossProduct(const glm::vec2 & p1, const glm::vec2 & p2, const glm::vec2 & p3) {
  float det_p2p3 = determinant(p2.x, p2.y, p3.x, p3.y);
  float det_p1p3 = determinant(p1.x, p1.y, p3.x, p3.y);
  float det_p1p2 = determinant(p1.x, p1.y, p2.x, p2.y);
  return det_p2p3 - det_p1p3 + det_p1p2;
}

// The winding number method has been used here. It counts the number
// of times a polygon winds around the point.  If the result is 0, the
// points is outside the polygon.
bool
Path2D::isInside(float x, float y) const {
  glm::vec2 point(x, y);
  int wn = 0;
  for (unsigned int i = 0; i < data.size(); i++) {
    glm::vec2 v1;
    if (i == 0) {
      v1 = glm::vec2( (float)data.back().x0, (float)data.back().y0 );
    } else {
      v1 = glm::vec2( (float)data[i - 1].x0, (float)data[i - 1].y0 );
    }
    glm::vec2 v2( (float)data[i].x0, (float)data[i].y0 );
    if (v1.y <= point.y) { // start y <= P.y
      if (v2.y > point.y) { // an upward crossing
	if (crossProduct(v1, v2, point) > 0) {
	  // point left of edge
	  wn++; // have a valid up intersect
	}
      }
    } else { // start y > P.y (no test needed)
      if (v2.y <= point.y) { // a downward crossing
	if (crossProduct(v1, v2, point) < 0) {
	  // point right of edge
	  wn--; // have a valid down intersect
	}
      }
    }
  }

  bool is_inside = wn != 0 ? true : false;

  // fprintf(stderr, "inside test for polygon %Ld: %s\n", id, is_inside ? "true" : "false" );
  return is_inside;
}
#endif
<|endoftext|>


<commit_before>/* Copyright 2018 Google LLC

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

    https://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_data_validation/anomalies/feature_statistics_validator.h"

#include <memory>
#include <string>

#include "absl/types/optional.h"
#include "tensorflow_data_validation/anomalies/schema.h"
#include "tensorflow_data_validation/anomalies/schema_anomalies.h"
#include "tensorflow_data_validation/anomalies/statistics_view.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow_metadata/proto/v0/schema.pb.h"

using tensorflow::metadata::v0::DatasetFeatureStatistics;

namespace tensorflow {
namespace data_validation {

namespace {
const int64 kDefaultEnumThreshold = 400;
}

FeatureStatisticsToProtoConfig GetDefaultFeatureStatisticsToProtoConfig() {
  FeatureStatisticsToProtoConfig feature_statistics_to_proto_config;
  feature_statistics_to_proto_config.set_enum_threshold(kDefaultEnumThreshold);
  return feature_statistics_to_proto_config;
}

tensorflow::Status InferSchema(const string& feature_statistics_proto_string,
                               const int max_string_domain_size,
                               const bool infer_feature_shape,
                               string* schema_proto_string) {
  tensorflow::metadata::v0::DatasetFeatureStatistics feature_statistics;
  if (!feature_statistics.ParseFromString(feature_statistics_proto_string)) {
    return tensorflow::errors::InvalidArgument(
        "Failed to parse DatasetFeatureStatistics proto.");
  }
  FeatureStatisticsToProtoConfig feature_statistics_to_proto_config;
  feature_statistics_to_proto_config.set_enum_threshold(max_string_domain_size);
  feature_statistics_to_proto_config.set_infer_feature_shape(
      infer_feature_shape);
  tensorflow::metadata::v0::Schema schema;
  TF_RETURN_IF_ERROR(
      UpdateSchema(feature_statistics_to_proto_config,
                   schema, feature_statistics,
                   /* paths_to_consider= */ gtl::nullopt,
                   /* environment= */ gtl::nullopt, &schema));
  if (!schema.SerializeToString(schema_proto_string)) {
    return tensorflow::errors::Internal(
        "Could not serialize Schema output proto to string.");
  }
  return tensorflow::Status::OK();
}

tensorflow::Status UpdateSchema(const string& schema_proto_string,
                                const string& feature_statistics_proto_string,
                                const int max_string_domain_size,
                                string* output_schema_proto_string) {
  tensorflow::metadata::v0::Schema schema;
  if (!schema.ParseFromString(schema_proto_string)) {
    return tensorflow::errors::InvalidArgument("Failed to parse Schema proto.");
  }
  tensorflow::metadata::v0::DatasetFeatureStatistics feature_statistics;
  if (!feature_statistics.ParseFromString(feature_statistics_proto_string)) {
    return tensorflow::errors::InvalidArgument(
        "Failed to parse DatasetFeatureStatistics proto.");
  }
  FeatureStatisticsToProtoConfig feature_statistics_to_proto_config;
  feature_statistics_to_proto_config.set_enum_threshold(max_string_domain_size);
  tensorflow::metadata::v0::Schema output_schema;
  TF_RETURN_IF_ERROR(
      UpdateSchema(feature_statistics_to_proto_config,
                   schema, feature_statistics,
                   /* paths_to_consider= */ gtl::nullopt,
                   /* environment= */ gtl::nullopt, &output_schema));
  if (!output_schema.SerializeToString(output_schema_proto_string)) {
    return tensorflow::errors::Internal(
        "Could not serialize Schema output proto to string.");
  }
  return tensorflow::Status::OK();
}

tensorflow::Status ValidateFeatureStatistics(
    const tensorflow::metadata::v0::DatasetFeatureStatistics&
        feature_statistics,
    const tensorflow::metadata::v0::Schema& schema_proto,
    const absl::optional<string>& environment,
    const absl::optional<tensorflow::metadata::v0::DatasetFeatureStatistics>&
        prev_span_feature_statistics,
    const absl::optional<tensorflow::metadata::v0::DatasetFeatureStatistics>&
        serving_feature_statistics,
    const absl::optional<metadata::v0::DatasetFeatureStatistics>&
        prev_version_feature_statistics,
    const absl::optional<FeaturesNeeded>& features_needed,
    const ValidationConfig& validation_config, bool enable_diff_regions,
    tensorflow::metadata::v0::Anomalies* result) {
  // TODO(b/113295423): Clean up the optional conversions.
  const absl::optional<string> maybe_environment =
      environment ? absl::optional<string>(*environment)
                  : absl::optional<string>();
  FeatureStatisticsToProtoConfig feature_statistics_to_proto_config;
  feature_statistics_to_proto_config.set_enum_threshold(kDefaultEnumThreshold);
  feature_statistics_to_proto_config.set_new_features_are_warnings(
      validation_config.new_features_are_warnings());
  *feature_statistics_to_proto_config.mutable_severity_overrides() =
      validation_config.severity_overrides();

  const bool by_weight =
      DatasetStatsView(feature_statistics).WeightedStatisticsExist();
  if (feature_statistics.num_examples() == 0) {
    *result->mutable_baseline() = schema_proto;
    result->set_data_missing(true);
  } else {
    SchemaAnomalies schema_anomalies(schema_proto);
    std::shared_ptr<DatasetStatsView> previous_span =
        (prev_span_feature_statistics)
            ? std::make_shared<DatasetStatsView>(
                  prev_span_feature_statistics.value(), by_weight,
                  maybe_environment,
                  /* previous_span= */ nullptr,
                  /* serving= */ nullptr,
                  /* previous_version= */ nullptr)
            : nullptr;

    std::shared_ptr<DatasetStatsView> serving =
        (serving_feature_statistics) ? std::make_shared<DatasetStatsView>(
                                           serving_feature_statistics.value(),
                                           by_weight, maybe_environment,
                                           /* previous_span= */ nullptr,
                                           /* serving= */ nullptr,
                                           /* previous_version= */ nullptr)
                                     : nullptr;

    std::shared_ptr<DatasetStatsView> previous_version =
        (prev_version_feature_statistics)
            ? std::make_shared<DatasetStatsView>(
                  prev_version_feature_statistics.value(), by_weight,
                  maybe_environment,
                  /* previous_span= */ nullptr,
                  /* serving= */ nullptr,
                  /* previous_version= */ nullptr)
            : nullptr;

    const DatasetStatsView training =
        DatasetStatsView(feature_statistics, by_weight, maybe_environment,
                         previous_span, serving, previous_version);
    TF_RETURN_IF_ERROR(
        schema_anomalies.FindChanges(training, features_needed,
                                     feature_statistics_to_proto_config));
    *result = schema_anomalies.GetSchemaDiff(enable_diff_regions);
  }

  return tensorflow::Status::OK();
}

tensorflow::Status ValidateFeatureStatisticsWithSerializedInputs(
    const string& feature_statistics_proto_string,
    const string& schema_proto_string, const string& environment,
    const string& previous_span_statistics_proto_string,
    const string& serving_statistics_proto_string,
    const string& previous_version_statistics_proto_string,
    const string& features_needed_string,
    const string& validation_config_string, const bool enable_diff_regions,
    string* anomalies_proto_string) {
  tensorflow::metadata::v0::Schema schema;
  if (!schema.ParseFromString(schema_proto_string)) {
    return tensorflow::errors::InvalidArgument("Failed to parse Schema proto.");
  }

  tensorflow::metadata::v0::DatasetFeatureStatistics feature_statistics;
  if (!feature_statistics.ParseFromString(feature_statistics_proto_string)) {
    return tensorflow::errors::InvalidArgument(
        "Failed to parse DatasetFeatureStatistics proto.");
  }

  absl::optional<tensorflow::metadata::v0::DatasetFeatureStatistics>
      previous_span_statistics = tensorflow::gtl::nullopt;
  if (!previous_span_statistics_proto_string.empty()) {
    tensorflow::metadata::v0::DatasetFeatureStatistics tmp_stats;
    if (!tmp_stats.ParseFromString(previous_span_statistics_proto_string)) {
      return tensorflow::errors::InvalidArgument(
          "Failed to parse DatasetFeatureStatistics proto.");
    }
    previous_span_statistics = tmp_stats;
  }

  absl::optional<tensorflow::metadata::v0::DatasetFeatureStatistics>
      serving_statistics = tensorflow::gtl::nullopt;
  if (!serving_statistics_proto_string.empty()) {
    tensorflow::metadata::v0::DatasetFeatureStatistics tmp_stats;
    if (!tmp_stats.ParseFromString(serving_statistics_proto_string)) {
      return tensorflow::errors::InvalidArgument(
          "Failed to parse DatasetFeatureStatistics proto.");
    }
    serving_statistics = tmp_stats;
  }

  absl::optional<tensorflow::metadata::v0::DatasetFeatureStatistics>
      previous_version_statistics = tensorflow::gtl::nullopt;
  if (!previous_version_statistics_proto_string.empty()) {
    tensorflow::metadata::v0::DatasetFeatureStatistics tmp_stats;
    if (!tmp_stats.ParseFromString(previous_version_statistics_proto_string)) {
      return tensorflow::errors::InvalidArgument(
          "Failed to parse DatasetFeatureStatistics proto.");
    }
    previous_version_statistics = tmp_stats;
  }

  absl::optional<string> may_be_environment =
      tensorflow::gtl::nullopt;
  if (!environment.empty()) {
    may_be_environment = environment;
  }

  absl::optional<FeaturesNeeded> features_needed = gtl::nullopt;
  if (!features_needed_string.empty()) {
    FeaturesNeededProto parsed_proto;
    if (!parsed_proto.ParseFromString(features_needed_string)) {
      return tensorflow::errors::InvalidArgument(
          "Failed to parse FeaturesNeeded");
    }

    FeaturesNeeded parsed_feature_needed;
    TF_RETURN_IF_ERROR(
        FromFeaturesNeededProto(parsed_proto, &parsed_feature_needed));
    if (!parsed_feature_needed.empty()) {
      features_needed = parsed_feature_needed;
    }
  }

  data_validation::ValidationConfig validation_config;
  if (!validation_config.ParseFromString(validation_config_string)) {
    return tensorflow::errors::InvalidArgument(
        "Failed to parse ValidationConfig");
  }

  tensorflow::metadata::v0::Anomalies anomalies;
  TF_RETURN_IF_ERROR(ValidateFeatureStatistics(
      feature_statistics, schema, may_be_environment, previous_span_statistics,
      serving_statistics, previous_version_statistics, features_needed,
      validation_config, enable_diff_regions, &anomalies));

  if (!anomalies.SerializeToString(anomalies_proto_string)) {
    return tensorflow::errors::Internal(
        "Could not serialize Anomalies output proto to string.");
  }
  return tensorflow::Status::OK();
}

tensorflow::Status UpdateSchema(
    const FeatureStatisticsToProtoConfig& feature_statistics_to_proto_config,
    const tensorflow::metadata::v0::Schema& schema_to_update,
    const tensorflow::metadata::v0::DatasetFeatureStatistics&
        feature_statistics,
    const absl::optional<std::vector<Path>>& paths_to_consider,
    const absl::optional<string>& environment,
    tensorflow::metadata::v0::Schema* result) {
  // TODO(b/112762449): Add full support for multi-step
  // paths from paths_to_consider.
  // In the meantime, there are two ways you could imagine
  // translating to a string:
  // 1: As below, using the last step. Since all the paths at present are just
  //    a single step, this won't break anything. Moreover, since in
  //    schema_updater.cc, we are populating the string into last_step, this
  //    is the same as the existing implementation.
  // 2: As a serialized path. This will break current designs, as the Schema
  //    Updater will incorrectly handle paths like Path({"foo.bar"}).
  // TODO(b/113295423): Clean up the optional conversions.
  const absl::optional<string> maybe_environment =
      environment ? absl::optional<string>(*environment) : absl::nullopt;

  const bool by_weight =
      DatasetStatsView(feature_statistics).WeightedStatisticsExist();
  Schema schema;
  TF_RETURN_IF_ERROR(schema.Init(schema_to_update));
  if (paths_to_consider) {
    TF_RETURN_IF_ERROR(schema.Update(
        DatasetStatsView(feature_statistics, by_weight, maybe_environment,
                         /* previous_span= */ nullptr,
                         /* serving= */ nullptr,
                         /* previous_version= */ nullptr),
        feature_statistics_to_proto_config, *paths_to_consider));
  } else {
    TF_RETURN_IF_ERROR(schema.Update(
        DatasetStatsView(feature_statistics, by_weight, maybe_environment,
                         /* previous_span= */ nullptr,
                         /* serving= */ nullptr,
                         /* previous_version= */ nullptr),
        feature_statistics_to_proto_config));
  }
  *result = schema.GetSchema();
  return tensorflow::Status::OK();
}

}  // namespace data_validation
}  // namespace tensorflow
<commit_msg>no-op<commit_after>/* Copyright 2018 Google LLC

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

    https://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_data_validation/anomalies/feature_statistics_validator.h"

#include <memory>
#include <string>

#include "absl/types/optional.h"
#include "tensorflow_data_validation/anomalies/schema.h"
#include "tensorflow_data_validation/anomalies/schema_anomalies.h"
#include "tensorflow_data_validation/anomalies/statistics_view.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/monitoring/counter.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow_metadata/proto/v0/schema.pb.h"

using tensorflow::metadata::v0::DatasetFeatureStatistics;

namespace tensorflow {
namespace data_validation {

namespace {
const int64 kDefaultEnumThreshold = 400;
auto* anomaly_type_counts = tensorflow::monitoring::Counter<1>::New(
    "/tfx/example_validation/anomaly_type_counts", "Anomaly types found.",
    "anomaly_type");
}

FeatureStatisticsToProtoConfig GetDefaultFeatureStatisticsToProtoConfig() {
  FeatureStatisticsToProtoConfig feature_statistics_to_proto_config;
  feature_statistics_to_proto_config.set_enum_threshold(kDefaultEnumThreshold);
  return feature_statistics_to_proto_config;
}

tensorflow::Status InferSchema(const string& feature_statistics_proto_string,
                               const int max_string_domain_size,
                               const bool infer_feature_shape,
                               string* schema_proto_string) {
  tensorflow::metadata::v0::DatasetFeatureStatistics feature_statistics;
  if (!feature_statistics.ParseFromString(feature_statistics_proto_string)) {
    return tensorflow::errors::InvalidArgument(
        "Failed to parse DatasetFeatureStatistics proto.");
  }
  FeatureStatisticsToProtoConfig feature_statistics_to_proto_config;
  feature_statistics_to_proto_config.set_enum_threshold(max_string_domain_size);
  feature_statistics_to_proto_config.set_infer_feature_shape(
      infer_feature_shape);
  tensorflow::metadata::v0::Schema schema;
  TF_RETURN_IF_ERROR(
      UpdateSchema(feature_statistics_to_proto_config,
                   schema, feature_statistics,
                   /* paths_to_consider= */ gtl::nullopt,
                   /* environment= */ gtl::nullopt, &schema));
  if (!schema.SerializeToString(schema_proto_string)) {
    return tensorflow::errors::Internal(
        "Could not serialize Schema output proto to string.");
  }
  return tensorflow::Status::OK();
}

tensorflow::Status UpdateSchema(const string& schema_proto_string,
                                const string& feature_statistics_proto_string,
                                const int max_string_domain_size,
                                string* output_schema_proto_string) {
  tensorflow::metadata::v0::Schema schema;
  if (!schema.ParseFromString(schema_proto_string)) {
    return tensorflow::errors::InvalidArgument("Failed to parse Schema proto.");
  }
  tensorflow::metadata::v0::DatasetFeatureStatistics feature_statistics;
  if (!feature_statistics.ParseFromString(feature_statistics_proto_string)) {
    return tensorflow::errors::InvalidArgument(
        "Failed to parse DatasetFeatureStatistics proto.");
  }
  FeatureStatisticsToProtoConfig feature_statistics_to_proto_config;
  feature_statistics_to_proto_config.set_enum_threshold(max_string_domain_size);
  tensorflow::metadata::v0::Schema output_schema;
  TF_RETURN_IF_ERROR(
      UpdateSchema(feature_statistics_to_proto_config,
                   schema, feature_statistics,
                   /* paths_to_consider= */ gtl::nullopt,
                   /* environment= */ gtl::nullopt, &output_schema));
  if (!output_schema.SerializeToString(output_schema_proto_string)) {
    return tensorflow::errors::Internal(
        "Could not serialize Schema output proto to string.");
  }
  return tensorflow::Status::OK();
}

tensorflow::Status ValidateFeatureStatistics(
    const tensorflow::metadata::v0::DatasetFeatureStatistics&
        feature_statistics,
    const tensorflow::metadata::v0::Schema& schema_proto,
    const absl::optional<string>& environment,
    const absl::optional<tensorflow::metadata::v0::DatasetFeatureStatistics>&
        prev_span_feature_statistics,
    const absl::optional<tensorflow::metadata::v0::DatasetFeatureStatistics>&
        serving_feature_statistics,
    const absl::optional<metadata::v0::DatasetFeatureStatistics>&
        prev_version_feature_statistics,
    const absl::optional<FeaturesNeeded>& features_needed,
    const ValidationConfig& validation_config, bool enable_diff_regions,
    tensorflow::metadata::v0::Anomalies* result) {
  // TODO(b/113295423): Clean up the optional conversions.
  const absl::optional<string> maybe_environment =
      environment ? absl::optional<string>(*environment)
                  : absl::optional<string>();
  FeatureStatisticsToProtoConfig feature_statistics_to_proto_config;
  feature_statistics_to_proto_config.set_enum_threshold(kDefaultEnumThreshold);
  feature_statistics_to_proto_config.set_new_features_are_warnings(
      validation_config.new_features_are_warnings());
  *feature_statistics_to_proto_config.mutable_severity_overrides() =
      validation_config.severity_overrides();

  const bool by_weight =
      DatasetStatsView(feature_statistics).WeightedStatisticsExist();
  if (feature_statistics.num_examples() == 0) {
    *result->mutable_baseline() = schema_proto;
    result->set_data_missing(true);
  } else {
    SchemaAnomalies schema_anomalies(schema_proto);
    std::shared_ptr<DatasetStatsView> previous_span =
        (prev_span_feature_statistics)
            ? std::make_shared<DatasetStatsView>(
                  prev_span_feature_statistics.value(), by_weight,
                  maybe_environment,
                  /* previous_span= */ nullptr,
                  /* serving= */ nullptr,
                  /* previous_version= */ nullptr)
            : nullptr;

    std::shared_ptr<DatasetStatsView> serving =
        (serving_feature_statistics) ? std::make_shared<DatasetStatsView>(
                                           serving_feature_statistics.value(),
                                           by_weight, maybe_environment,
                                           /* previous_span= */ nullptr,
                                           /* serving= */ nullptr,
                                           /* previous_version= */ nullptr)
                                     : nullptr;

    std::shared_ptr<DatasetStatsView> previous_version =
        (prev_version_feature_statistics)
            ? std::make_shared<DatasetStatsView>(
                  prev_version_feature_statistics.value(), by_weight,
                  maybe_environment,
                  /* previous_span= */ nullptr,
                  /* serving= */ nullptr,
                  /* previous_version= */ nullptr)
            : nullptr;

    const DatasetStatsView training =
        DatasetStatsView(feature_statistics, by_weight, maybe_environment,
                         previous_span, serving, previous_version);
    TF_RETURN_IF_ERROR(
        schema_anomalies.FindChanges(training, features_needed,
                                     feature_statistics_to_proto_config));
    *result = schema_anomalies.GetSchemaDiff(enable_diff_regions);
  }

  for (const auto& anomaly : result->anomaly_info()) {
    for (const auto& reason : anomaly.second.reason()) {
      anomaly_type_counts
          ->GetCell(metadata::v0::AnomalyInfo::Type_Name(reason.type()))
          ->IncrementBy(1);
    }
  }
  if (result->has_dataset_anomaly_info()) {
    for (const auto& reason : result->dataset_anomaly_info().reason()) {
      anomaly_type_counts
          ->GetCell(metadata::v0::AnomalyInfo::Type_Name(reason.type()))
          ->IncrementBy(1);
    }
  }
  if (result->data_missing()) {
    anomaly_type_counts->GetCell("data_missing")->IncrementBy(1);
  }

  return tensorflow::Status::OK();
}

tensorflow::Status ValidateFeatureStatisticsWithSerializedInputs(
    const string& feature_statistics_proto_string,
    const string& schema_proto_string, const string& environment,
    const string& previous_span_statistics_proto_string,
    const string& serving_statistics_proto_string,
    const string& previous_version_statistics_proto_string,
    const string& features_needed_string,
    const string& validation_config_string, const bool enable_diff_regions,
    string* anomalies_proto_string) {
  tensorflow::metadata::v0::Schema schema;
  if (!schema.ParseFromString(schema_proto_string)) {
    return tensorflow::errors::InvalidArgument("Failed to parse Schema proto.");
  }

  tensorflow::metadata::v0::DatasetFeatureStatistics feature_statistics;
  if (!feature_statistics.ParseFromString(feature_statistics_proto_string)) {
    return tensorflow::errors::InvalidArgument(
        "Failed to parse DatasetFeatureStatistics proto.");
  }

  absl::optional<tensorflow::metadata::v0::DatasetFeatureStatistics>
      previous_span_statistics = tensorflow::gtl::nullopt;
  if (!previous_span_statistics_proto_string.empty()) {
    tensorflow::metadata::v0::DatasetFeatureStatistics tmp_stats;
    if (!tmp_stats.ParseFromString(previous_span_statistics_proto_string)) {
      return tensorflow::errors::InvalidArgument(
          "Failed to parse DatasetFeatureStatistics proto.");
    }
    previous_span_statistics = tmp_stats;
  }

  absl::optional<tensorflow::metadata::v0::DatasetFeatureStatistics>
      serving_statistics = tensorflow::gtl::nullopt;
  if (!serving_statistics_proto_string.empty()) {
    tensorflow::metadata::v0::DatasetFeatureStatistics tmp_stats;
    if (!tmp_stats.ParseFromString(serving_statistics_proto_string)) {
      return tensorflow::errors::InvalidArgument(
          "Failed to parse DatasetFeatureStatistics proto.");
    }
    serving_statistics = tmp_stats;
  }

  absl::optional<tensorflow::metadata::v0::DatasetFeatureStatistics>
      previous_version_statistics = tensorflow::gtl::nullopt;
  if (!previous_version_statistics_proto_string.empty()) {
    tensorflow::metadata::v0::DatasetFeatureStatistics tmp_stats;
    if (!tmp_stats.ParseFromString(previous_version_statistics_proto_string)) {
      return tensorflow::errors::InvalidArgument(
          "Failed to parse DatasetFeatureStatistics proto.");
    }
    previous_version_statistics = tmp_stats;
  }

  absl::optional<string> may_be_environment =
      tensorflow::gtl::nullopt;
  if (!environment.empty()) {
    may_be_environment = environment;
  }

  absl::optional<FeaturesNeeded> features_needed = gtl::nullopt;
  if (!features_needed_string.empty()) {
    FeaturesNeededProto parsed_proto;
    if (!parsed_proto.ParseFromString(features_needed_string)) {
      return tensorflow::errors::InvalidArgument(
          "Failed to parse FeaturesNeeded");
    }

    FeaturesNeeded parsed_feature_needed;
    TF_RETURN_IF_ERROR(
        FromFeaturesNeededProto(parsed_proto, &parsed_feature_needed));
    if (!parsed_feature_needed.empty()) {
      features_needed = parsed_feature_needed;
    }
  }

  data_validation::ValidationConfig validation_config;
  if (!validation_config.ParseFromString(validation_config_string)) {
    return tensorflow::errors::InvalidArgument(
        "Failed to parse ValidationConfig");
  }

  tensorflow::metadata::v0::Anomalies anomalies;
  TF_RETURN_IF_ERROR(ValidateFeatureStatistics(
      feature_statistics, schema, may_be_environment, previous_span_statistics,
      serving_statistics, previous_version_statistics, features_needed,
      validation_config, enable_diff_regions, &anomalies));

  if (!anomalies.SerializeToString(anomalies_proto_string)) {
    return tensorflow::errors::Internal(
        "Could not serialize Anomalies output proto to string.");
  }
  return tensorflow::Status::OK();
}

tensorflow::Status UpdateSchema(
    const FeatureStatisticsToProtoConfig& feature_statistics_to_proto_config,
    const tensorflow::metadata::v0::Schema& schema_to_update,
    const tensorflow::metadata::v0::DatasetFeatureStatistics&
        feature_statistics,
    const absl::optional<std::vector<Path>>& paths_to_consider,
    const absl::optional<string>& environment,
    tensorflow::metadata::v0::Schema* result) {
  // TODO(b/112762449): Add full support for multi-step
  // paths from paths_to_consider.
  // In the meantime, there are two ways you could imagine
  // translating to a string:
  // 1: As below, using the last step. Since all the paths at present are just
  //    a single step, this won't break anything. Moreover, since in
  //    schema_updater.cc, we are populating the string into last_step, this
  //    is the same as the existing implementation.
  // 2: As a serialized path. This will break current designs, as the Schema
  //    Updater will incorrectly handle paths like Path({"foo.bar"}).
  // TODO(b/113295423): Clean up the optional conversions.
  const absl::optional<string> maybe_environment =
      environment ? absl::optional<string>(*environment) : absl::nullopt;

  const bool by_weight =
      DatasetStatsView(feature_statistics).WeightedStatisticsExist();
  Schema schema;
  TF_RETURN_IF_ERROR(schema.Init(schema_to_update));
  if (paths_to_consider) {
    TF_RETURN_IF_ERROR(schema.Update(
        DatasetStatsView(feature_statistics, by_weight, maybe_environment,
                         /* previous_span= */ nullptr,
                         /* serving= */ nullptr,
                         /* previous_version= */ nullptr),
        feature_statistics_to_proto_config, *paths_to_consider));
  } else {
    TF_RETURN_IF_ERROR(schema.Update(
        DatasetStatsView(feature_statistics, by_weight, maybe_environment,
                         /* previous_span= */ nullptr,
                         /* serving= */ nullptr,
                         /* previous_version= */ nullptr),
        feature_statistics_to_proto_config));
  }
  *result = schema.GetSchema();
  return tensorflow::Status::OK();
}

}  // namespace data_validation
}  // namespace tensorflow
<|endoftext|>


<commit_before>//
// Hello World client
// Connects REQ socket to tcp://localhost:5555
// Sends "Hello" to server, expects "World" back
//
#include <zmq.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <getopt.h>

#include <pthread.h>

#include "ProtocolBuffers/arangodb.pb.h"

using namespace std;

void* context = 0;
size_t loop = 10000;
size_t concurrency = 1;
size_t pipelined = 1;
char const* connection = "tcp://localhost:5555";
char const* path = "/_api/version";

void* ThreadStarter (void* data) {
  int res;
  size_t n, p;
  void* requester;

  requester = zmq_socket(context, ZMQ_REQ);
  res = zmq_connect(requester, connection);

  if (res != 0) {
    printf("ERROR zmq_connect: %d\n", errno);
    exit(EXIT_FAILURE);
  }

  printf("connected\n");

  for (n = 0; n < loop; n += pipelined) {
    zmq_msg_t request;
    zmq_msg_t reply;

    PB_ArangoMessage messages;
    PB_ArangoBatchMessage* batch;
    PB_ArangoBlobRequest* blob;

    for (p = 0; p < pipelined; p++) {
      batch = messages.add_messages();

      batch->set_type(PB_BLOB_REQUEST);
      blob = batch->mutable_request();

      blob->set_requesttype(PB_REQUEST_TYPE_GET);
      blob->set_url(path);
      blob->set_contenttype(PB_NO_CONTENT);
      blob->set_contentlength(0);
      blob->set_content("");
    }

    string data;
    messages.SerializeToString(&data);

    // send
    zmq_msg_init_size(&request, data.size());
    memcpy(zmq_msg_data(&request), data.c_str(), data.size());

    res = zmq_send(requester, &request, 0);

    if (res != 0) {
      printf("ERROR zmq_send: %d %d %s\n", (int) res, (int) errno, strerror(errno));
    }

    zmq_msg_close(&request);

    // receive
    zmq_msg_init(&reply);

    res = zmq_recv(requester, &reply, 0);

    if (res != 0) {
      printf("ERROR zmq_recv: %d %d %s\n", (int) res, (int) errno, strerror(errno));
    }

    zmq_msg_close(&reply);
  }

  zmq_close(requester);

  return 0;
}

/* Return 1 if the difference is negative, otherwise 0.  */
int timeval_subtract(struct timeval* result, struct timeval* t2, struct timeval* t1) {
  long int diff = (t2->tv_usec + 1000000 * t2->tv_sec) - (t1->tv_usec + 1000000 * t1->tv_sec);
  result->tv_sec = diff / 1000000;
  result->tv_usec = diff % 1000000;

  return (diff<0);
}

int main (int argc, char* argv[]) {
  struct timeval start, end, result;
  float rps, runtime;
  size_t i;
  int opt;
  pthread_t* threads;

// Aufruf:
//
// -C <zeromq-connection>
// -u <path>            where <path> is of the form "/_api/version"
// -h <key> <value>     where <key> is converted to all lowercase
// -v <key> <value>
// -P <pipeline>        send <number> request in one message
// -c <concurrency>     use <concurrency> parallel threads
// -n <count>           send a total of <count> requests

  while ((opt = getopt(argc, argv, "C:u:h:P:c:n:")) != -1) {
    switch (opt) {
      case 'C':
        connection = optarg;
        break;
      case 'u':
        path = optarg;
        break;
      case 'h':
        // TODO
        break;
      case 'P':
        pipelined = atoi(optarg);
        if (pipelined < 1) {
          fprintf(stderr, "pipeline argument must be at least 1\n");
          exit(EXIT_FAILURE);
        }
        break;
      case 'c':
        concurrency = atoi(optarg);
        if (concurrency < 1) {
          fprintf(stderr, "concurrency must be at least 1\n");
          exit(EXIT_FAILURE);
        }
        break;
      case 'n':
        loop = atoi(optarg);
        break;
      default: /* '?' */
        fprintf(stderr, "Usage: %s [-C connection] [-u path] [-h key value] [-P pipeline] [-c concurrency] [-n count]\n", argv[0]);
        exit(EXIT_FAILURE);
    }
  }

  printf("Looping %d times per thread, total %d, pipelined %d\n", (int) loop, (int) (loop * concurrency), (int) pipelined);
  printf("Concurrency %d\n", (int) concurrency);
  printf("Connection %s\n", connection);

  context = zmq_init(16);

  // Socket to talk to server
  printf("Connecting to server…\n");

  threads = (pthread_t*) malloc(sizeof(pthread_t) * concurrency);

  for (i = 0;  i < concurrency;  ++i) {
    pthread_create(&threads[i], 0, &ThreadStarter, 0);
  }

  gettimeofday(&start, 0);

  for (i = 0;  i < concurrency;  ++i) {
    pthread_join(threads[i], 0);
  }

  gettimeofday(&end, 0);
  timeval_subtract(&result, &end, &start);
  runtime = (float) result.tv_sec + (float) ((float) result.tv_usec / 1000000.0);

  rps = (float) loop * (float) concurrency / runtime;
  printf("runtime %f sec, req/sec %f, req/sec/thread %f\n", runtime, rps, rps / (float) concurrency);

  zmq_term(context);
  free(threads);

  return 0;
}
<commit_msg>added option to specify arbitrary values in body<commit_after>//
// Hello World client
// Connects REQ socket to tcp://localhost:5555
// Sends "Hello" to server, expects "World" back
//
#include <zmq.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <getopt.h>
#include <pthread.h>

#include <string>
#include <map>
#include <algorithm>
#include <iostream>

#include "ProtocolBuffers/arangodb.pb.h"

using namespace std;

void* context = 0;

// default values
size_t loop = 10000;
size_t concurrency = 1;
size_t pipelined = 1;
char const* connection = "tcp://localhost:5555";
char const* path = "/_api/version";
bool verbose = false;
map<string, string> headers;
map<string, string> values;

void* ThreadStarter (void* data) {
  int res;
  size_t n;
  void* requester;

  requester = zmq_socket(context, ZMQ_REQ);
  res = zmq_connect(requester, connection);

  if (res != 0) {
    printf("ERROR zmq_connect: %d\n", errno);
    exit(EXIT_FAILURE);
  }

  if (verbose) {
    printf("connected\n");
  }

  for (n = 0; n < loop; n += pipelined) {
    zmq_msg_t request;
    zmq_msg_t reply;

    PB_ArangoMessage messages;
    PB_ArangoBatchMessage* batch;
    PB_ArangoBlobRequest* blob;
    PB_ArangoKeyValue* kv;

    for (size_t p = 0; p < pipelined; p++) {
      batch = messages.add_messages();

      batch->set_type(PB_BLOB_REQUEST);
      blob = batch->mutable_request();

      map<string, string>::iterator it;

      for (it = headers.begin(); it != headers.end(); ++it) {
        kv = blob->add_headers();
        kv->set_key((*it).first);
        kv->set_value((*it).second);
      }

      for (it = values.begin(); it != values.end(); ++it) {
        kv = blob->add_values();
        kv->set_key((*it).first);
        kv->set_value((*it).second);
      }

      blob->set_requesttype(PB_REQUEST_TYPE_GET);
      blob->set_url(path);
      blob->set_contenttype(PB_NO_CONTENT);
      blob->set_contentlength(0);
      blob->set_content("");
    }

    string data;
    messages.SerializeToString(&data);

    // send
    zmq_msg_init_size(&request, data.size());
    memcpy(zmq_msg_data(&request), data.c_str(), data.size());

    res = zmq_send(requester, &request, 0);

    if (res != 0) {
      printf("ERROR zmq_send: %d %d %s\n", (int) res, (int) errno, strerror(errno));
    }

    zmq_msg_close(&request);

    // receive
    zmq_msg_init(&reply);

    res = zmq_recv(requester, &reply, 0);

    if (res != 0) {
      printf("ERROR zmq_recv: %d %d %s\n", (int) res, (int) errno, strerror(errno));
    }

    zmq_msg_close(&reply);
  }

  zmq_close(requester);

  return 0;
}

/* Return 1 if the difference is negative, otherwise 0.  */
int timeval_subtract(struct timeval* result, struct timeval* t2, struct timeval* t1) {
  long int diff = (t2->tv_usec + 1000000 * t2->tv_sec) - (t1->tv_usec + 1000000 * t1->tv_sec);
  result->tv_sec = diff / 1000000;
  result->tv_usec = diff % 1000000;

  return (diff<0);
}

void addHeader (char* arg) {
  string header(arg);
  size_t found = header.find('=', 0);

  if (found == string::npos) {
    fprintf(stderr, "invalid header %s\n", arg);
    exit(EXIT_FAILURE);
  }

  string key(header.substr(0, found));
  string value(header.substr(found + 1, header.length() - found - 1));

  std::transform(key.begin(), key.end(), key.begin(), ::tolower);
  headers[key] = value;
}

void addValue (char* arg) {
  string data(arg);
  size_t found = data.find('=', 0);

  if (found == string::npos) {
    fprintf(stderr, "invalid value %s\n", arg);
    exit(EXIT_FAILURE);
  }

  string key(data.substr(0, found));
  string value(data.substr(found + 1, data.length() - found - 1));

  values[key] = value;
}

int main (int argc, char* argv[]) {
  struct timeval start, end, result;
  float rps, runtime;
  size_t i;
  int opt;
  pthread_t* threads;

// Aufruf:
//
// -C <zeromq-connection>
// -u <path>            where <path> is of the form "/_api/version"
// -h <key> <value>     where <key> is converted to all lowercase
// -v <key> <value>
// -P <pipeline>        send <number> request in one message
// -c <concurrency>     use <concurrency> parallel threads
// -n <count>           send a total of <count> requests

  while ((opt = getopt(argc, argv, "C:u:h:v:P:c:n:d")) != -1) {
    switch (opt) {
      case 'C':
        connection = optarg;
        break;
      case 'u':
        path = optarg;
        break;
      case 'h':
        addHeader(optarg);
        break;
      case 'v':
        addValue(optarg);
        break;
      case 'P':
        pipelined = atoi(optarg);
        if (pipelined < 1) {
          fprintf(stderr, "pipeline argument must be at least 1\n");
          exit(EXIT_FAILURE);
        }
        break;
      case 'c':
        concurrency = atoi(optarg);
        if (concurrency < 1) {
          fprintf(stderr, "concurrency must be at least 1\n");
          exit(EXIT_FAILURE);
        }
        break;
      case 'n':
        loop = atoi(optarg);
        break;
      case 'd':
        verbose = true;
        break;
      default: /* '?' */
        fprintf(stderr, "Usage: %s [-C connection] [-u path] [-h \"key=value\"] [-v \"key=value\"] [-P pipeline] [-c concurrency] [-n count] [-d]\n", argv[0]);
        exit(EXIT_FAILURE);
    }
  }

  printf("Looping %d times per thread, total %d, pipelined %d\n", (int) loop, (int) (loop * concurrency), (int) pipelined);
  printf("Concurrency %d\n", (int) concurrency);
  printf("Connection %s\n", connection);

  context = zmq_init(16);

  if (verbose) {
    printf("Connecting to server…\n");
  }

  threads = (pthread_t*) malloc(sizeof(pthread_t) * concurrency);

  for (i = 0;  i < concurrency;  ++i) {
    pthread_create(&threads[i], 0, &ThreadStarter, 0);
  }

  gettimeofday(&start, 0);

  for (i = 0;  i < concurrency;  ++i) {
    pthread_join(threads[i], 0);
  }

  gettimeofday(&end, 0);
  timeval_subtract(&result, &end, &start);
  runtime = (float) result.tv_sec + (float) ((float) result.tv_usec / 1000000.0);

  rps = (float) loop * (float) concurrency / runtime;
  printf("runtime %f sec, req/sec %f, req/sec/thread %f\n", runtime, rps, rps / (float) concurrency);

  zmq_term(context);
  free(threads);

  threads = 0;
  context = 0;

  return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) [2016-2017] SUSE LLC
 *
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as published
 * by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, contact Novell, Inc.
 *
 * To contact Novell about this file by physical or electronic mail, you may
 * find current contact information at www.novell.com.
 */

#include <boost/math/common_factor_rt.hpp>

#include "storage/Utils/AlignmentImpl.h"
#include "storage/Utils/ExceptionImpl.h"

namespace storage
{

    unsigned long
    Alignment::Impl::calculate_grain() const
    {
	unsigned long grain = std::max(topology.get_optimal_io_size(), 1UL);

	while (grain < topology.get_minimal_grain())
	    grain *= 2;

	if (extra_grain != 0)
	    grain = boost::math::lcm(grain, extra_grain);

	return grain;
    }

    bool
    Alignment::Impl::align_block_in_place(unsigned long long& block, unsigned long block_size,
					  Location location) const
    {
	long alignment_offset_in_blocks = topology.get_alignment_offset() / block_size;
	unsigned long grain_in_blocks = calculate_grain() / block_size;

	block -= alignment_offset_in_blocks;

	switch (location)
	{
	    case Location::START: {
		unsigned long long rest = block % grain_in_blocks;
		if (rest != 0)
		    block += grain_in_blocks - rest;
	    } break;

	    case Location::END: {
		unsigned long long rest = (block + 1) % grain_in_blocks;
		if (rest > block)
		    return false;
		block -= rest;
	    } break;
	}

	block += alignment_offset_in_blocks;

	return true;
    }

    bool
    Alignment::Impl::align_region_in_place(Region& region, AlignPolicy align_policy) const
    {
	unsigned long block_size = region.get_block_size();

	unsigned long long start = region.get_start();
	if (!align_block_in_place(start, block_size, Location::START))
	    return false;

	unsigned long long length = 0;
	switch (align_policy)
	{
	    case AlignPolicy::ALIGN_END: {
		unsigned long long end = region.get_end();
		if (!align_block_in_place(end, block_size, Location::END))
		    return false;
		if (end + 1 <= start)
		    return false;
		length = end - start + 1;
	    } break;

	    case AlignPolicy::KEEP_SIZE: {
		length = region.get_length();
	    } break;

	    case AlignPolicy::KEEP_END: {
		unsigned long long delta = start - region.get_start();
		if (region.get_length() <= delta)
		    return false;
		length = region.get_length() - delta;
	    } break;
	}

	region = Region(start, length, region.get_block_size());
	return true;
    }

    bool
    Alignment::Impl::can_be_aligned(const Region& region, AlignPolicy align_policy) const
    {
	Region tmp(region);
	return align_region_in_place(tmp, align_policy);
    }

    Region
    Alignment::Impl::align(const Region& region, AlignPolicy align_policy) const
    {
	Region tmp(region);
	if (!align_region_in_place(tmp, align_policy))
	    ST_THROW(AlignError());

	return tmp;
    }

    std::ostream&
    operator<<(std::ostream& s, const Alignment::Impl& impl)
    {
	s << "topology:" << impl.topology;

	if (impl.extra_grain != 0)
	    s << " extra-grain:" << impl.extra_grain << " B";

	return s;
    }

}
<commit_msg>- nicer check<commit_after>/*
 * Copyright (c) [2016-2017] SUSE LLC
 *
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as published
 * by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, contact Novell, Inc.
 *
 * To contact Novell about this file by physical or electronic mail, you may
 * find current contact information at www.novell.com.
 */

#include <boost/math/common_factor_rt.hpp>

#include "storage/Utils/AlignmentImpl.h"
#include "storage/Utils/ExceptionImpl.h"

namespace storage
{

    unsigned long
    Alignment::Impl::calculate_grain() const
    {
	unsigned long grain = std::max(topology.get_optimal_io_size(), 1UL);

	while (grain < topology.get_minimal_grain())
	    grain *= 2;

	if (extra_grain > 0)
	    grain = boost::math::lcm(grain, extra_grain);

	return grain;
    }

    bool
    Alignment::Impl::align_block_in_place(unsigned long long& block, unsigned long block_size,
					  Location location) const
    {
	long alignment_offset_in_blocks = topology.get_alignment_offset() / block_size;
	unsigned long grain_in_blocks = calculate_grain() / block_size;

	block -= alignment_offset_in_blocks;

	switch (location)
	{
	    case Location::START: {
		unsigned long long rest = block % grain_in_blocks;
		if (rest != 0)
		    block += grain_in_blocks - rest;
	    } break;

	    case Location::END: {
		unsigned long long rest = (block + 1) % grain_in_blocks;
		if (rest > block)
		    return false;
		block -= rest;
	    } break;
	}

	block += alignment_offset_in_blocks;

	return true;
    }

    bool
    Alignment::Impl::align_region_in_place(Region& region, AlignPolicy align_policy) const
    {
	unsigned long block_size = region.get_block_size();

	unsigned long long start = region.get_start();
	if (!align_block_in_place(start, block_size, Location::START))
	    return false;

	unsigned long long length = 0;
	switch (align_policy)
	{
	    case AlignPolicy::ALIGN_END: {
		unsigned long long end = region.get_end();
		if (!align_block_in_place(end, block_size, Location::END))
		    return false;
		if (end + 1 <= start)
		    return false;
		length = end - start + 1;
	    } break;

	    case AlignPolicy::KEEP_SIZE: {
		length = region.get_length();
	    } break;

	    case AlignPolicy::KEEP_END: {
		unsigned long long delta = start - region.get_start();
		if (region.get_length() <= delta)
		    return false;
		length = region.get_length() - delta;
	    } break;
	}

	region = Region(start, length, region.get_block_size());
	return true;
    }

    bool
    Alignment::Impl::can_be_aligned(const Region& region, AlignPolicy align_policy) const
    {
	Region tmp(region);
	return align_region_in_place(tmp, align_policy);
    }

    Region
    Alignment::Impl::align(const Region& region, AlignPolicy align_policy) const
    {
	Region tmp(region);
	if (!align_region_in_place(tmp, align_policy))
	    ST_THROW(AlignError());

	return tmp;
    }

    std::ostream&
    operator<<(std::ostream& s, const Alignment::Impl& impl)
    {
	s << "topology:" << impl.topology;

	if (impl.extra_grain != 0)
	    s << " extra-grain:" << impl.extra_grain << " B";

	return s;
    }

}
<|endoftext|>


<commit_before>#include "Shader.hpp"

#include "Window.hpp"
#include "Utils.hpp"

void Shader::CheckAttribs()
{
    // Check for max Attribs
    GLint nrAttributes;
    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
    std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;
}

void Shader::SetupShaders(std::string vertFilename, std::string fragFilename)
{
    const auto& paths = Utils::GetResourcePaths();

    // Load Shaders
    // Retrieve the vertex/fragment source code from filePath
    std::string   vertexCode, fragmentCode;
    std::ifstream vShaderFile, fShaderFile;

    // Ensures ifstream objects can throw exceptions:
    vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);

    try
    {
        printf("Loading: %s\n", vertFilename.c_str());
        printf("Loading: %s\n", fragFilename.c_str());

        for (const std::string& p : paths) {
            std::string fullVertFilename = p + "/" + vertFilename;
            std::string fullFragFilename = p + "/" + fragFilename;

            // Open files
            vShaderFile.open(fullVertFilename);
            fShaderFile.open(fullFragFilename);

            if (vShaderFile && fShaderFile) break;
        }

        std::stringstream vShaderStream, fShaderStream;

        // Read files buffer contents into streams
        vShaderStream << vShaderFile.rdbuf();
        fShaderStream << fShaderFile.rdbuf();

        // Close file
        vShaderFile.close();
        fShaderFile.close();

        // Convert stream into GLchar array
        vertexCode   = vShaderStream.str();
        fragmentCode = fShaderStream.str();
    }
    catch (std::ifstream::failure e)
    {
        std::cout << "ERROR::SHADER::FILE_NOT_READ_SUCCESSFULLY" << std::endl;
    }

    const GLchar* vShaderCode = vertexCode.c_str();
    const GLchar* fShaderCode = fragmentCode.c_str();

    // Shader & Program Init
    GLuint vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vShaderCode, NULL);
    glCompileShader(vertexShader);

    GLint  success;
    GLchar infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    GLuint fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fShaderCode, NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

	_mID = glCreateProgram();

    glAttachShader(_mID, vertexShader);
    glAttachShader(_mID, fragmentShader);
    glLinkProgram(_mID);

    glGetProgramiv(_mID, GL_LINK_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(_mID, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
}

void Shader::Destroy()
{
	glUseProgram(_mID);
	glDeleteProgram(_mID);
}
<commit_msg>Fixed shader loading<commit_after>#include "Shader.hpp"

#include "Window.hpp"
#include "Utils.hpp"

void Shader::CheckAttribs()
{
    // Check for max Attribs
    GLint nrAttributes;
    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
    std::cout << "Maximum nr of vertex attributes supported: " << nrAttributes << std::endl;
}

void Shader::SetupShaders(std::string vertFilename, std::string fragFilename)
{
    const auto& paths = Utils::GetResourcePaths();

    // Load Shaders
    // Retrieve the vertex/fragment source code from filePath
    std::ifstream vertShaderFile;
    std::ifstream fragShaderFile;

    printf("Loading: [%s]\n", vertFilename.c_str());
    printf("Loading: [%s]\n", fragFilename.c_str());

    bool loaded = false;
    for (const std::string& p : paths) {
        std::string fullVertFilename = p + "/" + vertFilename;
        std::string fullFragFilename = p + "/" + fragFilename;

        vertShaderFile.open(fullVertFilename);
        fragShaderFile.open(fullFragFilename);

        if (vertShaderFile.is_open() && fragShaderFile.is_open()) {
            loaded = true;
            break;
        }
    }

    if (!loaded) {
        fprintf(stderr, "Failed to load shaders [%s] [%s]\n", vertFilename.c_str(), fragFilename.c_str());
        return;
    }

    std::string vertCode((std::istreambuf_iterator<char>(vertShaderFile)),
                         std::istreambuf_iterator<char>());
    std::string fragCode((std::istreambuf_iterator<char>(fragShaderFile)),
                         std::istreambuf_iterator<char>());

    vertShaderFile.close();
    fragShaderFile.close();

    const GLchar* vShaderCode = vertCode.c_str();
    const GLchar* fShaderCode = fragCode.c_str();

    // Shader & Program Init
    GLuint vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vShaderCode, NULL);
    glCompileShader(vertexShader);

    GLint  success;
    GLchar infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    GLuint fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fShaderCode, NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

	_mID = glCreateProgram();

    glAttachShader(_mID, vertexShader);
    glAttachShader(_mID, fragmentShader);
    glLinkProgram(_mID);

    glGetProgramiv(_mID, GL_LINK_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(_mID, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
}

void Shader::Destroy()
{
	glUseProgram(_mID);
	glDeleteProgram(_mID);
}
<|endoftext|>


<commit_before>#include <array>
#include <fstream>
#include <iostream>
#include "bicycle.h"

namespace model {

const double g = 9.80665; // gravitational constant [m/s^2]

Bicycle::Bicycle(const char* param_file, double v, double dt,
        state_space_map_t const* discrete_state_space_map) :
    m_expAT(m_AT), m_discrete_state_space_map(discrete_state_space_map) {
    // set M, C1, K0, K2 matrices from file
    set_matrices_from_file(param_file);

    // initialize state space matrices to zero
    m_A.setZero();
    m_B.setZero();
    m_C.setZero();
    m_D.setZero();
    m_Ad.setZero();
    m_Bd.setZero();

    // matrix used for calculating discrete time state space matrices
    // a reference of this matrix must be provided to the MatrixExponential class
    m_AT.setZero();

    // set top right block to identity
    m_A.topRightCorner<o, o>().setIdentity();
    // set lower half of input matrix
    m_B.bottomLeftCorner<o, o>() = m_M.inverse();
    // set forward speed and (optionally sampling time) and update state matrix
    set_v(v, dt);
}

void Bicycle::set_matrices_from_file(const char* param_file) {
    const unsigned int num_elem = o*o;
    std::array<double, 4*num_elem> buffer;

    std::fstream pf(param_file, std::ios_base::in);
    for (auto& d: buffer) {
        pf >> d;
    }
    pf.close();

    m_M = Eigen::Map<second_order_matrix_t>(buffer.data()).transpose();
    m_C1 = Eigen::Map<second_order_matrix_t>(buffer.data() + num_elem).transpose();
    m_K0 = Eigen::Map<second_order_matrix_t>(buffer.data() + 2*num_elem).transpose();
    m_K2 = Eigen::Map<second_order_matrix_t>(buffer.data() + 3*num_elem).transpose();
}

Bicycle::state_t Bicycle::x_next(const Bicycle::state_t& x, const Bicycle::input_t& u) const {
    return m_Ad*x + m_Bd*u;
}

Bicycle::output_t Bicycle::y(const Bicycle::state_t& x, const Bicycle::input_t& u) const {
    return m_C*x + m_D*u;
}

Bicycle::state_t Bicycle::x_next(const Bicycle::state_t& x) const {
    return m_Ad*x;
}

Bicycle::output_t Bicycle::y(const Bicycle::state_t& x) const {
    return m_C*x;
}

Bicycle::state_t Bicycle::x_integrate(const Bicycle::state_t& x, const Bicycle::input_t& u, double dt) const {
    odeint_state_t xu;
    odeint_state_t xout;

    xu << x, u;
    m_stepper.do_step([this](const odeint_state_t& xu, odeint_state_t& dxdt, const double t) -> void {
                dxdt.block<n, 1>(0, 0) = m_A*xu.block<n, 1>(0, 0) + m_B*xu.block<m, 1>(n, 0);
            }, xu, 0.0, xout, dt);
    return xout.block<n, 1>(0, 0);
}

Bicycle::state_t Bicycle::x_integrate(const Bicycle::state_t& x, double dt) const {
    state_t xout;

    m_stepper_noinput.do_step([this](const state_t& x, state_t& dxdt, const double t) -> void {
                dxdt = m_A*x;
            }, x, 0.0, xout, dt);
    return xout;
}

void Bicycle::set_v(double v, double dt) {
    /* system state space is parameterized by forward speed v
     * this function sets forward speed and calculates the state space matrices
     * additionally, calculates discrete time state space if sampling time is nonzero
     */
    m_v = v;
    m_dt = dt;

    // M is positive definite so use the Cholskey decomposition in solving the linear system
    m_A.bottomLeftCorner<o, o>() = -m_M.llt().solve(g*m_K0 + m_v*m_v*m_K2);
    m_A.bottomRightCorner<o, o>() = -m_M.llt().solve(m_v*m_C1);

    if (m_dt == 0.0) { // discrete time state does not change
        m_AT.setZero();
        m_Ad.setIdentity();
        m_Bd.setZero();
    } else {
        m_AT = m_A*dt;
        state_space_map_key_t k = make_state_space_map_key(v, dt);
        if (!discrete_state_space_lookup(k)) {
            m_expAT.compute(m_Ad);
            Eigen::FullPivHouseholderQR<state_matrix_t> A_qr(m_A);
            // TODO: Investigate threshold.
            // Current threshold only results in capsize speed as rank deficient, not weave speed.
            A_qr.setThreshold(1e-5);
            if (A_qr.rank() < n) {
                std::cout << "Warning: A is (near) singular and a precomputed Bd has not been " <<
                    "provided in the discrete state space map.\nComputation of Bd may be inaccurate.\n";
            }
            m_Bd = A_qr.solve((m_Ad - state_matrix_t::Identity())*m_B);
        }
    }
}

bool Bicycle::discrete_state_space_lookup(const state_space_map_key_t& k) {
    if (m_discrete_state_space_map == nullptr) {
        return false;
    }
    auto search = m_discrete_state_space_map->find(k);
    if (search == m_discrete_state_space_map->end()) {
        return false;
    }

    // discrete state space matrices Ad, Bd have been provided for speed v.
    m_Ad = search->second.first;
    m_Bd = search->second.second;
    return true;
}

} // namespace model
<commit_msg>Suppress unused parameter warning in integrators<commit_after>#include <array>
#include <fstream>
#include <iostream>
#include "bicycle.h"

namespace model {

const double g = 9.80665; // gravitational constant [m/s^2]

Bicycle::Bicycle(const char* param_file, double v, double dt,
        state_space_map_t const* discrete_state_space_map) :
    m_expAT(m_AT), m_discrete_state_space_map(discrete_state_space_map) {
    // set M, C1, K0, K2 matrices from file
    set_matrices_from_file(param_file);

    // initialize state space matrices to zero
    m_A.setZero();
    m_B.setZero();
    m_C.setZero();
    m_D.setZero();
    m_Ad.setZero();
    m_Bd.setZero();

    // matrix used for calculating discrete time state space matrices
    // a reference of this matrix must be provided to the MatrixExponential class
    m_AT.setZero();

    // set top right block to identity
    m_A.topRightCorner<o, o>().setIdentity();
    // set lower half of input matrix
    m_B.bottomLeftCorner<o, o>() = m_M.inverse();
    // set forward speed and (optionally sampling time) and update state matrix
    set_v(v, dt);
}

void Bicycle::set_matrices_from_file(const char* param_file) {
    const unsigned int num_elem = o*o;
    std::array<double, 4*num_elem> buffer;

    std::fstream pf(param_file, std::ios_base::in);
    for (auto& d: buffer) {
        pf >> d;
    }
    pf.close();

    m_M = Eigen::Map<second_order_matrix_t>(buffer.data()).transpose();
    m_C1 = Eigen::Map<second_order_matrix_t>(buffer.data() + num_elem).transpose();
    m_K0 = Eigen::Map<second_order_matrix_t>(buffer.data() + 2*num_elem).transpose();
    m_K2 = Eigen::Map<second_order_matrix_t>(buffer.data() + 3*num_elem).transpose();
}

Bicycle::state_t Bicycle::x_next(const Bicycle::state_t& x, const Bicycle::input_t& u) const {
    return m_Ad*x + m_Bd*u;
}

Bicycle::output_t Bicycle::y(const Bicycle::state_t& x, const Bicycle::input_t& u) const {
    return m_C*x + m_D*u;
}

Bicycle::state_t Bicycle::x_next(const Bicycle::state_t& x) const {
    return m_Ad*x;
}

Bicycle::output_t Bicycle::y(const Bicycle::state_t& x) const {
    return m_C*x;
}

Bicycle::state_t Bicycle::x_integrate(const Bicycle::state_t& x, const Bicycle::input_t& u, double dt) const {
    odeint_state_t xu;
    odeint_state_t xout;

    xu << x, u;
    m_stepper.do_step([this](const odeint_state_t& xu, odeint_state_t& dxdt, const double t) -> void {
                (void)t;
                dxdt.block<n, 1>(0, 0) = m_A*xu.block<n, 1>(0, 0) + m_B*xu.block<m, 1>(n, 0);
            }, xu, 0.0, xout, dt);
    return xout.block<n, 1>(0, 0);
}

Bicycle::state_t Bicycle::x_integrate(const Bicycle::state_t& x, double dt) const {
    state_t xout;

    m_stepper_noinput.do_step([this](const state_t& x, state_t& dxdt, const double t) -> void {
                (void)t;
                dxdt = m_A*x;
            }, x, 0.0, xout, dt);
    return xout;
}

void Bicycle::set_v(double v, double dt) {
    /* system state space is parameterized by forward speed v
     * this function sets forward speed and calculates the state space matrices
     * additionally, calculates discrete time state space if sampling time is nonzero
     */
    m_v = v;
    m_dt = dt;

    // M is positive definite so use the Cholskey decomposition in solving the linear system
    m_A.bottomLeftCorner<o, o>() = -m_M.llt().solve(g*m_K0 + m_v*m_v*m_K2);
    m_A.bottomRightCorner<o, o>() = -m_M.llt().solve(m_v*m_C1);

    if (m_dt == 0.0) { // discrete time state does not change
        m_AT.setZero();
        m_Ad.setIdentity();
        m_Bd.setZero();
    } else {
        m_AT = m_A*dt;
        state_space_map_key_t k = make_state_space_map_key(v, dt);
        if (!discrete_state_space_lookup(k)) {
            m_expAT.compute(m_Ad);
            Eigen::FullPivHouseholderQR<state_matrix_t> A_qr(m_A);
            // TODO: Investigate threshold.
            // Current threshold only results in capsize speed as rank deficient, not weave speed.
            A_qr.setThreshold(1e-5);
            if (A_qr.rank() < n) {
                std::cout << "Warning: A is (near) singular and a precomputed Bd has not been " <<
                    "provided in the discrete state space map.\nComputation of Bd may be inaccurate.\n";
            }
            m_Bd = A_qr.solve((m_Ad - state_matrix_t::Identity())*m_B);
        }
    }
}

bool Bicycle::discrete_state_space_lookup(const state_space_map_key_t& k) {
    if (m_discrete_state_space_map == nullptr) {
        return false;
    }
    auto search = m_discrete_state_space_map->find(k);
    if (search == m_discrete_state_space_map->end()) {
        return false;
    }

    // discrete state space matrices Ad, Bd have been provided for speed v.
    m_Ad = search->second.first;
    m_Bd = search->second.second;
    return true;
}

} // namespace model
<|endoftext|>


<commit_before>#include "OSD.h"

#include "../resource.h"

OSD::OSD(HINSTANCE hInstance, LPCWSTR tabTemplate, LPCWSTR title) :
SettingsTab(hInstance, tabTemplate, title) {

}

void OSD::Initialize() {

}

void OSD::LoadSettings() {

}

void OSD::SaveSettings() {

}<commit_msg>Add OSDs to the lsit<commit_after>#include "OSD.h"

#include "../resource.h"

OSD::OSD(HINSTANCE hInstance, LPCWSTR tabTemplate, LPCWSTR title) :
SettingsTab(hInstance, tabTemplate, title) {

}

void OSD::Initialize() {
    ListBox *lb = new ListBox(LST_OSDS, *this);
    lb->AddItem(L"Volume");
    lb->AddItem(L"Brightness");
    lb->AddItem(L"Eject");
    lb->AddItem(L"Keyboard");
}

void OSD::LoadSettings() {

}

void OSD::SaveSettings() {

}<|endoftext|>


<commit_before>//
//  SwingGame.cpp
//  SwingGame
//
//  Created by Tim Brier on 26/09/2014.
//  Copyright (c) 2014 tbrier. All rights reserved.
//

// =============================================================================
// Include Files
// -----------------------------------------------------------------------------
#include "CSwingGame.hpp"
#include "CTextFrontEnd.hpp"
#include "CTextureBank.hpp"
#include "CLevel.hpp"
#include "CGameOptions.hpp"
#include <sstream>

// =============================================================================
// Static members
// -----------------------------------------------------------------------------
bool                        CSwingGame::smExitRequested = false;
EGameState                  CSwingGame::smGameState = kGameStateFrontEnd;
std::list<CUpdateable *>    CSwingGame::smTheUpdateables;
std::list<CUpdateable *>    CSwingGame::smTheUpdateablesToAdd;
std::list<CUpdateable *>    CSwingGame::smTheUpdateablesToRemove;
std::list<CDrawable *>      CSwingGame::smTheDrawables;
std::list<CEvent>           CSwingGame::smTheKeyPresses;
CGameLocation               *CSwingGame::smCurrentLocation = NULL;

// =============================================================================
// CSwingGame constructor/destructor
// -----------------------------------------------------------------------------
CSwingGame::CSwingGame() :  mWindowTitle("SwingGame v0.0"),
                            mWindow(NULL),
                            mFPS(0),
                            mUPS(0),
                            mExitCode(EXIT_SUCCESS)
{

}

CSwingGame::~CSwingGame()
{

}

// =============================================================================
// SwingGame::Init
// Initialise the game
// -----------------------------------------------------------------------------
void CSwingGame::Init()
{
    // Create the game window
    mWindow = new CWindow(CGameOptions::smWindowWidth,
                          CGameOptions::smWindowHeight,
                          mWindowTitle);

    // Enter the front end menu
    GoToLocation(kGameLocationFrontEnd);

    // Initialise other systems
    InitSFML(mWindow);
}

// =============================================================================
// SwingGame::Run
// Enter the main loop, returns program exit code
// -----------------------------------------------------------------------------
int CSwingGame::Run()
{
    CClock theClock;

    while (mWindow->isOpen())
    {
        CTime elapsedTime = theClock.restart();

        static CTime accumulatingTime;
        accumulatingTime += elapsedTime;

        ProcessEvents();

        Update(elapsedTime);

        // Only render if vsync is off or enough time has past
        if (!CGameOptions::smVsync
            || accumulatingTime.asSeconds() >= 1.0f / CGameOptions::smMaxFPS)
        {
            accumulatingTime = CTime();
            Render();
        }
    }

    return mExitCode;
}

// =============================================================================
// SwingGame::Cleanup
// Cleanup before quitting
// -----------------------------------------------------------------------------
void CSwingGame::Cleanup()
{
    SAFE_DELETE(mWindow);
    SAFE_DELETE(smCurrentLocation);
    CTextUtilities::Cleanup();
    CTextureBank::Cleanup();
}

// =============================================================================
// CSwingGame::ExitGame
// Exit the game
// -----------------------------------------------------------------------------
void CSwingGame::ExitGame()
{
    DEBUG_LOG("Exit requested");
    smExitRequested = true;
}

// =============================================================================
// CSwingGame::SetGameState
// Set given GameState flags
// -----------------------------------------------------------------------------
void CSwingGame::SetGameState(EGameState theState)
{
    smGameState = static_cast<EGameState>(smGameState | theState);
}

// =============================================================================
// CSwingGame::UnsetGameState
// Unset the given GameState flags
// -----------------------------------------------------------------------------
void CSwingGame::UnsetGameState(EGameState theState)
{
    smGameState = static_cast<EGameState>(smGameState & ~theState);
}

// =============================================================================
// CSwingGame::HasAllGameStates
// Returns true only if the current state has all the given flags
// -----------------------------------------------------------------------------
bool CSwingGame::HasAllGameStates(EGameState theState)
{
    EGameState theResult = static_cast<EGameState>(smGameState & theState);
    return theResult == theState;
}

// =============================================================================
// CSwingGame::RegisterUpdateable
// Add an updateable to the list
// -----------------------------------------------------------------------------
void CSwingGame::RegisterUpdateable(CUpdateable *theUpdateable)
{
    // If we're not updating then we can add it now, otherwise add it to a list
    // to be added after the current update cycle
    if (!HasAllGameStates(kGameStateUpdating))
    {
        smTheUpdateables.push_back(theUpdateable);
    }
    else
    {
        smTheUpdateablesToAdd.push_back(theUpdateable);
    }
}

// =============================================================================
// CSwingGame::RegisterDrawable
// Add a drawable to the list
// -----------------------------------------------------------------------------
void CSwingGame::RegisterDrawable(CDrawable *theDrawable)
{
    smTheDrawables.push_back(theDrawable);
}

// =============================================================================
// CSwingGame::UnregisterUpdateable
// Remove a given updateable from the list
// -----------------------------------------------------------------------------
void CSwingGame::UnregisterUpdateable(CUpdateable *theUpdateable)
{
    // If we're not updating go ahead and remove it, otherwise add it to a list
    // to be removed after the current update cycle
    if (!HasAllGameStates(kGameStateUpdating))
    {
        smTheUpdateables.remove(theUpdateable);
    }
    else
    {
        smTheUpdateablesToRemove.push_back(theUpdateable);
    }
}

// =============================================================================
// CSwingGame::UnregisterDrawable
// Remove a given drawable from the list
// -----------------------------------------------------------------------------
void CSwingGame::UnregisterDrawable(CDrawable *theDrawable)
{
    smTheDrawables.remove(theDrawable);
}

// =============================================================================
// CSwingGame::WasKeyPressedThisCycle
// Was a keypress event recieved for the given key this cycle
// -----------------------------------------------------------------------------
bool CSwingGame::WasKeyPressedThisCycle(CKeyboard::Key theKey)
{
    bool theResult = false;

    for (std::list<CEvent>::iterator it = smTheKeyPresses.begin();
         it != smTheKeyPresses.end();
         ++it)
    {
        if ((*it).type == CEvent::KeyPressed && (*it).key.code == theKey)
        {
            theResult = true;
        }
    }

    return theResult;
}

// =============================================================================
// CSwingGame::GoToLocation
// Go to a game location (level/menu)
// -----------------------------------------------------------------------------
void CSwingGame::GoToLocation(EGameLocation theLocation)
{
    // If we're already in a location leave it
    if (smCurrentLocation != NULL)
    {
        smCurrentLocation->Exit();
        SAFE_DELETE(smCurrentLocation);
    }

    switch (theLocation)
    {
        case kGameLocationFrontEnd:
            DEBUG_LOG("Front end requested");
            smCurrentLocation = new CTextFrontEnd();
            break;

        case kGameLocationLevel1:
            DEBUG_LOG("Level 1 requested");
            smCurrentLocation = new CLevel("testLevel.xml");
            break;

        default:
            DEBUG_LOG("Unimplemented game location - going to front end");
            smCurrentLocation = new CTextFrontEnd();
            break;
    }

    smCurrentLocation->Enter();
}

// =============================================================================
// CSwingGame::ProcessEvents
// Process all events recieved this cycle
// -----------------------------------------------------------------------------
void CSwingGame::ProcessEvents()
{
    // Eventually this will handle window focus events and keyboard/mouse events
    // Only log once
    static bool hasLogged = false;
    if (!hasLogged)
    {
        DEBUG_LOG("Process Events - Not fully implemented");
        hasLogged = true;
    }

    // Clear the last cycles keypress/mouse event list
    smTheKeyPresses.clear();

    CEvent theEvent;
    while (mWindow->pollEvent(theEvent))
    {
        switch (theEvent.type)
        {
            case CEvent::KeyPressed:
                // Keep a list of keypress events this cycle
                smTheKeyPresses.push_back(theEvent);
                break;

            case CEvent::Closed:
                // Exit on close event
                ExitGame();
                break;

            default:
                break; // Do nothing
        }
    }

    // React to exit requests
    if (smExitRequested)
    {
        mWindow->close();
    }
}

// =============================================================================
// CSwingGame::Update
// Update all registered CUpdatables
// -----------------------------------------------------------------------------
void CSwingGame::Update(CTime elapsedTime)
{
    // Set game state
    SetGameState(kGameStateUpdating);

    // Count updates
    static int numUpdates;
    static CTime accumulatingElapsedTime;

    numUpdates++;
    accumulatingElapsedTime += elapsedTime;
    if (accumulatingElapsedTime.asSeconds() >= 1.0f) // Every second
    {
        mUPS = numUpdates;
        numUpdates = 0;
        accumulatingElapsedTime = CTime();
    }

    // Iterate through the registered updateables, updating each in turn
    for (std::list<CUpdateable *>::iterator it = smTheUpdateables.begin();
         it != smTheUpdateables.end();
         ++it)
    {
        // Only update when in an appropriate state
        if ((*it)->ShouldUpdateForState(smGameState))
        {
            (*it)->Update(elapsedTime);
        }
    }

    // Remove any updateables whice were requested this cycle
    while (!smTheUpdateablesToRemove.empty())
    {
        smTheUpdateables.remove(smTheUpdateablesToRemove.front());
        smTheUpdateablesToRemove.pop_front();
    }
    // Add any updateables which were requested this cycle
    while (!smTheUpdateablesToAdd.empty())
    {
        smTheUpdateables.push_back(smTheUpdateablesToAdd.front());
        smTheUpdateablesToAdd.pop_front();
    }

    // Unset game state
    UnsetGameState(kGameStateUpdating);
}

// =============================================================================
// CSwingGame::Render
// Render all CDrawables registered
// -----------------------------------------------------------------------------
void CSwingGame::Render()
{
    // Count frames
    static int numFrames = 0;
    static CClock theClock;
    static CTime elapsedTime;

    numFrames++;
    elapsedTime += theClock.restart();
    if (elapsedTime.asSeconds() >= 1.0f) // Every second
    {
        mFPS = numFrames;
        numFrames = 0;
        elapsedTime = CTime();
    }

    // Clear the window
    mWindow->clear();

    // Iterate through all registered drawables, drawing them all
    for (std::list<CDrawable *>::iterator it = smTheDrawables.begin();
         it != smTheDrawables.end();
         ++it)
    {
        (*it)->Draw(mWindow);
    }

    // In debug draw frame/update rate over everything else
#if SG_DEBUG
    std::stringstream theStream;
    theStream << "FPS: " << mFPS << std::endl;
    theStream << "UPS: " << mUPS;
    mWindow->DrawTextAt(theStream.str(),
                        CGameOptions::smWindowWidth - 100,
                        5,
                        CColour::Red);
#endif

    // Display the new window contents
    mWindow->display();
}

<commit_msg>Only show framerate when wanted<commit_after>//
//  SwingGame.cpp
//  SwingGame
//
//  Created by Tim Brier on 26/09/2014.
//  Copyright (c) 2014 tbrier. All rights reserved.
//

// =============================================================================
// Include Files
// -----------------------------------------------------------------------------
#include "CSwingGame.hpp"
#include "CTextFrontEnd.hpp"
#include "CTextureBank.hpp"
#include "CLevel.hpp"
#include "CGameOptions.hpp"
#include "CDebugOptions.hpp"
#include <sstream>

// =============================================================================
// Static members
// -----------------------------------------------------------------------------
bool                        CSwingGame::smExitRequested = false;
EGameState                  CSwingGame::smGameState = kGameStateFrontEnd;
std::list<CUpdateable *>    CSwingGame::smTheUpdateables;
std::list<CUpdateable *>    CSwingGame::smTheUpdateablesToAdd;
std::list<CUpdateable *>    CSwingGame::smTheUpdateablesToRemove;
std::list<CDrawable *>      CSwingGame::smTheDrawables;
std::list<CEvent>           CSwingGame::smTheKeyPresses;
CGameLocation               *CSwingGame::smCurrentLocation = NULL;

// =============================================================================
// CSwingGame constructor/destructor
// -----------------------------------------------------------------------------
CSwingGame::CSwingGame() :  mWindowTitle("SwingGame v0.0"),
                            mWindow(NULL),
                            mFPS(0),
                            mUPS(0),
                            mExitCode(EXIT_SUCCESS)
{

}

CSwingGame::~CSwingGame()
{

}

// =============================================================================
// SwingGame::Init
// Initialise the game
// -----------------------------------------------------------------------------
void CSwingGame::Init()
{
    // Create the game window
    mWindow = new CWindow(CGameOptions::smWindowWidth,
                          CGameOptions::smWindowHeight,
                          mWindowTitle);

    // Enter the front end menu
    GoToLocation(kGameLocationFrontEnd);

    // Initialise other systems
    InitSFML(mWindow);
}

// =============================================================================
// SwingGame::Run
// Enter the main loop, returns program exit code
// -----------------------------------------------------------------------------
int CSwingGame::Run()
{
    CClock theClock;

    while (mWindow->isOpen())
    {
        CTime elapsedTime = theClock.restart();

        static CTime accumulatingTime;
        accumulatingTime += elapsedTime;

        ProcessEvents();

        Update(elapsedTime);

        // Only render if vsync is off or enough time has past
        if (!CGameOptions::smVsync
            || accumulatingTime.asSeconds() >= 1.0f / CGameOptions::smMaxFPS)
        {
            accumulatingTime = CTime();
            Render();
        }
    }

    return mExitCode;
}

// =============================================================================
// SwingGame::Cleanup
// Cleanup before quitting
// -----------------------------------------------------------------------------
void CSwingGame::Cleanup()
{
    SAFE_DELETE(mWindow);
    SAFE_DELETE(smCurrentLocation);
    CTextUtilities::Cleanup();
    CTextureBank::Cleanup();
}

// =============================================================================
// CSwingGame::ExitGame
// Exit the game
// -----------------------------------------------------------------------------
void CSwingGame::ExitGame()
{
    DEBUG_LOG("Exit requested");
    smExitRequested = true;
}

// =============================================================================
// CSwingGame::SetGameState
// Set given GameState flags
// -----------------------------------------------------------------------------
void CSwingGame::SetGameState(EGameState theState)
{
    smGameState = static_cast<EGameState>(smGameState | theState);
}

// =============================================================================
// CSwingGame::UnsetGameState
// Unset the given GameState flags
// -----------------------------------------------------------------------------
void CSwingGame::UnsetGameState(EGameState theState)
{
    smGameState = static_cast<EGameState>(smGameState & ~theState);
}

// =============================================================================
// CSwingGame::HasAllGameStates
// Returns true only if the current state has all the given flags
// -----------------------------------------------------------------------------
bool CSwingGame::HasAllGameStates(EGameState theState)
{
    EGameState theResult = static_cast<EGameState>(smGameState & theState);
    return theResult == theState;
}

// =============================================================================
// CSwingGame::RegisterUpdateable
// Add an updateable to the list
// -----------------------------------------------------------------------------
void CSwingGame::RegisterUpdateable(CUpdateable *theUpdateable)
{
    // If we're not updating then we can add it now, otherwise add it to a list
    // to be added after the current update cycle
    if (!HasAllGameStates(kGameStateUpdating))
    {
        smTheUpdateables.push_back(theUpdateable);
    }
    else
    {
        smTheUpdateablesToAdd.push_back(theUpdateable);
    }
}

// =============================================================================
// CSwingGame::RegisterDrawable
// Add a drawable to the list
// -----------------------------------------------------------------------------
void CSwingGame::RegisterDrawable(CDrawable *theDrawable)
{
    smTheDrawables.push_back(theDrawable);
}

// =============================================================================
// CSwingGame::UnregisterUpdateable
// Remove a given updateable from the list
// -----------------------------------------------------------------------------
void CSwingGame::UnregisterUpdateable(CUpdateable *theUpdateable)
{
    // If we're not updating go ahead and remove it, otherwise add it to a list
    // to be removed after the current update cycle
    if (!HasAllGameStates(kGameStateUpdating))
    {
        smTheUpdateables.remove(theUpdateable);
    }
    else
    {
        smTheUpdateablesToRemove.push_back(theUpdateable);
    }
}

// =============================================================================
// CSwingGame::UnregisterDrawable
// Remove a given drawable from the list
// -----------------------------------------------------------------------------
void CSwingGame::UnregisterDrawable(CDrawable *theDrawable)
{
    smTheDrawables.remove(theDrawable);
}

// =============================================================================
// CSwingGame::WasKeyPressedThisCycle
// Was a keypress event recieved for the given key this cycle
// -----------------------------------------------------------------------------
bool CSwingGame::WasKeyPressedThisCycle(CKeyboard::Key theKey)
{
    bool theResult = false;

    for (std::list<CEvent>::iterator it = smTheKeyPresses.begin();
         it != smTheKeyPresses.end();
         ++it)
    {
        if ((*it).type == CEvent::KeyPressed && (*it).key.code == theKey)
        {
            theResult = true;
        }
    }

    return theResult;
}

// =============================================================================
// CSwingGame::GoToLocation
// Go to a game location (level/menu)
// -----------------------------------------------------------------------------
void CSwingGame::GoToLocation(EGameLocation theLocation)
{
    // If we're already in a location leave it
    if (smCurrentLocation != NULL)
    {
        smCurrentLocation->Exit();
        SAFE_DELETE(smCurrentLocation);
    }

    switch (theLocation)
    {
        case kGameLocationFrontEnd:
            DEBUG_LOG("Front end requested");
            smCurrentLocation = new CTextFrontEnd();
            break;

        case kGameLocationLevel1:
            DEBUG_LOG("Level 1 requested");
            smCurrentLocation = new CLevel("testLevel.xml");
            break;

        default:
            DEBUG_LOG("Unimplemented game location - going to front end");
            smCurrentLocation = new CTextFrontEnd();
            break;
    }

    smCurrentLocation->Enter();
}

// =============================================================================
// CSwingGame::ProcessEvents
// Process all events recieved this cycle
// -----------------------------------------------------------------------------
void CSwingGame::ProcessEvents()
{
    // Eventually this will handle window focus events and keyboard/mouse events
    // Only log once
    static bool hasLogged = false;
    if (!hasLogged)
    {
        DEBUG_LOG("Process Events - Not fully implemented");
        hasLogged = true;
    }

    // Clear the last cycles keypress/mouse event list
    smTheKeyPresses.clear();

    CEvent theEvent;
    while (mWindow->pollEvent(theEvent))
    {
        switch (theEvent.type)
        {
            case CEvent::KeyPressed:
                // Keep a list of keypress events this cycle
                smTheKeyPresses.push_back(theEvent);
                break;

            case CEvent::Closed:
                // Exit on close event
                ExitGame();
                break;

            default:
                break; // Do nothing
        }
    }

    // React to exit requests
    if (smExitRequested)
    {
        mWindow->close();
    }
}

// =============================================================================
// CSwingGame::Update
// Update all registered CUpdatables
// -----------------------------------------------------------------------------
void CSwingGame::Update(CTime elapsedTime)
{
    // Set game state
    SetGameState(kGameStateUpdating);

    // Count updates
    static int numUpdates;
    static CTime accumulatingElapsedTime;

    numUpdates++;
    accumulatingElapsedTime += elapsedTime;
    if (accumulatingElapsedTime.asSeconds() >= 1.0f) // Every second
    {
        mUPS = numUpdates;
        numUpdates = 0;
        accumulatingElapsedTime = CTime();
    }

    // Iterate through the registered updateables, updating each in turn
    for (std::list<CUpdateable *>::iterator it = smTheUpdateables.begin();
         it != smTheUpdateables.end();
         ++it)
    {
        // Only update when in an appropriate state
        if ((*it)->ShouldUpdateForState(smGameState))
        {
            (*it)->Update(elapsedTime);
        }
    }

    // Remove any updateables whice were requested this cycle
    while (!smTheUpdateablesToRemove.empty())
    {
        smTheUpdateables.remove(smTheUpdateablesToRemove.front());
        smTheUpdateablesToRemove.pop_front();
    }
    // Add any updateables which were requested this cycle
    while (!smTheUpdateablesToAdd.empty())
    {
        smTheUpdateables.push_back(smTheUpdateablesToAdd.front());
        smTheUpdateablesToAdd.pop_front();
    }

    // Unset game state
    UnsetGameState(kGameStateUpdating);
}

// =============================================================================
// CSwingGame::Render
// Render all CDrawables registered
// -----------------------------------------------------------------------------
void CSwingGame::Render()
{
    // Count frames
    static int numFrames = 0;
    static CClock theClock;
    static CTime elapsedTime;

    numFrames++;
    elapsedTime += theClock.restart();
    if (elapsedTime.asSeconds() >= 1.0f) // Every second
    {
        mFPS = numFrames;
        numFrames = 0;
        elapsedTime = CTime();
    }

    // Clear the window
    mWindow->clear();

    // Iterate through all registered drawables, drawing them all
    for (std::list<CDrawable *>::iterator it = smTheDrawables.begin();
         it != smTheDrawables.end();
         ++it)
    {
        (*it)->Draw(mWindow);
    }

    // In debug draw frame/update rate over everything else
#if SG_DEBUG
    if (CDebugOptions::smShowFramerate)
    {
        std::stringstream theStream;
        theStream << "FPS: " << mFPS << std::endl;
        theStream << "UPS: " << mUPS;
        mWindow->DrawTextAt(theStream.str(),
                            CGameOptions::smWindowWidth - 100,
                            5,
                            CColour::Red);
    }
#endif

    // Display the new window contents
    mWindow->display();
}

<|endoftext|>