<commit_before>// This file is part of xsonrpc, an XML/JSON RPC library.
// Copyright (C) 2015 Erik Johansson <erik@ejohansson.se>
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
// for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

#include "jsonreader.h"

#include "fault.h"
#include "json.h"
#include "request.h"
#include "response.h"
#include "util.h"
#include "value.h"

namespace xsonrpc {

using namespace json;

JsonReader::JsonReader(std::string data)
{
  myDocument.Parse(data.c_str());
  if (myDocument.HasParseError()) {
    throw ParseErrorFault(
      "Parse error: " + std::to_string(myDocument.GetParseError()));
  }
}

Request JsonReader::GetRequest()
{
  if (!myDocument.IsObject()) {
    throw InvalidRequestFault();
  }

  ValidateJsonrpcVersion();

  auto method = myDocument.FindMember(METHOD_NAME);
  if (method == myDocument.MemberEnd() || !method->value.IsString()) {
    throw InvalidRequestFault();
  }

  // TODO: get id

  auto params = myDocument.FindMember(PARAMS_NAME);
  if (params != myDocument.MemberEnd() && !params->value.IsArray()) {
    throw InvalidRequestFault();
  }

  Request::Parameters parameters;
  for (auto param = params->value.Begin(); param != params->value.End();
       ++param) {
    parameters.emplace_back(GetValue(*param));
  }

  return Request(method->value.GetString(), std::move(parameters));
}

Response JsonReader::GetResponse()
{
  if (!myDocument.IsObject()) {
    throw InvalidRequestFault();
  }

  ValidateJsonrpcVersion();

  // TODO: get id

  auto result = myDocument.FindMember(RESULT_NAME);
  auto error = myDocument.FindMember(ERROR_NAME);

  if (result != myDocument.MemberEnd()) {
    if (error != myDocument.MemberEnd()) {
      throw InvalidRequestFault();
    }
    return Response(GetValue(result->value));
  }
  else if (error != myDocument.MemberEnd()) {
    if (result != myDocument.MemberEnd()) {
      throw InvalidRequestFault();
    }
    if (!error->value.IsObject()) {
      throw InvalidRequestFault();
    }
    auto code = error->value.FindMember(ERROR_CODE_NAME);
    if (code == error->value.MemberEnd() || !code->value.IsInt()) {
      throw InvalidRequestFault();
    }
    auto message = error->value.FindMember(ERROR_MESSAGE_NAME);
    if (message == error->value.MemberEnd() || !message->value.IsString()) {
      throw InvalidRequestFault();
    }

    return Response(code->value.GetInt(), message->value.GetString());
  }
  else {
    throw InvalidRequestFault();
  }
}

Value JsonReader::GetValue()
{
  return GetValue(myDocument);
}

void JsonReader::ValidateJsonrpcVersion()
{
  auto jsonrpc = myDocument.FindMember(JSONRPC_NAME);
  if (jsonrpc == myDocument.MemberEnd()
      || !jsonrpc->value.IsString()
      || strcmp(jsonrpc->value.GetString(), JSONRPC_VERSION_2_0) != 0) {
    throw InvalidRequestFault();
  }
}

Value JsonReader::GetValue(const rapidjson::Value& value)
{
  switch (value.GetType()) {
    case rapidjson::kNullType:
      return Value();
    case rapidjson::kFalseType:
    case rapidjson::kTrueType:
      return Value(value.GetBool());
    case rapidjson::kObjectType: {
      Value::Struct data;
      for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) {
        std::string name(it->name.GetString(), it->name.GetStringLength());
        data.emplace(name, GetValue(it->value));
      }
      return Value(std::move(data));
    }
    case rapidjson::kArrayType: {
      Value::Array array;
      array.reserve(value.Size());
      for (auto it = value.Begin(); it != value.End(); ++it) {
        array.emplace_back(GetValue(*it));
      }
      return Value(std::move(array));
    }
    case rapidjson::kStringType: {
      tm dt;
      if (util::ParseIso8601DateTime(value.GetString(), dt)) {
        return Value(dt);
      }

      std::string str(value.GetString(), value.GetStringLength());
      const bool binary = str.find('\0') != std::string::npos;
      return Value(std::move(str), binary);
    }
    case rapidjson::kNumberType:
      if (value.IsDouble()) {
        return Value(value.GetDouble());
      }
      else if (value.IsInt()) {
        return Value(value.GetInt());
      }
      else if (value.IsUint()) {
        return Value(static_cast<int64_t>(value.GetUint()));
      }
      else if (value.IsInt64()) {
        return Value(value.GetInt64());
      }
      else {
        assert(value.IsUint64());
        return Value(static_cast<double>(value.GetUint64()));
      }
      break;
  }

  throw InternalErrorFault();
}

} // namespace xsonrpc
<commit_msg>json: don't try to member if it doesn't exist<commit_after>// This file is part of xsonrpc, an XML/JSON RPC library.
// Copyright (C) 2015 Erik Johansson <erik@ejohansson.se>
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 2.1 of the License, or (at your
// option) any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
// for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

#include "jsonreader.h"

#include "fault.h"
#include "json.h"
#include "request.h"
#include "response.h"
#include "util.h"
#include "value.h"

namespace xsonrpc {

using namespace json;

JsonReader::JsonReader(std::string data)
{
  myDocument.Parse(data.c_str());
  if (myDocument.HasParseError()) {
    throw ParseErrorFault(
      "Parse error: " + std::to_string(myDocument.GetParseError()));
  }
}

Request JsonReader::GetRequest()
{
  if (!myDocument.IsObject()) {
    throw InvalidRequestFault();
  }

  ValidateJsonrpcVersion();

  auto method = myDocument.FindMember(METHOD_NAME);
  if (method == myDocument.MemberEnd() || !method->value.IsString()) {
    throw InvalidRequestFault();
  }

  // TODO: get id

  Request::Parameters parameters;
  auto params = myDocument.FindMember(PARAMS_NAME);
  if (params != myDocument.MemberEnd()) {
    if (!params->value.IsArray()) {
      throw InvalidRequestFault();
    }

    for (auto param = params->value.Begin(); param != params->value.End();
         ++param) {
      parameters.emplace_back(GetValue(*param));
    }
  }

  return Request(method->value.GetString(), std::move(parameters));
}

Response JsonReader::GetResponse()
{
  if (!myDocument.IsObject()) {
    throw InvalidRequestFault();
  }

  ValidateJsonrpcVersion();

  // TODO: get id

  auto result = myDocument.FindMember(RESULT_NAME);
  auto error = myDocument.FindMember(ERROR_NAME);

  if (result != myDocument.MemberEnd()) {
    if (error != myDocument.MemberEnd()) {
      throw InvalidRequestFault();
    }
    return Response(GetValue(result->value));
  }
  else if (error != myDocument.MemberEnd()) {
    if (result != myDocument.MemberEnd()) {
      throw InvalidRequestFault();
    }
    if (!error->value.IsObject()) {
      throw InvalidRequestFault();
    }
    auto code = error->value.FindMember(ERROR_CODE_NAME);
    if (code == error->value.MemberEnd() || !code->value.IsInt()) {
      throw InvalidRequestFault();
    }
    auto message = error->value.FindMember(ERROR_MESSAGE_NAME);
    if (message == error->value.MemberEnd() || !message->value.IsString()) {
      throw InvalidRequestFault();
    }

    return Response(code->value.GetInt(), message->value.GetString());
  }
  else {
    throw InvalidRequestFault();
  }
}

Value JsonReader::GetValue()
{
  return GetValue(myDocument);
}

void JsonReader::ValidateJsonrpcVersion()
{
  auto jsonrpc = myDocument.FindMember(JSONRPC_NAME);
  if (jsonrpc == myDocument.MemberEnd()
      || !jsonrpc->value.IsString()
      || strcmp(jsonrpc->value.GetString(), JSONRPC_VERSION_2_0) != 0) {
    throw InvalidRequestFault();
  }
}

Value JsonReader::GetValue(const rapidjson::Value& value)
{
  switch (value.GetType()) {
    case rapidjson::kNullType:
      return Value();
    case rapidjson::kFalseType:
    case rapidjson::kTrueType:
      return Value(value.GetBool());
    case rapidjson::kObjectType: {
      Value::Struct data;
      for (auto it = value.MemberBegin(); it != value.MemberEnd(); ++it) {
        std::string name(it->name.GetString(), it->name.GetStringLength());
        data.emplace(name, GetValue(it->value));
      }
      return Value(std::move(data));
    }
    case rapidjson::kArrayType: {
      Value::Array array;
      array.reserve(value.Size());
      for (auto it = value.Begin(); it != value.End(); ++it) {
        array.emplace_back(GetValue(*it));
      }
      return Value(std::move(array));
    }
    case rapidjson::kStringType: {
      tm dt;
      if (util::ParseIso8601DateTime(value.GetString(), dt)) {
        return Value(dt);
      }

      std::string str(value.GetString(), value.GetStringLength());
      const bool binary = str.find('\0') != std::string::npos;
      return Value(std::move(str), binary);
    }
    case rapidjson::kNumberType:
      if (value.IsDouble()) {
        return Value(value.GetDouble());
      }
      else if (value.IsInt()) {
        return Value(value.GetInt());
      }
      else if (value.IsUint()) {
        return Value(static_cast<int64_t>(value.GetUint()));
      }
      else if (value.IsInt64()) {
        return Value(value.GetInt64());
      }
      else {
        assert(value.IsUint64());
        return Value(static_cast<double>(value.GetUint64()));
      }
      break;
  }

  throw InternalErrorFault();
}

} // namespace xsonrpc
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __PERF_HPP__
#define __PERF_HPP__

#include <unistd.h>

#include <set>
#include <string>

#include <process/future.hpp>

#include <stout/duration.hpp>
#include <stout/hashmap.hpp>

// For PerfStatistics protobuf.
#include "mesos/mesos.hpp"

namespace perf {

// Sample the perf events for process pid for duration.
process::Future<mesos::PerfStatistics> sample(
    const std::set<std::string>& events,
    pid_t pid,
    const Duration& duration);

// Sample the perf events for processes in pids for duration.
process::Future<mesos::PerfStatistics> sample(
    const std::set<std::string>& events,
    const std::set<pid_t>& pids,
    const Duration& duration);

// Sample the perf events for process(es) in the perf_event cgroups
// for duration. The returned hashmap is keyed by cgroup.
// NOTE: cgroups should be relative to the perf_event subsystem mount,
// e.g., mesos/test for /sys/fs/cgroup/perf_event/mesos/test.
process::Future<hashmap<std::string, mesos::PerfStatistics>> sample(
    const std::set<std::string>& events,
    const std::set<std::string>& cgroup,
    const Duration& duration);

// Sample the perf events for process(es) in the perf_event cgroup.
process::Future<mesos::PerfStatistics> sample(
    const std::set<std::string>& events,
    const std::string& cgroup,
    const Duration& duration);

// Validate a set of events are accepted by `perf stat`.
bool valid(const std::set<std::string>& events);

// Returns whether perf is supported on this host. Returns false if
// the kernel is too old (requires >= 2.6.39).
bool supported();

// Note: Exposed for testing purposes.
Try<hashmap<std::string, mesos::PerfStatistics>> parse(
    const std::string& output);

} // namespace perf {

#endif // __PERF_HPP__
<commit_msg>Fixed a non-plural variable name in perf.hpp.<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef __PERF_HPP__
#define __PERF_HPP__

#include <unistd.h>

#include <set>
#include <string>

#include <process/future.hpp>

#include <stout/duration.hpp>
#include <stout/hashmap.hpp>

// For PerfStatistics protobuf.
#include "mesos/mesos.hpp"

namespace perf {

// Sample the perf events for process pid for duration.
process::Future<mesos::PerfStatistics> sample(
    const std::set<std::string>& events,
    pid_t pid,
    const Duration& duration);

// Sample the perf events for processes in pids for duration.
process::Future<mesos::PerfStatistics> sample(
    const std::set<std::string>& events,
    const std::set<pid_t>& pids,
    const Duration& duration);

// Sample the perf events for process(es) in the perf_event cgroups
// for duration. The returned hashmap is keyed by cgroup.
// NOTE: cgroups should be relative to the perf_event subsystem mount,
// e.g., mesos/test for /sys/fs/cgroup/perf_event/mesos/test.
process::Future<hashmap<std::string, mesos::PerfStatistics>> sample(
    const std::set<std::string>& events,
    const std::set<std::string>& cgroups,
    const Duration& duration);

// Sample the perf events for process(es) in the perf_event cgroup.
process::Future<mesos::PerfStatistics> sample(
    const std::set<std::string>& events,
    const std::string& cgroup,
    const Duration& duration);

// Validate a set of events are accepted by `perf stat`.
bool valid(const std::set<std::string>& events);

// Returns whether perf is supported on this host. Returns false if
// the kernel is too old (requires >= 2.6.39).
bool supported();

// Note: Exposed for testing purposes.
Try<hashmap<std::string, mesos::PerfStatistics>> parse(
    const std::string& output);

} // namespace perf {

#endif // __PERF_HPP__
<|endoftext|>


<commit_before>#pragma once

#include <cmath>
#include <limits>
#include <cassert>
#include <algorithm>

namespace math
{
        ///
        /// \brief computes statistics: average, standard deviation etc.
        ///
        template
        <
                typename tscalar = double,
                typename tsize = std::size_t
        >
        class stats_t
	{
        public:

                ///
                /// \brief constructor
                ///
                stats_t()
                {
                        clear();
                }

                ///
                /// \brief update statistics with a new value
                ///
                void operator()(tscalar value)
                {
                        m_count ++;
                        m_sum += value;
                        m_sumsq += value * value;
                        m_min = std::min(m_min, value);
                        m_max = std::max(m_max, value);
                }

                ///
                /// \brief merge statistics
                ///
                void operator()(const stats_t& other)
                {
                        m_count += other.m_count;
                        m_sum += other.m_sum;
                        m_sumsq += other.m_sumsq;
                        m_min = std::min(m_min, other.m_min);
                        m_max = std::max(m_max, other.m_max);
                }

                ///
                /// \brief update statistics with the given [begin, end) range
                ///
                template
                <
                        class titerator
                >
                void operator()(titerator begin, titerator end)
		{
			for ( ; begin != end; ++ begin)
                        {
                                operator()(*begin);
                        }
		}

                ///
                /// \brief reset statistics
                ///
                void clear()
                {
                        m_count = 0;
                        m_sum = 0;
                        m_sumsq = 0;
                        m_min = +std::numeric_limits<tscalar>::max();
                        m_max = -std::numeric_limits<tscalar>::max();
                }

                // access functions
                operator bool() const { return count() > 1; }

                tsize count() const { return m_count; }
                tscalar min() const { return m_min; }
                tscalar max() const { return m_max; }
                tscalar sum() const { return m_sum; }

                double avg() const
                {
                        assert(count() > 0);
                        return  static_cast<double>(sum()) /
                                static_cast<double>(count());
                }

                double var2() const
                {
                        assert(count() > 0);
                        return  static_cast<double>(m_sumsq) -
                                static_cast<double>(m_sum * m_sum) / static_cast<double>(count());
                }

                double var() const
                {
                        assert(count() > 1);
                        return var2() / static_cast<double>(count() - 1);
                }

                double stdev() const
                {
                        return std::sqrt(var());
                }

        private:

                // attributes
                tsize           m_count;
                tscalar         m_sum, m_sumsq;
                tscalar         m_min, m_max;
	};
}
<commit_msg>default variance to zero if a single sample<commit_after>#pragma once

#include <cmath>
#include <limits>
#include <cassert>
#include <algorithm>

namespace math
{
        ///
        /// \brief computes statistics: average, standard deviation etc.
        ///
        template
        <
                typename tscalar = double,
                typename tsize = std::size_t
        >
        class stats_t
        {
        public:

                ///
                /// \brief constructor
                ///
                stats_t()
                {
                        clear();
                }

                ///
                /// \brief update statistics with a new value
                ///
                void operator()(tscalar value)
                {
                        m_count ++;
                        m_sum += value;
                        m_sumsq += value * value;
                        m_min = std::min(m_min, value);
                        m_max = std::max(m_max, value);
                }

                ///
                /// \brief merge statistics
                ///
                void operator()(const stats_t& other)
                {
                        m_count += other.m_count;
                        m_sum += other.m_sum;
                        m_sumsq += other.m_sumsq;
                        m_min = std::min(m_min, other.m_min);
                        m_max = std::max(m_max, other.m_max);
                }

                ///
                /// \brief update statistics with the given [begin, end) range
                ///
                template
                <
                        class titerator
                >
                void operator()(titerator begin, titerator end)
                {
                        for ( ; begin != end; ++ begin)
                        {
                                operator()(*begin);
                        }
                }

                ///
                /// \brief reset statistics
                ///
                void clear()
                {
                        m_count = 0;
                        m_sum = 0;
                        m_sumsq = 0;
                        m_min = +std::numeric_limits<tscalar>::max();
                        m_max = -std::numeric_limits<tscalar>::max();
                }

                // access functions
                operator bool() const { return count() > 1; }

                tsize count() const { return m_count; }
                tscalar min() const { return m_min; }
                tscalar max() const { return m_max; }
                tscalar sum() const { return m_sum; }

                double avg() const
                {
                        assert(count() > 0);
                        return  static_cast<double>(sum()) /
                                static_cast<double>(count());
                }

                double var2() const
                {
                        assert(count() > 0);
                        return  static_cast<double>(m_sumsq) -
                                static_cast<double>(m_sum * m_sum) / static_cast<double>(count());
                }

                double var() const
                {
                        assert(count() > 0);
                        return (count() == 1) ? 0.0 : (var2() / static_cast<double>(count() - 1));
                }

                double stdev() const
                {
                        return std::sqrt(var());
                }

        private:

                // attributes
                tsize           m_count;
                tscalar         m_sum, m_sumsq;
                tscalar         m_min, m_max;
        };
}
<|endoftext|>


<commit_before>#define EIGEN_USE_MKL_ALL

#include <iostream> // for standard output
#include <vector> // vector objects
#include <eigen3/Eigen/Dense> // linear algebra library
#include <eigen3/unsupported/Eigen/KroneckerProduct> // provides tensor product
#include <eigen3/unsupported/Eigen/MatrixFunctions> // provides matrix functions

#include "constants.h"
#include "qp-math.h"

using namespace std;
using namespace Eigen;

// ---------------------------------------------------------------------------------------
// Matrix functions
// ---------------------------------------------------------------------------------------

// tensor product of many matrices
MatrixXcd tp(const initializer_list<MatrixXcd>& list) {
  MatrixXcd out = I1;
  for (MatrixXcd elem: list) {
    out = tp(out,elem);
  }
  return out;
}

// remove numerical artifacts from a matrix
MatrixXcd remove_artifacts(const MatrixXcd& A, const double threshold) {
  MatrixXcd B = MatrixXcd::Zero(A.rows(),A.cols());
  for (uint m = 0; m < A.rows(); m++) {
    for (uint n = 0; n < A.cols(); n++) {
      B(m,n) += round(A(m,n).real()/threshold)*threshold;
      B(m,n) += round(A(m,n).imag()/threshold)*threshold*j;
    }
  }
  return B;
}

// get global phase of matrix
complex<double> get_phase(const MatrixXcd& A, const double threshold) {
  for (uint m = 0; m < A.rows(); m++) {
    for (uint n = 0; n < A.cols(); n++) {
      if (abs(A(m,n)) > threshold) {
        const complex<double> phase = A(m,n)/abs(A(m,n));
        return phase;
      }
    }
  }
  return 1;
}

// ---------------------------------------------------------------------------------------
// Operator manipulation
// ---------------------------------------------------------------------------------------

// generate matrix B to act A on qbits qs_act out of qbits_new
MatrixXcd act(const MatrixXcd& A, const vector<uint>& qs_act, const uint qbits_new) {
  assert(A.rows() == A.cols()); // A should be square

  if (qs_act.size() == qbits_new) {
    bool do_nothing = true;
    for (uint i = 0; i < qbits_new; i++) {
      if (i != qs_act.at(i)) {
        do_nothing = false;
        break;
      }
    }
    if (do_nothing) return A;
  }

  // number of qbits A acted on
  const uint qbits_old = qs_act.size();
  assert(qbits_old == log2(A.rows()));

  // vector of qubits we are ignoring
  vector<uint> qs_ignore;
  for (uint i = 0; i < qbits_new; i++) {
    if (!in_vector(i,qs_act)) {
      qs_ignore.push_back(i);
    }
  }

  // initialize B (output) to the zero matrix
  MatrixXcd B = MatrixXcd::Zero(pow(2,qbits_new),pow(2,qbits_new));

  // loop over all entries A(m,n)
  for (uint m = 0; m < A.rows(); m++) {
    for (uint n = 0; n < A.cols(); n++) {

      // get contribution of substates |m-><n-| to indices of B
      uint b_m = 0, b_n = 0;
      for (uint q = 0; q < qbits_old; q++) {
        if (qbit_state(q,qbits_old,m)) b_m += bit_int(qs_act.at(q),qbits_new);
        if (qbit_state(q,qbits_old,n)) b_n += bit_int(qs_act.at(q),qbits_new);
      }

      // loop over all elements of the form |ms><ns| in B
      for (uint s = 0; s < pow(2,qs_ignore.size()); s++) {
        uint b_out = b_m, b_in = b_n;
        for (uint q = 0; q < qs_ignore.size(); q++) {
          if (qbit_state(q,qs_ignore.size(),s)) {
            b_out += bit_int(qs_ignore.at(q),qbits_new);
            b_in += bit_int(qs_ignore.at(q),qbits_new);
          }
        }
        B(b_out,b_in) = A(m,n);
      }
    }
  }
  return B;
}

// perform a partial trace over qbits qs_trace
MatrixXcd ptrace(const MatrixXcd& A, const vector<uint>& qs_trace) {
  assert(A.rows() == A.cols()); // A should be square

  // number of qbits A acted on
  const uint qbits_old = log2(A.rows());
  const uint qbits_new = qbits_old - qs_trace.size();

  // vector of qubits we are keeping
  vector<uint> qs_keep;
  for (uint i = 0; i < qbits_old; i++) {
    if (!in_vector(i,qs_trace)) qs_keep.push_back(i);
  }
  assert(qbits_new == qs_keep.size());

  // initialize B (output) to the zero matrix
  MatrixXcd B = MatrixXcd::Zero(pow(2,qbits_new),pow(2,qbits_new));

  // loop over all entries B(m,n)
  for (uint m = 0; m < B.rows(); m++) {
    for (uint n = 0; n < B.cols(); n++) {

      // get contribution of substates |m-><n-| to indices of A
      uint a_m = 0, a_n = 0;
      for (uint q = 0; q < qbits_new; q++) {
        if (qbit_state(q,qbits_new,m)) a_m += bit_int(qs_keep.at(q),qbits_old);
        if (qbit_state(q,qbits_new,n)) a_n += bit_int(qs_keep.at(q),qbits_old);
      }

      // loop over all elements of the form |ms><ns| in A
      for (uint s = 0; s < pow(2,qs_trace.size()); s++) {
        uint a_out = a_m, a_in = a_n;
        for (uint q = 0; q < qs_trace.size(); q++) {
          if (qbit_state(q,qs_trace.size(),s)) {
            a_out += bit_int(qs_trace.at(q),qbits_old);
            a_in += bit_int(qs_trace.at(q),qbits_old);
          }
        }
        B(m,n) += A(a_out,a_in);
      }
    }
  }
  return B;
}

// ---------------------------------------------------------------------------------------
// Gate decomposition and fidelity
// ---------------------------------------------------------------------------------------

// returns basis element p for an operator acting on a system with N spins
MatrixXcd U_basis_element(const uint p, const uint N) {
  const vector<MatrixXcd> spins = {I2, sx, sy, sz};
  MatrixXcd b_p = I1;
  for (uint n = 0; n < N; n++) {
    b_p = tp(b_p,spins.at(int_bit(p,2*n)+2*int_bit(p,2*n+1)));
  }
  return b_p;
}

// returns element p of a basis for operators acting on a system with N qubits
string U_basis_element_text(const uint p, const uint N) {
  const vector<char> spins = {'I','X','Y','Z'};
  stringstream stream;
  for (uint n = 0; n < N; n++) {
    stream << spins.at(int_bit(p,2*n)+2*int_bit(p,2*n+1));
  }
  return stream.str();
}

// returns matrix whose columns are basis Hamiltonians for a system of N spins
MatrixXcd U_basis_matrix(const uint N) {
  MatrixXcd out = MatrixXcd::Zero(pow(4,N),pow(4,N));
  for (uint p = 0; p < pow(4,N); p++) {
    out.col(p) = flatten(U_basis_element(p,N));
  }
  return out;
}

// decompose an operator into its basis elements
VectorXcd U_decompose(const MatrixXcd& U, const bool fast) {
  const uint N = log2(U.rows());
  if (fast) return U_basis_matrix(N).householderQr().solve(flatten(U));
  else return U_basis_matrix(N).fullPivLu().solve(flatten(U));
}

// compute mean fidelity of gate U with respect to G, i.e. how well U approximates G
double gate_fidelity(const MatrixXcd&  U, const MatrixXcd& G) {
  assert(U.size() == G.size());
  const uint D = U.rows();
  const MatrixXcd M = G.adjoint() * U;
  return real( trace(M.adjoint()*M) + trace(M)*conj(trace(M)) ) / (D*(D+1));
}

// compute mean fidelity of propagator acting on system_qubits
double gate_fidelity(const MatrixXcd& U, const MatrixXcd& G, const vector<uint>& nuclei) {
  assert(U.size() == G.size());

  const uint spins = log2(G.rows());
  vector<uint> system_qubits = {0};
  for (uint n: nuclei) system_qubits.push_back(n+1);

  const MatrixXcd U_err = G.adjoint() * U;
  const VectorXcd H_err_vec = U_decompose(j*log(U_err));

  MatrixXcd H_env = MatrixXcd::Zero(pow(2,spins),pow(2,spins));
  for (uint h = 0; h < H_err_vec.size(); h++) {
    bool add_this_element = true;
    for (uint q: system_qubits) {
      if (int_bit(h,2*q) + int_bit(h,2*q+1)) {
        add_this_element = false;
        break;
      }
    }
    if (add_this_element) H_env += H_err_vec(h)*U_basis_element(h,spins);
  }
  return gate_fidelity(U*exp(j*H_env),G);
}

// ---------------------------------------------------------------------------------------
// Matrix vectors
// ---------------------------------------------------------------------------------------

mvec operator*(const MatrixXcd& G, const mvec& v) {
  vector<MatrixXcd> out;
  for (uint i = 0; i < v.size(); i++) {
    out.push_back(G*v.at(i));
  }
  return mvec(out);
}

// ---------------------------------------------------------------------------------------
// Printing methods
// ---------------------------------------------------------------------------------------

// print operator in human-readable form
void U_print(const MatrixXcd& U, const double threshold) {
  const int N = log2(U.rows());
  const VectorXcd hs = remove_artifacts(U_decompose(U), threshold);
  for (int p = 0; p < pow(4,N); p++) {
    if (abs(hs(p)) != 0) {
      cout << U_basis_element_text(p,N) << ": " << hs(p) << endl;
    }
  }
  cout << endl;
}

// print state vector in human readable form
void state_print(const MatrixXcd& psi) {
  const uint N = psi.size();
  const uint qbits = log2(N);
  for (uint n = 0; n < N; n++) {
    if (abs(psi(n)) != 0) {
      cout << "|";
      for (uint q = 0; q < qbits; q++) {
        cout << (qbit_state(q,qbits,n)?"d":"u");
      }
      cout << "> " << psi(n) << endl;
    }
  }
  cout << endl;
}

// print matrix in human readable form
void matrix_print(const MatrixXcd& M) {
  const uint qbits = log2(M.rows());
  for (uint m = 0; m < M.rows(); m++) {
    for (uint n = 0; n < M.cols(); n++) {
      if (abs(M(m,n)) != 0) {
        cout << "|";
        for (uint q = 0; q < qbits; q++) {
          cout << (qbit_state(q,qbits,m)?"d":"u");
        }
        cout << "><";
        for (uint q = 0; q < qbits; q++) {
          cout << (qbit_state(q,qbits,n)?"d":"u");
        }
        cout << "| " << M(m,n) << endl;
      }
    }
  }
  cout << endl;
}
<commit_msg>change algorithm for matrix decomposition<commit_after>#define EIGEN_USE_MKL_ALL

#include <iostream> // for standard output
#include <vector> // vector objects
#include <eigen3/Eigen/Dense> // linear algebra library
#include <eigen3/unsupported/Eigen/KroneckerProduct> // provides tensor product
#include <eigen3/unsupported/Eigen/MatrixFunctions> // provides matrix functions

#include "constants.h"
#include "qp-math.h"

using namespace std;
using namespace Eigen;

// ---------------------------------------------------------------------------------------
// Matrix functions
// ---------------------------------------------------------------------------------------

// tensor product of many matrices
MatrixXcd tp(const initializer_list<MatrixXcd>& list) {
  MatrixXcd out = I1;
  for (MatrixXcd elem: list) {
    out = tp(out,elem);
  }
  return out;
}

// remove numerical artifacts from a matrix
MatrixXcd remove_artifacts(const MatrixXcd& A, const double threshold) {
  MatrixXcd B = MatrixXcd::Zero(A.rows(),A.cols());
  for (uint m = 0; m < A.rows(); m++) {
    for (uint n = 0; n < A.cols(); n++) {
      B(m,n) += round(A(m,n).real()/threshold)*threshold;
      B(m,n) += round(A(m,n).imag()/threshold)*threshold*j;
    }
  }
  return B;
}

// get global phase of matrix
complex<double> get_phase(const MatrixXcd& A, const double threshold) {
  for (uint m = 0; m < A.rows(); m++) {
    for (uint n = 0; n < A.cols(); n++) {
      if (abs(A(m,n)) > threshold) {
        const complex<double> phase = A(m,n)/abs(A(m,n));
        return phase;
      }
    }
  }
  return 1;
}

// ---------------------------------------------------------------------------------------
// Operator manipulation
// ---------------------------------------------------------------------------------------

// generate matrix B to act A on qbits qs_act out of qbits_new
MatrixXcd act(const MatrixXcd& A, const vector<uint>& qs_act, const uint qbits_new) {
  assert(A.rows() == A.cols()); // A should be square

  if (qs_act.size() == qbits_new) {
    bool do_nothing = true;
    for (uint i = 0; i < qbits_new; i++) {
      if (i != qs_act.at(i)) {
        do_nothing = false;
        break;
      }
    }
    if (do_nothing) return A;
  }

  // number of qbits A acted on
  const uint qbits_old = qs_act.size();
  assert(qbits_old == log2(A.rows()));

  // vector of qubits we are ignoring
  vector<uint> qs_ignore;
  for (uint i = 0; i < qbits_new; i++) {
    if (!in_vector(i,qs_act)) {
      qs_ignore.push_back(i);
    }
  }

  // initialize B (output) to the zero matrix
  MatrixXcd B = MatrixXcd::Zero(pow(2,qbits_new),pow(2,qbits_new));

  // loop over all entries A(m,n)
  for (uint m = 0; m < A.rows(); m++) {
    for (uint n = 0; n < A.cols(); n++) {

      // get contribution of substates |m-><n-| to indices of B
      uint b_m = 0, b_n = 0;
      for (uint q = 0; q < qbits_old; q++) {
        if (qbit_state(q,qbits_old,m)) b_m += bit_int(qs_act.at(q),qbits_new);
        if (qbit_state(q,qbits_old,n)) b_n += bit_int(qs_act.at(q),qbits_new);
      }

      // loop over all elements of the form |ms><ns| in B
      for (uint s = 0; s < pow(2,qs_ignore.size()); s++) {
        uint b_out = b_m, b_in = b_n;
        for (uint q = 0; q < qs_ignore.size(); q++) {
          if (qbit_state(q,qs_ignore.size(),s)) {
            b_out += bit_int(qs_ignore.at(q),qbits_new);
            b_in += bit_int(qs_ignore.at(q),qbits_new);
          }
        }
        B(b_out,b_in) = A(m,n);
      }
    }
  }
  return B;
}

// perform a partial trace over qbits qs_trace
MatrixXcd ptrace(const MatrixXcd& A, const vector<uint>& qs_trace) {
  assert(A.rows() == A.cols()); // A should be square

  // number of qbits A acted on
  const uint qbits_old = log2(A.rows());
  const uint qbits_new = qbits_old - qs_trace.size();

  // vector of qubits we are keeping
  vector<uint> qs_keep;
  for (uint i = 0; i < qbits_old; i++) {
    if (!in_vector(i,qs_trace)) qs_keep.push_back(i);
  }
  assert(qbits_new == qs_keep.size());

  // initialize B (output) to the zero matrix
  MatrixXcd B = MatrixXcd::Zero(pow(2,qbits_new),pow(2,qbits_new));

  // loop over all entries B(m,n)
  for (uint m = 0; m < B.rows(); m++) {
    for (uint n = 0; n < B.cols(); n++) {

      // get contribution of substates |m-><n-| to indices of A
      uint a_m = 0, a_n = 0;
      for (uint q = 0; q < qbits_new; q++) {
        if (qbit_state(q,qbits_new,m)) a_m += bit_int(qs_keep.at(q),qbits_old);
        if (qbit_state(q,qbits_new,n)) a_n += bit_int(qs_keep.at(q),qbits_old);
      }

      // loop over all elements of the form |ms><ns| in A
      for (uint s = 0; s < pow(2,qs_trace.size()); s++) {
        uint a_out = a_m, a_in = a_n;
        for (uint q = 0; q < qs_trace.size(); q++) {
          if (qbit_state(q,qs_trace.size(),s)) {
            a_out += bit_int(qs_trace.at(q),qbits_old);
            a_in += bit_int(qs_trace.at(q),qbits_old);
          }
        }
        B(m,n) += A(a_out,a_in);
      }
    }
  }
  return B;
}

// ---------------------------------------------------------------------------------------
// Gate decomposition and fidelity
// ---------------------------------------------------------------------------------------

// returns basis element p for an operator acting on a system with N spins
MatrixXcd U_basis_element(const uint p, const uint N) {
  const vector<MatrixXcd> spins = {I2, sx, sy, sz};
  MatrixXcd b_p = I1;
  for (uint n = 0; n < N; n++) {
    b_p = tp(b_p,spins.at(int_bit(p,2*n)+2*int_bit(p,2*n+1)));
  }
  return b_p;
}

// returns element p of a basis for operators acting on a system with N qubits
string U_basis_element_text(const uint p, const uint N) {
  const vector<char> spins = {'I','X','Y','Z'};
  stringstream stream;
  for (uint n = 0; n < N; n++) {
    stream << spins.at(int_bit(p,2*n)+2*int_bit(p,2*n+1));
  }
  return stream.str();
}

// returns matrix whose columns are basis Hamiltonians for a system of N spins
MatrixXcd U_basis_matrix(const uint N) {
  MatrixXcd out = MatrixXcd::Zero(pow(4,N),pow(4,N));
  for (uint p = 0; p < pow(4,N); p++) {
    out.col(p) = flatten(U_basis_element(p,N));
  }
  return out;
}

// decompose an operator into its basis elements
VectorXcd U_decompose(const MatrixXcd& U, const bool fast) {
  const uint N = log2(U.rows());
  if (fast) return U_basis_matrix(N).partialPivLu().solve(flatten(U));
  else return U_basis_matrix(N).fullPivHouseholderQr().solve(flatten(U));
}

// compute mean fidelity of gate U with respect to G, i.e. how well U approximates G
double gate_fidelity(const MatrixXcd&  U, const MatrixXcd& G) {
  assert(U.size() == G.size());
  const uint D = U.rows();
  const MatrixXcd M = G.adjoint() * U;
  return real( trace(M.adjoint()*M) + trace(M)*conj(trace(M)) ) / (D*(D+1));
}

// compute mean fidelity of propagator acting on system_qubits
double gate_fidelity(const MatrixXcd& U, const MatrixXcd& G, const vector<uint>& nuclei) {
  assert(U.size() == G.size());

  const uint spins = log2(G.rows());
  vector<uint> system_qubits = {0};
  for (uint n: nuclei) system_qubits.push_back(n+1);

  const MatrixXcd U_err = G.adjoint() * U;
  const VectorXcd H_err_vec = U_decompose(j*log(U_err));

  MatrixXcd H_env = MatrixXcd::Zero(pow(2,spins),pow(2,spins));
  for (uint h = 0; h < H_err_vec.size(); h++) {
    bool add_this_element = true;
    for (uint q: system_qubits) {
      if (int_bit(h,2*q) + int_bit(h,2*q+1)) {
        add_this_element = false;
        break;
      }
    }
    if (add_this_element) H_env += H_err_vec(h)*U_basis_element(h,spins);
  }
  return gate_fidelity(U*exp(j*H_env),G);
}

// ---------------------------------------------------------------------------------------
// Matrix vectors
// ---------------------------------------------------------------------------------------

mvec operator*(const MatrixXcd& G, const mvec& v) {
  vector<MatrixXcd> out;
  for (uint i = 0; i < v.size(); i++) {
    out.push_back(G*v.at(i));
  }
  return mvec(out);
}

// ---------------------------------------------------------------------------------------
// Printing methods
// ---------------------------------------------------------------------------------------

// print operator in human-readable form
void U_print(const MatrixXcd& U, const double threshold) {
  const int N = log2(U.rows());
  const VectorXcd hs = remove_artifacts(U_decompose(U), threshold);
  for (int p = 0; p < pow(4,N); p++) {
    if (abs(hs(p)) != 0) {
      cout << U_basis_element_text(p,N) << ": " << hs(p) << endl;
    }
  }
  cout << endl;
}

// print state vector in human readable form
void state_print(const MatrixXcd& psi) {
  const uint N = psi.size();
  const uint qbits = log2(N);
  for (uint n = 0; n < N; n++) {
    if (abs(psi(n)) != 0) {
      cout << "|";
      for (uint q = 0; q < qbits; q++) {
        cout << (qbit_state(q,qbits,n)?"d":"u");
      }
      cout << "> " << psi(n) << endl;
    }
  }
  cout << endl;
}

// print matrix in human readable form
void matrix_print(const MatrixXcd& M) {
  const uint qbits = log2(M.rows());
  for (uint m = 0; m < M.rows(); m++) {
    for (uint n = 0; n < M.cols(); n++) {
      if (abs(M(m,n)) != 0) {
        cout << "|";
        for (uint q = 0; q < qbits; q++) {
          cout << (qbit_state(q,qbits,m)?"d":"u");
        }
        cout << "><";
        for (uint q = 0; q < qbits; q++) {
          cout << (qbit_state(q,qbits,n)?"d":"u");
        }
        cout << "| " << M(m,n) << endl;
      }
    }
  }
  cout << endl;
}
<|endoftext|>


<commit_before>//---------------------------------------------------------------------------//
// $Id$
//---------------------------------------------------------------------------//
//
//---------------------------------------------------------------------------//
// Copyright (C) 2003 Andrew Ross <andrewr@coriolis.greenend.org.uk>
// This file is part of PLplot.
//
// This file is free software; you can redistribute it and/or modify
// it under the terms of the GNU Library General Public License as published by
// the Free Software Foundation; version 2 of the License.
//
// This file 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 Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public License
// along with the file; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
//---------------------------------------------------------------------------//
//
//---------------------------------------------------------------------------//
// Implementation of PLplot example 8 in C++.
//---------------------------------------------------------------------------//

#include <cstdlib>
#include <cctype>
#include <iostream>
#include <cmath>

#include "plstream.h"

class x08 {

public:
  x08(int, char**);
  void cmap1_init(int);

private:
  plstream *pls;

  static const int XPTS;
  static const int YPTS;
  static PLFLT alt[];
  static PLFLT az[];
  static char *title[];

  static int sombrero;

  static PLOptionTable options[];
};

const int x08::XPTS = 35;
const int x08::YPTS = 46;
PLFLT x08::alt[] = {60.0, 20.0};
PLFLT x08::az[] = {30.0, 60.0};

char *x08::title[] = {
  "#frPLplot Example 8 - Alt=60, Az=30",
  "#frPLplot Example 8 - Alt=20, Az=60",
};

PLOptionTable x08::options[] = {
  {
    "sombrero",                 /* Turns on use of Sombrero function */
    NULL,
    NULL,
    &x08::sombrero,
    PL_OPT_BOOL,
    "-sombrero",
    "Use the \"sombrero\" function." },
  {
    NULL,                       /* option */
    NULL,                       /* handler */
    NULL,                       /* client data */
    NULL,                       /* address of variable to set */
    0,                          /* mode flag */
      NULL,                       /* short syntax */
    NULL }                      /* long syntax */
};

int x08::sombrero = 0;

// cmap1_init1

// Initializes color map 1 in HLS space.
// Basic grayscale variation from half-dark (which makes more interesting
// looking plot compared to dark) to light.
// An interesting variation on this:
// s[1] = 1.0

void x08::cmap1_init(int gray)
{
  PLFLT *i = new PLFLT[2];
  PLFLT *h = new PLFLT[2];
  PLFLT *l = new PLFLT[2];
  PLFLT *s = new PLFLT[2];
  int *rev = new int[2];

  i[0] = 0.0;         // left boundary
  i[1] = 1.0;         // right boundary

  if (gray==1) {
    h[0] = 0.0;         // hue -- low: red (arbitrary if s=0)
    h[1] = 0.0;         // hue -- high: red (arbitrary if s=0)

    l[0] = 0.5;         // lightness -- low: half-dark
    l[1] = 1.0;         // lightness -- high: light

    s[0] = 0.0;         // minimum saturation
    s[1] = 0.0;         // minimum saturation
  }
  else {
    h[0] = 240; /* blue -> green -> yellow -> */
    h[1] = 0;   /* -> red */

    l[0] = 0.6;
    l[1] = 0.6;

    s[0] = 0.8;
    s[1] = 0.8;
  }

  rev[0] = 0;         // interpolate on front side of colour wheel.
  rev[1] = 0;         // interpolate on front side of colour wheel.

  pls->scmap1n(256);
  pls->scmap1l(0, 2, i, h, l, s, rev);
}

// Does a series of 3-d plots for a given data set, with different viewing
// options in each plot.

x08::x08( int argc, char **argv ) {
  int i, j, k;
  const int LEVELS = 10;

  PLFLT *x = new PLFLT[ XPTS ];
  PLFLT *y = new PLFLT[ YPTS ];
  PLFLT **z;
  PLFLT *clevel = new PLFLT[LEVELS];
  bool rosen = true;

  PLFLT xx, yy, r;
  PLFLT zmin, zmax;

  int ifshade;

  pls = new plstream();

  // Parse and process command line arguments.
  pls->MergeOpts(options, "x08c options",  NULL);
  pls->ParseOpts( &argc, argv, PL_PARSE_FULL );
  if (sombrero) {
    rosen = false;
  }

  // Initialize plplot.

  pls->init();

  z = new PLFLT*[XPTS];

  for (i = 0; i < XPTS; i++) {
    z[i] = new PLFLT [YPTS];
    x[i] = ((double) (i - (XPTS / 2)) / (double) (XPTS / 2));
    if (rosen)
      x[i] *=  1.5;
  }

  for( i=0; i < XPTS; i++ ) {
    x[i] = (PLFLT) (i - (XPTS/2)) / (PLFLT) (XPTS/2);
    if (rosen)
      x[i] *=  1.5;
  }

  for( j=0; j < YPTS; j++ ) {
    y[j] = (PLFLT) (j - (YPTS/2)) / (PLFLT) (YPTS/2);
    if (rosen)
      y[j] += 0.5;
  }

  for( i = 0; i < XPTS; i++ )
    {
      xx = x[i];
      for( j = 0; j < YPTS; j++ )
	{
	  yy = y[j];
	  if (rosen) {
	    z[i][j] = std::log(std::pow(1. - xx,2.) + 100 *
			       std::pow(yy - std::pow(xx,2.),2.));

	    if (std::isinf(z[i][j])) /* the log() of the function may become -inf */
	      z[i][j] = -5.; /* -MAXFLOAT would mess-up up the scale */
	  }
	  else {
	    r = std::sqrt(xx * xx + yy * yy);
	    z[i][j] = std::exp(-r * r) * std::cos(2.0 * M_PI * r);
	  }
	  if (zmin > z[i][j])
	    zmin = z[i][j];
	  if (zmax < z[i][j])
	    zmax = z[i][j];
	}
    }

  PLFLT step = (zmax-zmin)/(LEVELS+1);
  for (i=0; i<LEVELS; i++)
    clevel[i] = zmin + step*(i+1);

  pls->lightsource( 1., 1., 1. );
  for( k = 0; k < 2; k++ )
    {
      for( ifshade = 0; ifshade < 4; ifshade++)
	{
	  pls->adv(0);
	  pls->vpor(0.0, 1.0, 0.0, 0.9);
	  pls->wind(-1.0, 1.0, -0.9, 1.1);
	  pls->col0(3);
	  pls->mtex("t", 1.0, 0.5, 0.5, title[k]);
	  pls->col0(1);
	  if(rosen)
	    pls->w3d( 1.0, 1.0, 1.0, -1.5, 1.5, -0.5, 1.5, zmin, zmax,
		       alt[k], az[k] );
	  else
	    pls->w3d( 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, zmin, zmax,
		       alt[k], az[k] );
	  pls->box3( "bnstu", "x axis", 0.0, 0,
		      "bnstu", "y axis", 0.0, 0,
		      "bcdmnstuv", "z axis", 0.0, 0 );

	  pls->col0(2);

	  if (ifshade == 0) { /* diffuse light surface plot */
	    cmap1_init(1);
	    pls->surf3d( x, y, z, XPTS, YPTS, 0, NULL, 0 );
	  } else if (ifshade == 1) { /* magnitude colored plot */
	    cmap1_init(0);
	    pls->surf3d( x, y, z, XPTS, YPTS, MAG_COLOR, NULL, 0 );
	  } else if (ifshade == 2) { /*  magnitude colored plot with faceted squares */
	    pls->surf3d( x, y, z, XPTS, YPTS, MAG_COLOR | FACETED, NULL, 0 );
	  } else                     /* magnitude colored plot with contours */
	    pls->surf3d( x, y, z, XPTS, YPTS, MAG_COLOR | SURF_CONT | BASE_CONT, clevel, LEVELS );
	}
    }

  delete pls;
}

int main( int argc, char **argv )
{
  x08 *x = new x08( argc, argv );
}

//---------------------------------------------------------------------------//
//                              End of x08.cc
//---------------------------------------------------------------------------//
<commit_msg>Replace isinf logic by simple check for zero log argument.<commit_after>//---------------------------------------------------------------------------//
// $Id$
//---------------------------------------------------------------------------//
//
//---------------------------------------------------------------------------//
// Copyright (C) 2003 Andrew Ross <andrewr@coriolis.greenend.org.uk>
// This file is part of PLplot.
//
// This file is free software; you can redistribute it and/or modify
// it under the terms of the GNU Library General Public License as published by
// the Free Software Foundation; version 2 of the License.
//
// This file 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 Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public License
// along with the file; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
//---------------------------------------------------------------------------//
//
//---------------------------------------------------------------------------//
// Implementation of PLplot example 8 in C++.
//---------------------------------------------------------------------------//

#include <cstdlib>
#include <cctype>
#include <iostream>
#include <cmath>

#include "plstream.h"

class x08 {

public:
  x08(int, char**);
  void cmap1_init(int);

private:
  plstream *pls;

  static const int XPTS;
  static const int YPTS;
  static PLFLT alt[];
  static PLFLT az[];
  static char *title[];

  static int sombrero;

  static PLOptionTable options[];
};

const int x08::XPTS = 35;
const int x08::YPTS = 46;
PLFLT x08::alt[] = {60.0, 20.0};
PLFLT x08::az[] = {30.0, 60.0};

char *x08::title[] = {
  "#frPLplot Example 8 - Alt=60, Az=30",
  "#frPLplot Example 8 - Alt=20, Az=60",
};

PLOptionTable x08::options[] = {
  {
    "sombrero",                 /* Turns on use of Sombrero function */
    NULL,
    NULL,
    &x08::sombrero,
    PL_OPT_BOOL,
    "-sombrero",
    "Use the \"sombrero\" function." },
  {
    NULL,                       /* option */
    NULL,                       /* handler */
    NULL,                       /* client data */
    NULL,                       /* address of variable to set */
    0,                          /* mode flag */
      NULL,                       /* short syntax */
    NULL }                      /* long syntax */
};

int x08::sombrero = 0;

// cmap1_init1

// Initializes color map 1 in HLS space.
// Basic grayscale variation from half-dark (which makes more interesting
// looking plot compared to dark) to light.
// An interesting variation on this:
// s[1] = 1.0

void x08::cmap1_init(int gray)
{
  PLFLT *i = new PLFLT[2];
  PLFLT *h = new PLFLT[2];
  PLFLT *l = new PLFLT[2];
  PLFLT *s = new PLFLT[2];
  int *rev = new int[2];

  i[0] = 0.0;         // left boundary
  i[1] = 1.0;         // right boundary

  if (gray==1) {
    h[0] = 0.0;         // hue -- low: red (arbitrary if s=0)
    h[1] = 0.0;         // hue -- high: red (arbitrary if s=0)

    l[0] = 0.5;         // lightness -- low: half-dark
    l[1] = 1.0;         // lightness -- high: light

    s[0] = 0.0;         // minimum saturation
    s[1] = 0.0;         // minimum saturation
  }
  else {
    h[0] = 240; /* blue -> green -> yellow -> */
    h[1] = 0;   /* -> red */

    l[0] = 0.6;
    l[1] = 0.6;

    s[0] = 0.8;
    s[1] = 0.8;
  }

  rev[0] = 0;         // interpolate on front side of colour wheel.
  rev[1] = 0;         // interpolate on front side of colour wheel.

  pls->scmap1n(256);
  pls->scmap1l(0, 2, i, h, l, s, rev);
}

// Does a series of 3-d plots for a given data set, with different viewing
// options in each plot.

x08::x08( int argc, char **argv ) {
  int i, j, k;
  const int LEVELS = 10;

  PLFLT *x = new PLFLT[ XPTS ];
  PLFLT *y = new PLFLT[ YPTS ];
  PLFLT **z;
  PLFLT *clevel = new PLFLT[LEVELS];
  bool rosen = true;

  PLFLT xx, yy, r;
  PLFLT zmin, zmax;

  int ifshade;

  pls = new plstream();

  // Parse and process command line arguments.
  pls->MergeOpts(options, "x08c options",  NULL);
  pls->ParseOpts( &argc, argv, PL_PARSE_FULL );
  if (sombrero) {
    rosen = false;
  }

  // Initialize plplot.

  pls->init();

  z = new PLFLT*[XPTS];

  for (i = 0; i < XPTS; i++) {
    z[i] = new PLFLT [YPTS];
    x[i] = ((double) (i - (XPTS / 2)) / (double) (XPTS / 2));
    if (rosen)
      x[i] *=  1.5;
  }

  for( i=0; i < XPTS; i++ ) {
    x[i] = (PLFLT) (i - (XPTS/2)) / (PLFLT) (XPTS/2);
    if (rosen)
      x[i] *=  1.5;
  }

  for( j=0; j < YPTS; j++ ) {
    y[j] = (PLFLT) (j - (YPTS/2)) / (PLFLT) (YPTS/2);
    if (rosen)
      y[j] += 0.5;
  }

  for( i = 0; i < XPTS; i++ )
    {
      xx = x[i];
      for( j = 0; j < YPTS; j++ )
	{
	  yy = y[j];
	  if (rosen) {
	    z[i][j] = std::pow(1. - xx,2.) + 100 *
			       std::pow(yy - std::pow(xx,2.),2.);

	    if (z[i][j] > 0.)
	       z[i][j] = std::log(z[i][j]);
	    else
	      z[i][j] = -5.; /* -MAXFLOAT would mess-up up the scale */
	  }
	  else {
	    r = std::sqrt(xx * xx + yy * yy);
	    z[i][j] = std::exp(-r * r) * std::cos(2.0 * M_PI * r);
	  }
          if(i==0 && j==0) {
	     zmin = z[i][j];
	     zmax = zmin;
	  }
	  if (zmin > z[i][j])
	    zmin = z[i][j];
	  if (zmax < z[i][j])
	    zmax = z[i][j];
	}
    }

  PLFLT step = (zmax-zmin)/(LEVELS+1);
  for (i=0; i<LEVELS; i++)
    clevel[i] = zmin + step*(i+1);

  pls->lightsource( 1., 1., 1. );
  for( k = 0; k < 2; k++ )
    {
      for( ifshade = 0; ifshade < 4; ifshade++)
	{
	  pls->adv(0);
	  pls->vpor(0.0, 1.0, 0.0, 0.9);
	  pls->wind(-1.0, 1.0, -0.9, 1.1);
	  pls->col0(3);
	  pls->mtex("t", 1.0, 0.5, 0.5, title[k]);
	  pls->col0(1);
	  if(rosen)
	    pls->w3d( 1.0, 1.0, 1.0, -1.5, 1.5, -0.5, 1.5, zmin, zmax,
		       alt[k], az[k] );
	  else
	    pls->w3d( 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, zmin, zmax,
		       alt[k], az[k] );
	  pls->box3( "bnstu", "x axis", 0.0, 0,
		      "bnstu", "y axis", 0.0, 0,
		      "bcdmnstuv", "z axis", 0.0, 0 );

	  pls->col0(2);

	  if (ifshade == 0) { /* diffuse light surface plot */
	    cmap1_init(1);
	    pls->surf3d( x, y, z, XPTS, YPTS, 0, NULL, 0 );
	  } else if (ifshade == 1) { /* magnitude colored plot */
	    cmap1_init(0);
	    pls->surf3d( x, y, z, XPTS, YPTS, MAG_COLOR, NULL, 0 );
	  } else if (ifshade == 2) { /*  magnitude colored plot with faceted squares */
	    pls->surf3d( x, y, z, XPTS, YPTS, MAG_COLOR | FACETED, NULL, 0 );
	  } else                     /* magnitude colored plot with contours */
	    pls->surf3d( x, y, z, XPTS, YPTS, MAG_COLOR | SURF_CONT | BASE_CONT, clevel, LEVELS );
	}
    }

  delete pls;
}

int main( int argc, char **argv )
{
  x08 *x = new x08( argc, argv );
}

//---------------------------------------------------------------------------//
//                              End of x08.cc
//---------------------------------------------------------------------------//
<|endoftext|>


<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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

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

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

#include "paddle/framework/executor.h"

#include <memory>
#include <vector>

#include "gflags/gflags.h"
#include "gtest/gtest.h"
#include "paddle/framework/attribute.h"
#include "paddle/framework/backward.h"
#include "paddle/framework/block_desc.h"
#include "paddle/framework/op_desc.h"
#include "paddle/framework/op_registry.h"
#include "paddle/framework/operator.h"

USE_OP(elementwise_add);
USE_OP(gaussian_random);
USE_OP(feed);
USE_OP(fetch);
USE_OP(mul);
USE_OP(sum);
USE_OP(squared_l2_distance);
USE_OP(fill_constant);
USE_OP(sgd);

using namespace paddle::platform;
using namespace paddle::framework;

void AddOp(const std::string& type, const VariableNameMap& inputs,
           const VariableNameMap& outputs, AttributeMap attrs,
           paddle::framework::BlockDescBind* block) {
  // insert output
  for (auto kv : outputs) {
    for (auto v : kv.second) {
      auto var = block->NewVar(v);
      var->SetDataType(paddle::framework::DataType::FP32);
    }
  }

  // insert op
  auto op = block->AppendOp();
  op->SetType(type);
  for (auto& kv : inputs) {
    op->SetInput(kv.first, kv.second);
  }
  for (auto& kv : outputs) {
    op->SetOutput(kv.first, kv.second);
  }
  op->SetAttrMap(attrs);
  op->CheckAttrs();
}

// Tensors in feed value variable will only be in CPUPlace
// So we can memcpy the data from vector<T> to feed_value
template <typename T>
void SetFeedVariable(const std::vector<std::vector<T>>& inputs,
                     const std::vector<std::vector<int64_t>>& dims) {
  Variable* g_feed_value = GetGlobalScope().FindVar("feed_value");
  auto& feed_inputs =
      *(g_feed_value->GetMutable<std::vector<paddle::framework::Tensor>>());
  size_t size = inputs.size();
  feed_inputs.resize(size);
  for (size_t i = 0; i < size; i++) {
    T* dst = feed_inputs[i].mutable_data<T>(make_ddim(dims[i]), CPUPlace());
    memcpy(dst, inputs[i].data(), inputs[i].size() * sizeof(T));
  }
}

// Tensors in fetch value variable will only be in CPUPlace
// So we can memcpy the data from fetch_value to vector<T>
template <typename T>
std::vector<std::vector<T>> GetFetchVariable() {
  Variable* g_fetch_value = GetGlobalScope().FindVar("fetch_value");
  auto& fetch_outputs =
      *(g_fetch_value->GetMutable<std::vector<paddle::framework::Tensor>>());

  size_t size = fetch_outputs.size();
  std::vector<std::vector<T>> result;
  result.reserve(size);
  for (size_t i = 0; i < size; i++) {
    std::vector<T> tmp;
    tmp.resize(fetch_outputs[i].numel());
    memcpy(tmp.data(), fetch_outputs[i].data<T>(),
           fetch_outputs[i].numel() * sizeof(T));
    result.push_back(tmp);
  }

  return result;
}

class ExecutorTesterRandom : public ::testing::Test {
 public:
  virtual void SetUp() override {
    int input_dim = 3, batch_size = 2, embed_dim = 5;

    auto temp_init_root_block = init_pdesc_.add_blocks();
    temp_init_root_block->set_idx(0);
    temp_init_root_block->set_parent_idx(-1);
    paddle::framework::ProgramDescBind& init_program =
        paddle::framework::ProgramDescBind::Instance(&init_pdesc_);
    paddle::framework::BlockDescBind* init_root_block = init_program.Block(0);

    AddOp("gaussian_random", {}, {{"Out", {"w1"}}},
          {{"dims", std::vector<int>{input_dim, embed_dim}}}, init_root_block);
    AddOp("gaussian_random", {}, {{"Out", {"w2"}}},
          {{"dims", std::vector<int>{embed_dim, input_dim}}}, init_root_block);
    AddOp("fetch", {{"Input", {"w1"}}}, {}, {{"col", 0}}, init_root_block);
    AddOp("fetch", {{"Input", {"w2"}}}, {}, {{"col", 1}}, init_root_block);

    // flush
    init_program.Proto();

    // run block
    auto temp_root_block = pdesc_.add_blocks();
    temp_root_block->set_idx(0);
    temp_root_block->set_parent_idx(-1);
    paddle::framework::ProgramDescBind& program =
        paddle::framework::ProgramDescBind::Instance(&pdesc_);
    paddle::framework::BlockDescBind* root_block = program.Block(0);

    // feed data
    inputs_.push_back({1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
    dims_.push_back({batch_size, input_dim});
    AddOp("feed", {}, {{"Out", {"a"}}},
          {{"dims", std::vector<int>{batch_size, input_dim}}, {"col", 0}},
          root_block);

    // forward
    AddOp("mul", {{"X", {"a"}}, {"Y", {"w1"}}}, {{"Out", {"b"}}}, {},
          root_block);
    AddOp("mul", {{"X", {"b"}}, {"Y", {"w2"}}}, {{"Out", {"a_out"}}}, {},
          root_block);
    AddOp("squared_l2_distance", {{"X", {"a"}}, {"Y", {"a_out"}}},
          {{"Out", {"l2_distance"}}, {"sub_result", {"l2_distance_sub"}}}, {},
          root_block);

    // backward
    AddOp("fill_constant", {}, {{"Out", {"l2_distance@GRAD"}}},
          {{"shape", std::vector<int>{batch_size, 1}}, {"value", float(1.0)}},
          root_block);
    AppendBackward(program, {});

    // update
    AddOp("fill_constant", {}, {{"Out", {"learning_rate"}}},
          {{"shape", std::vector<int>{1}}, {"value", float(0.001)}},
          root_block);
    AddOp("sgd", {{"Param", {"w1"}},
                  {"LearningRate", {"learning_rate"}},
                  {"Grad", {"w1@GRAD"}}},
          {{"ParamOut", {"w1"}}}, {}, root_block);
    AddOp("sgd", {{"Param", {"w2"}},
                  {"LearningRate", {"learning_rate"}},
                  {"Grad", {"w2@GRAD"}}},
          {{"ParamOut", {"w2"}}}, {}, root_block);

    AddOp("fetch", {{"Input", {"w1"}}}, {}, {{"col", 0}}, root_block);
    AddOp("fetch", {{"Input", {"w2"}}}, {}, {{"col", 1}}, root_block);
    AddOp("fetch", {{"Input", {"l2_distance"}}}, {}, {{"col", 0}}, root_block);

    // flush
    program.Proto();
  }

 protected:
  ProgramDesc init_pdesc_;
  ProgramDesc pdesc_;
  std::vector<std::vector<float>> inputs_;
  std::vector<std::vector<int64_t>> dims_;
};

class ExecutorTesterFeedAndFetch : public ::testing::Test {
 public:
  virtual void SetUp() override {
    auto temp_root_block = pdesc_.add_blocks();
    temp_root_block->set_idx(0);
    temp_root_block->set_parent_idx(-1);

    // wrap to BlockDescBind
    paddle::framework::ProgramDescBind& program =
        paddle::framework::ProgramDescBind::Instance(&pdesc_);
    paddle::framework::BlockDescBind* root_block = program.Block(0);

    std::vector<int> dim{6};

    AddOp("feed", {}, {{"Out", {"a"}}}, {{"dims", dim}, {"col", 0}},
          root_block);
    AddOp("feed", {}, {{"Out", {"b"}}}, {{"dims", dim}, {"col", 1}},
          root_block);
    AddOp("fetch", {{"Input", {"a"}}}, {}, {{"col", 0}}, root_block);
    AddOp("fetch", {{"Input", {"b"}}}, {}, {{"col", 1}}, root_block);

    // flush
    program.Proto();

    std::vector<float> vec1 = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
    std::vector<float> vec2 = {4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
    inputs_.push_back(vec1);
    inputs_.push_back(vec2);
    dims_.push_back({static_cast<int64_t>(vec1.size())});
    dims_.push_back({static_cast<int64_t>(vec2.size())});
  }

 protected:
  ProgramDesc pdesc_;
  std::vector<std::vector<float>> inputs_;
  std::vector<std::vector<int64_t>> dims_;
};

#ifndef PADDLE_WITH_CUDA
TEST_F(ExecutorTesterRandom, CPU) {
  std::vector<Place> places;
  CPUPlace cpu_place;
  places.push_back(cpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  paddle::memory::Used(cpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  executor->Run(init_pdesc_, &GetGlobalScope(), 0);
  SetFeedVariable<float>(inputs_, dims_);
  executor->Run(pdesc_, &GetGlobalScope(), 0);
  std::vector<std::vector<float>> result = GetFetchVariable<float>();
}

TEST_F(ExecutorTesterFeedAndFetch, CPU) {
  std::vector<Place> places;
  CPUPlace cpu_place;
  places.push_back(cpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  paddle::memory::Used(cpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  for (int batch_id = 0; batch_id < 3; batch_id++) {
    SetFeedVariable<float>(inputs_, dims_);
    executor->Run(pdesc_, &GetGlobalScope(), 0);
    std::vector<std::vector<float>> result = GetFetchVariable<float>();
    PADDLE_ENFORCE_EQ(result.size(), inputs_.size());
    for (size_t i = 0; i < result.size(); ++i) {
      PADDLE_ENFORCE_EQ(result[i].size(), inputs_[i].size());
      for (size_t j = 0; j < result[i].size(); ++j) {
        PADDLE_ENFORCE_EQ(result[i][j], inputs_[i][j]);
      }
    }
  }
}
#else
TEST_F(ExecutorTesterRandom, GPU) {
  std::vector<Place> places;
  GPUPlace gpu_place(0);
  places.push_back(gpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  // If paddle is compiled with GPU, both CPU and GPU BuddyAllocator
  // need to be used at first.
  paddle::memory::Used(CPUPlace());
  paddle::memory::Used(gpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  executor->Run(init_pdesc_, &GetGlobalScope(), 0);
  for (int batch_id = 0; batch_id < 3; batch_id++) {
    SetFeedVariable<float>(inputs_, dims_);
    executor->Run(pdesc_, &GetGlobalScope(), 0);
  }
}

TEST_F(ExecutorTesterFeedAndFetch, GPU) {
  std::vector<Place> places;
  GPUPlace gpu_place(0);
  places.push_back(gpu_place);
  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  // If paddle is compiled with GPU, both CPU and GPU BuddyAllocator
  // need to be used at first.
  paddle::memory::Used(CPUPlace());
  paddle::memory::Used(gpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  for (int batch_id = 0; batch_id < 3; batch_id++) {
    SetFeedVariable<float>(inputs_, dims_);
    executor->Run(pdesc_, &GetGlobalScope(), 0);
    std::vector<std::vector<float>> result = GetFetchVariable<float>();
    PADDLE_ENFORCE_EQ(result.size(), inputs_.size());
    for (size_t i = 0; i < result.size(); ++i) {
      PADDLE_ENFORCE_EQ(result[i].size(), inputs_[i].size());
      for (size_t j = 0; j < result[i].size(); ++j) {
        PADDLE_ENFORCE_EQ(result[i][j], inputs_[i][j]);
      }
    }
  }
}
#endif

DECLARE_double(fraction_of_gpu_memory_to_use);

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  // Use less GPU memory for unittest.
  FLAGS_fraction_of_gpu_memory_to_use = 0.25;
  return RUN_ALL_TESTS();
}<commit_msg>Fix CPU compile (#4781)<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve.

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

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

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

#include "paddle/framework/executor.h"

#include <memory>
#include <vector>

#include "gflags/gflags.h"
#include "gtest/gtest.h"
#include "paddle/framework/attribute.h"
#include "paddle/framework/backward.h"
#include "paddle/framework/block_desc.h"
#include "paddle/framework/op_desc.h"
#include "paddle/framework/op_registry.h"
#include "paddle/framework/operator.h"

USE_OP(elementwise_add);
USE_OP(gaussian_random);
USE_OP(feed);
USE_OP(fetch);
USE_OP(mul);
USE_OP(sum);
USE_OP(squared_l2_distance);
USE_OP(fill_constant);
USE_OP(sgd);

using namespace paddle::platform;
using namespace paddle::framework;

void AddOp(const std::string& type, const VariableNameMap& inputs,
           const VariableNameMap& outputs, AttributeMap attrs,
           paddle::framework::BlockDescBind* block) {
  // insert output
  for (auto kv : outputs) {
    for (auto v : kv.second) {
      auto var = block->NewVar(v);
      var->SetDataType(paddle::framework::DataType::FP32);
    }
  }

  // insert op
  auto op = block->AppendOp();
  op->SetType(type);
  for (auto& kv : inputs) {
    op->SetInput(kv.first, kv.second);
  }
  for (auto& kv : outputs) {
    op->SetOutput(kv.first, kv.second);
  }
  op->SetAttrMap(attrs);
  op->CheckAttrs();
}

// Tensors in feed value variable will only be in CPUPlace
// So we can memcpy the data from vector<T> to feed_value
template <typename T>
void SetFeedVariable(const std::vector<std::vector<T>>& inputs,
                     const std::vector<std::vector<int64_t>>& dims) {
  Variable* g_feed_value = GetGlobalScope().FindVar("feed_value");
  auto& feed_inputs =
      *(g_feed_value->GetMutable<std::vector<paddle::framework::Tensor>>());
  size_t size = inputs.size();
  feed_inputs.resize(size);
  for (size_t i = 0; i < size; i++) {
    T* dst = feed_inputs[i].mutable_data<T>(make_ddim(dims[i]), CPUPlace());
    memcpy(dst, inputs[i].data(), inputs[i].size() * sizeof(T));
  }
}

// Tensors in fetch value variable will only be in CPUPlace
// So we can memcpy the data from fetch_value to vector<T>
template <typename T>
std::vector<std::vector<T>> GetFetchVariable() {
  Variable* g_fetch_value = GetGlobalScope().FindVar("fetch_value");
  auto& fetch_outputs =
      *(g_fetch_value->GetMutable<std::vector<paddle::framework::Tensor>>());

  size_t size = fetch_outputs.size();
  std::vector<std::vector<T>> result;
  result.reserve(size);
  for (size_t i = 0; i < size; i++) {
    std::vector<T> tmp;
    tmp.resize(fetch_outputs[i].numel());
    memcpy(tmp.data(), fetch_outputs[i].data<T>(),
           fetch_outputs[i].numel() * sizeof(T));
    result.push_back(tmp);
  }

  return result;
}

class ExecutorTesterRandom : public ::testing::Test {
 public:
  virtual void SetUp() override {
    int input_dim = 3, batch_size = 2, embed_dim = 5;

    auto temp_init_root_block = init_pdesc_.add_blocks();
    temp_init_root_block->set_idx(0);
    temp_init_root_block->set_parent_idx(-1);
    paddle::framework::ProgramDescBind& init_program =
        paddle::framework::ProgramDescBind::Instance(&init_pdesc_);
    paddle::framework::BlockDescBind* init_root_block = init_program.Block(0);

    AddOp("gaussian_random", {}, {{"Out", {"w1"}}},
          {{"dims", std::vector<int>{input_dim, embed_dim}}}, init_root_block);
    AddOp("gaussian_random", {}, {{"Out", {"w2"}}},
          {{"dims", std::vector<int>{embed_dim, input_dim}}}, init_root_block);
    AddOp("fetch", {{"Input", {"w1"}}}, {}, {{"col", 0}}, init_root_block);
    AddOp("fetch", {{"Input", {"w2"}}}, {}, {{"col", 1}}, init_root_block);

    // flush
    init_program.Proto();

    // run block
    auto temp_root_block = pdesc_.add_blocks();
    temp_root_block->set_idx(0);
    temp_root_block->set_parent_idx(-1);
    paddle::framework::ProgramDescBind& program =
        paddle::framework::ProgramDescBind::Instance(&pdesc_);
    paddle::framework::BlockDescBind* root_block = program.Block(0);

    // feed data
    inputs_.push_back({1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
    dims_.push_back({batch_size, input_dim});
    AddOp("feed", {}, {{"Out", {"a"}}},
          {{"dims", std::vector<int>{batch_size, input_dim}}, {"col", 0}},
          root_block);

    // forward
    AddOp("mul", {{"X", {"a"}}, {"Y", {"w1"}}}, {{"Out", {"b"}}}, {},
          root_block);
    AddOp("mul", {{"X", {"b"}}, {"Y", {"w2"}}}, {{"Out", {"a_out"}}}, {},
          root_block);
    AddOp("squared_l2_distance", {{"X", {"a"}}, {"Y", {"a_out"}}},
          {{"Out", {"l2_distance"}}, {"sub_result", {"l2_distance_sub"}}}, {},
          root_block);

    // backward
    AddOp("fill_constant", {}, {{"Out", {"l2_distance@GRAD"}}},
          {{"shape", std::vector<int>{batch_size, 1}}, {"value", float(1.0)}},
          root_block);
    AppendBackward(program, {});

    // update
    AddOp("fill_constant", {}, {{"Out", {"learning_rate"}}},
          {{"shape", std::vector<int>{1}}, {"value", float(0.001)}},
          root_block);
    AddOp("sgd", {{"Param", {"w1"}},
                  {"LearningRate", {"learning_rate"}},
                  {"Grad", {"w1@GRAD"}}},
          {{"ParamOut", {"w1"}}}, {}, root_block);
    AddOp("sgd", {{"Param", {"w2"}},
                  {"LearningRate", {"learning_rate"}},
                  {"Grad", {"w2@GRAD"}}},
          {{"ParamOut", {"w2"}}}, {}, root_block);

    AddOp("fetch", {{"Input", {"w1"}}}, {}, {{"col", 0}}, root_block);
    AddOp("fetch", {{"Input", {"w2"}}}, {}, {{"col", 1}}, root_block);
    AddOp("fetch", {{"Input", {"l2_distance"}}}, {}, {{"col", 0}}, root_block);

    // flush
    program.Proto();
  }

 protected:
  ProgramDesc init_pdesc_;
  ProgramDesc pdesc_;
  std::vector<std::vector<float>> inputs_;
  std::vector<std::vector<int64_t>> dims_;
};

class ExecutorTesterFeedAndFetch : public ::testing::Test {
 public:
  virtual void SetUp() override {
    auto temp_root_block = pdesc_.add_blocks();
    temp_root_block->set_idx(0);
    temp_root_block->set_parent_idx(-1);

    // wrap to BlockDescBind
    paddle::framework::ProgramDescBind& program =
        paddle::framework::ProgramDescBind::Instance(&pdesc_);
    paddle::framework::BlockDescBind* root_block = program.Block(0);

    std::vector<int> dim{6};

    AddOp("feed", {}, {{"Out", {"a"}}}, {{"dims", dim}, {"col", 0}},
          root_block);
    AddOp("feed", {}, {{"Out", {"b"}}}, {{"dims", dim}, {"col", 1}},
          root_block);
    AddOp("fetch", {{"Input", {"a"}}}, {}, {{"col", 0}}, root_block);
    AddOp("fetch", {{"Input", {"b"}}}, {}, {{"col", 1}}, root_block);

    // flush
    program.Proto();

    std::vector<float> vec1 = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
    std::vector<float> vec2 = {4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
    inputs_.push_back(vec1);
    inputs_.push_back(vec2);
    dims_.push_back({static_cast<int64_t>(vec1.size())});
    dims_.push_back({static_cast<int64_t>(vec2.size())});
  }

 protected:
  ProgramDesc pdesc_;
  std::vector<std::vector<float>> inputs_;
  std::vector<std::vector<int64_t>> dims_;
};

#ifndef PADDLE_WITH_CUDA
TEST_F(ExecutorTesterRandom, CPU) {
  std::vector<Place> places;
  CPUPlace cpu_place;
  places.push_back(cpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  paddle::memory::Used(cpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  executor->Run(init_pdesc_, &GetGlobalScope(), 0);
  SetFeedVariable<float>(inputs_, dims_);
  executor->Run(pdesc_, &GetGlobalScope(), 0);
  std::vector<std::vector<float>> result = GetFetchVariable<float>();
}

TEST_F(ExecutorTesterFeedAndFetch, CPU) {
  std::vector<Place> places;
  CPUPlace cpu_place;
  places.push_back(cpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  paddle::memory::Used(cpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  for (int batch_id = 0; batch_id < 3; batch_id++) {
    SetFeedVariable<float>(inputs_, dims_);
    executor->Run(pdesc_, &GetGlobalScope(), 0);
    std::vector<std::vector<float>> result = GetFetchVariable<float>();
    PADDLE_ENFORCE_EQ(result.size(), inputs_.size());
    for (size_t i = 0; i < result.size(); ++i) {
      PADDLE_ENFORCE_EQ(result[i].size(), inputs_[i].size());
      for (size_t j = 0; j < result[i].size(); ++j) {
        PADDLE_ENFORCE_EQ(result[i][j], inputs_[i][j]);
      }
    }
  }
}
#else
TEST_F(ExecutorTesterRandom, GPU) {
  std::vector<Place> places;
  GPUPlace gpu_place(0);
  places.push_back(gpu_place);

  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  // If paddle is compiled with GPU, both CPU and GPU BuddyAllocator
  // need to be used at first.
  paddle::memory::Used(CPUPlace());
  paddle::memory::Used(gpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  executor->Run(init_pdesc_, &GetGlobalScope(), 0);
  for (int batch_id = 0; batch_id < 3; batch_id++) {
    SetFeedVariable<float>(inputs_, dims_);
    executor->Run(pdesc_, &GetGlobalScope(), 0);
  }
}

TEST_F(ExecutorTesterFeedAndFetch, GPU) {
  std::vector<Place> places;
  GPUPlace gpu_place(0);
  places.push_back(gpu_place);
  // We have a global Scope and BuddyAllocator, and we must ensure
  // global BuddyAllocator is initialized before global Scope. Thus,
  // global Scope will deconstruct before BuddyAllocator. Otherwise,
  // "pointer being freed was not allocated" error will appear.
  // If paddle is compiled with GPU, both CPU and GPU BuddyAllocator
  // need to be used at first.
  paddle::memory::Used(CPUPlace());
  paddle::memory::Used(gpu_place);

  std::unique_ptr<Executor> executor(new Executor(places));

  for (int batch_id = 0; batch_id < 3; batch_id++) {
    SetFeedVariable<float>(inputs_, dims_);
    executor->Run(pdesc_, &GetGlobalScope(), 0);
    std::vector<std::vector<float>> result = GetFetchVariable<float>();
    PADDLE_ENFORCE_EQ(result.size(), inputs_.size());
    for (size_t i = 0; i < result.size(); ++i) {
      PADDLE_ENFORCE_EQ(result[i].size(), inputs_[i].size());
      for (size_t j = 0; j < result[i].size(); ++j) {
        PADDLE_ENFORCE_EQ(result[i][j], inputs_[i][j]);
      }
    }
  }
}

DECLARE_double(fraction_of_gpu_memory_to_use);

int main(int argc, char** argv) {
  testing::InitGoogleTest(&argc, argv);
  // Use less GPU memory for unittest.
  FLAGS_fraction_of_gpu_memory_to_use = 0.25;
  return RUN_ALL_TESTS();
}

#endif<|endoftext|>


<commit_before>///
/// @file  primecount.cpp
/// @brief Function definitions of primecount.hpp
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount.hpp>
#include <primecount-internal.hpp>
#include <primesieve.hpp>
#include <calculator.hpp>
#include <int128_t.hpp>
#include <imath.hpp>

#include <algorithm>
#include <chrono>
#include <cmath>
#include <limits>
#include <sstream>
#include <string>
#include <stdint.h>

#ifdef _OPENMP
  #include <omp.h>
#endif

#ifdef HAVE_MPI

#include <mpi.h>

namespace primecount {

int mpi_num_procs()
{
  int procs;
  MPI_Comm_size(MPI_COMM_WORLD, &procs);
  return procs;
}

int mpi_proc_id()
{
  int proc_id;
  MPI_Comm_rank(MPI_COMM_WORLD, &proc_id);
  return proc_id;
}

int mpi_master_proc_id()
{
  return 0;
}

bool is_mpi_master_proc()
{
  return mpi_proc_id() == mpi_master_proc_id();
}

} // namespace

#endif

using namespace std;

namespace {

#ifdef _OPENMP
  int threads_ = 0;
#endif

// Below 10^7 LMO is faster than Deleglise-Rivat
const int lmo_threshold_ = 10000000;

int status_precision_ = -1;

// Tuning factor used in the Lagarias-Miller-Odlyzko
// and Deleglise-Rivat algorithms.
double alpha_ = -1;

// Tuning factor used in Xavier Gourdon's algorithm
double alpha_y_ = -1;

// Tuning factor used in Xavier Gourdon's algorithm
double alpha_z_ = -1;

}

namespace primecount {

int64_t pi(int64_t x)
{
  return pi(x, get_num_threads());
}

int64_t pi(int64_t x, int threads)
{
  if (x <= lmo_threshold_)
    return pi_lmo5(x);
  else
    return pi_deleglise_rivat(x, threads);
}

#ifdef HAVE_INT128_T

int128_t pi(int128_t x)
{
  return pi(x, get_num_threads());
}

int128_t pi(int128_t x, int threads)
{
  // use 64-bit if possible
  if (x <= numeric_limits<int64_t>::max())
    return pi((int64_t) x, threads);
  else
    return pi_deleglise_rivat(x, threads);
}

#endif

string pi(const string& x)
{
  return pi(x, get_num_threads());
}

string pi(const string& x, int threads)
{
  maxint_t pi_x = pi(to_maxint(x), threads);
  ostringstream oss;
  oss << pi_x;
  return oss.str();
}

int64_t pi_legendre(int64_t x)
{
  return pi_legendre(x, get_num_threads());
}

int64_t pi_lehmer(int64_t x)
{
  return pi_lehmer(x, get_num_threads());
}

int64_t pi_lmo(int64_t x)
{
  return pi_lmo(x, get_num_threads());
}

int64_t pi_lmo(int64_t x, int threads)
{
  return pi_lmo_parallel(x, threads);
}

int64_t pi_meissel(int64_t x)
{
  return pi_meissel(x, get_num_threads());
}

int64_t pi_deleglise_rivat(int64_t x)
{
  return pi_deleglise_rivat(x, get_num_threads());
}

int64_t pi_deleglise_rivat(int64_t x, int threads)
{
  return pi_deleglise_rivat_parallel1(x, threads);
}

#ifdef HAVE_INT128_T

int128_t pi_deleglise_rivat(int128_t x)
{
  return pi_deleglise_rivat(x, get_num_threads());
}

int128_t pi_deleglise_rivat(int128_t x, int threads)
{
  // use 64-bit if possible
  if (x <= numeric_limits<int64_t>::max())
    return pi_deleglise_rivat_parallel1((int64_t) x, threads);
  else
    return pi_deleglise_rivat_parallel2(x, threads);
}

#endif

int64_t nth_prime(int64_t n)
{
  return nth_prime(n, get_num_threads());
}

int64_t phi(int64_t x, int64_t a)
{
  return phi(x, a, get_num_threads());
}

/// Returns the largest integer supported by pi(x). The
/// return type is a string as get_max_x() can be a 128-bit
/// integer which is not supported by all compilers.
///
string get_max_x(double alpha)
{
  ostringstream oss;

#ifdef HAVE_INT128_T
  // primecount is limited by:
  // z <= 2^62, with z = x^(2/3) / alpha
  // x^(2/3) / alpha <= 2^62
  // x <= (2^62 * alpha)^(3/2)
  //
  double max_x = pow(pow(2.0, 62.0) * alpha, 3.0 / 2.0);
  oss << (int128_t) max_x;
#else
  unused_param(alpha);
  oss << numeric_limits<int64_t>::max();
#endif

  return oss.str();
}

/// Get the time in seconds
double get_time()
{
  auto now = chrono::steady_clock::now();
  auto time = now.time_since_epoch();
  auto micro = chrono::duration_cast<chrono::microseconds>(time);
  return (double) micro.count() / 1e6;
}

int ideal_num_threads(int threads, int64_t sieve_limit, int64_t thread_threshold)
{
  thread_threshold = max((int64_t) 1, thread_threshold);
  threads = (int) min((int64_t) threads, sieve_limit / thread_threshold);
  threads = max(1, threads);
  return threads;
}

void set_alpha(double alpha)
{
  alpha_ = alpha;
}

void set_alpha_y(double alpha_y)
{
  alpha_y_ = alpha_y;
}

void set_alpha_z(double alpha_z)
{
  alpha_z_ = alpha_z;
}

/// Tuning factor used in the Lagarias-Miller-Odlyzko
/// and Deleglise-Rivat algorithms.
///
double get_alpha(maxint_t x, int64_t y)
{
  // y = x13 * alpha, thus alpha = y / x13
  double x13 = (double) iroot<3>(x);
  return (double) y / x13;
}

/// Tuning factor used in Xavier Gourdon's algorithm.
double get_alpha_y(maxint_t x, int64_t y)
{
  // y = x13 * alpha_y, thus alpha = y / x13
  double x13 = (double) iroot<3>(x);
  return (double) y / x13;
}

/// Tuning factor used in Xavier Gourdon's algorithm.
double get_alpha_z(int64_t y, int64_t z)
{
  // z = y * alpha_z, thus alpha_z = z / y
  return (double) z / y;
}

/// Get the Lagarias-Miller-Odlyzko alpha tuning factor.
/// alpha = a log(x)^2 + b log(x) + c
/// a, b and c have been determined empirically.
/// @see doc/alpha-factor-tuning.pdf
///
double get_alpha_lmo(maxint_t x)
{
  double alpha = alpha_;

  // use default alpha if no command-line alpha provided
  if (alpha < 1)
  {
    double a = 0.00156512;
    double b = -0.0261411;
    double c = 0.990948;
    double logx = log((double) x);

    alpha = a * pow(logx, 2) + b * logx + c;
  }

  return in_between(1, alpha, iroot<6>(x));
}

/// Get the Deleglise-Rivat alpha tuning factor.
/// alpha = a log(x)^3 + b log(x)^2 + c log(x) + d
/// a, b, c and d have been determined empirically.
/// @see doc/alpha-tuning-factor.pdf
///
double get_alpha_deleglise_rivat(maxint_t x)
{
  double alpha = alpha_;
  double x2 = (double) x;

  // use default alpha if no command-line alpha provided
  if (alpha < 1)
  {
    double a = 0.00033826;
    double b = 0.0018113;
    double c = -0.110407;
    double d = 1.3724;
    double logx = log(x2);

    alpha = a * pow(logx, 3) + b * pow(logx, 2) + c * logx + d;
  }

  return in_between(1, alpha, iroot<6>(x));
}

/// y = x^(1/3) * alpha_y, with alpha_y >= 1.
/// alpha_y is a tuning factor which should be determined
/// experimentally by running benchmarks.
///
/// Note that in Xavier Gourdon's paper alpha_y is named c
/// but we name it alpha_y since y = x^(1/3) * alpha_y
/// and the tuning factor in Tomás Oliveira e Silva's paper
/// is also named alpha.
///
double get_alpha_y_gourdon(maxint_t x)
{
  double alpha_y = alpha_y_;
  double x2 = (double) x;

  // use default alpha if no command-line alpha provided
  if (alpha_y < 1)
  {
    double a = 0.000497969;
    double b = -0.0153149;
    double c = 0.132236;
    double d = 0.787981;
    double logx = log(x2);

    alpha_y = a * pow(logx, 3) + b * pow(logx, 2) + c * logx + d;
  }

  return in_between(1, alpha_y, iroot<6>(x));
}

/// z = y * alpha_z, with alpha_z >= 1.
/// In Xavier Gourdon's paper the alpha_z tuning factor
/// is named d. alpha_z should be determined experimentally
/// by running benchmarks.
///
double get_alpha_z_gourdon(maxint_t x)
{
  double alpha_y = get_alpha_y_gourdon(x);
  double alpha_z = alpha_z_;

  if (alpha_z < 1)
  {
    // Xavier Gourdon's fastpix11.exe binary uses d = 2.4 but
    // according to my benchmarks alpha_z should grow very slowly
    // and be much smaller than alpha_y.
    double log_alpha_y = log(max(1.0, alpha_y));
    double loglog_alpha_y = log(max(1.0, log_alpha_y));
    alpha_z = 1 + loglog_alpha_y;
  }

  double x16 = (double) iroot<6>(x);
  double max_alpha = min(alpha_y * alpha_z, x16);
  return in_between(1, alpha_z, max_alpha);
}

/// x_star = max(x^(1/4), x / y^2)
///
/// After my implementation of Xavier Gourdon's algorithm worked for
/// the first time there were still many miscalculations mainly for
/// small numbers < 10^6. By debugging I found that most errors were
/// related to the Sigma formulas (Σ0 - Σ6) and the x_star variable
/// was responsible for most errors. For some unknown reason the
/// bounds from Xavier's paper (max(x^(1/4), x / y^2)) don't seem to
/// be enough. By trial and error I figured out a few more bounds that
/// fix all miscalculations in my implementation.
///
int64_t get_x_star_gourdon(maxint_t x, int64_t y)
{
  // For some unknown reason it is necessary
  // to round up (x / y^2). Without rounding up
  // there are many miscalculations below 2000
  // in my implementation.
  y = max(y, (int64_t) 1);
  maxint_t yy = (maxint_t) y * y;
  maxint_t x_div_yy = ceil_div(x, yy);

  int64_t x_star = (int64_t) max(iroot<4>(x), x_div_yy);
  int64_t sqrt_xy = (int64_t) isqrt(x / y);

  // x_star <= y
  // x_star <= (x / y)^(1/2)
  // The bounds above are missing in Xavier Gourdon's
  // paper. Without these bounds many of the 7 Sigma
  // formulas (Σ0 - Σ6) return incorrect results for
  // numbers below 10^6.
  x_star = min(x_star, y);
  x_star = min(x_star, sqrt_xy);
  x_star = max(x_star, (int64_t) 1);

  return x_star;
}

void set_num_threads(int threads)
{
#ifdef _OPENMP
  threads_ = in_between(1, threads, omp_get_max_threads());
#endif
  primesieve::set_num_threads(threads);
}

int get_num_threads()
{
#ifdef _OPENMP
  if (threads_)
    return threads_;
  else
    return max(1, omp_get_max_threads());
#else
  return 1;
#endif
}

void set_status_precision(int precision)
{
  status_precision_ = in_between(0, precision, 5);
}

int get_status_precision(maxint_t x)
{
  // use default precision when no command-line precision provided
  if (status_precision_ < 0)
  {
    if ((double) x >= 1e23)
      return 2;
    if ((double) x >= 1e21)
      return 1;
  }

  return max(status_precision_, 0);
}

maxint_t to_maxint(const string& expr)
{
  maxint_t n = calculator::eval<maxint_t>(expr);
  return n;
}

string primecount_version()
{
  return PRIMECOUNT_VERSION;
}

} // namespace
<commit_msg>Tune alpha_y factor<commit_after>///
/// @file  primecount.cpp
/// @brief Function definitions of primecount.hpp
///
/// Copyright (C) 2019 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount.hpp>
#include <primecount-internal.hpp>
#include <primesieve.hpp>
#include <calculator.hpp>
#include <int128_t.hpp>
#include <imath.hpp>

#include <algorithm>
#include <chrono>
#include <cmath>
#include <limits>
#include <sstream>
#include <string>
#include <stdint.h>

#ifdef _OPENMP
  #include <omp.h>
#endif

#ifdef HAVE_MPI

#include <mpi.h>

namespace primecount {

int mpi_num_procs()
{
  int procs;
  MPI_Comm_size(MPI_COMM_WORLD, &procs);
  return procs;
}

int mpi_proc_id()
{
  int proc_id;
  MPI_Comm_rank(MPI_COMM_WORLD, &proc_id);
  return proc_id;
}

int mpi_master_proc_id()
{
  return 0;
}

bool is_mpi_master_proc()
{
  return mpi_proc_id() == mpi_master_proc_id();
}

} // namespace

#endif

using namespace std;

namespace {

#ifdef _OPENMP
  int threads_ = 0;
#endif

// Below 10^7 LMO is faster than Deleglise-Rivat
const int lmo_threshold_ = 10000000;

int status_precision_ = -1;

// Tuning factor used in the Lagarias-Miller-Odlyzko
// and Deleglise-Rivat algorithms.
double alpha_ = -1;

// Tuning factor used in Xavier Gourdon's algorithm
double alpha_y_ = -1;

// Tuning factor used in Xavier Gourdon's algorithm
double alpha_z_ = -1;

}

namespace primecount {

int64_t pi(int64_t x)
{
  return pi(x, get_num_threads());
}

int64_t pi(int64_t x, int threads)
{
  if (x <= lmo_threshold_)
    return pi_lmo5(x);
  else
    return pi_deleglise_rivat(x, threads);
}

#ifdef HAVE_INT128_T

int128_t pi(int128_t x)
{
  return pi(x, get_num_threads());
}

int128_t pi(int128_t x, int threads)
{
  // use 64-bit if possible
  if (x <= numeric_limits<int64_t>::max())
    return pi((int64_t) x, threads);
  else
    return pi_deleglise_rivat(x, threads);
}

#endif

string pi(const string& x)
{
  return pi(x, get_num_threads());
}

string pi(const string& x, int threads)
{
  maxint_t pi_x = pi(to_maxint(x), threads);
  ostringstream oss;
  oss << pi_x;
  return oss.str();
}

int64_t pi_legendre(int64_t x)
{
  return pi_legendre(x, get_num_threads());
}

int64_t pi_lehmer(int64_t x)
{
  return pi_lehmer(x, get_num_threads());
}

int64_t pi_lmo(int64_t x)
{
  return pi_lmo(x, get_num_threads());
}

int64_t pi_lmo(int64_t x, int threads)
{
  return pi_lmo_parallel(x, threads);
}

int64_t pi_meissel(int64_t x)
{
  return pi_meissel(x, get_num_threads());
}

int64_t pi_deleglise_rivat(int64_t x)
{
  return pi_deleglise_rivat(x, get_num_threads());
}

int64_t pi_deleglise_rivat(int64_t x, int threads)
{
  return pi_deleglise_rivat_parallel1(x, threads);
}

#ifdef HAVE_INT128_T

int128_t pi_deleglise_rivat(int128_t x)
{
  return pi_deleglise_rivat(x, get_num_threads());
}

int128_t pi_deleglise_rivat(int128_t x, int threads)
{
  // use 64-bit if possible
  if (x <= numeric_limits<int64_t>::max())
    return pi_deleglise_rivat_parallel1((int64_t) x, threads);
  else
    return pi_deleglise_rivat_parallel2(x, threads);
}

#endif

int64_t nth_prime(int64_t n)
{
  return nth_prime(n, get_num_threads());
}

int64_t phi(int64_t x, int64_t a)
{
  return phi(x, a, get_num_threads());
}

/// Returns the largest integer supported by pi(x). The
/// return type is a string as get_max_x() can be a 128-bit
/// integer which is not supported by all compilers.
///
string get_max_x(double alpha)
{
  ostringstream oss;

#ifdef HAVE_INT128_T
  // primecount is limited by:
  // z <= 2^62, with z = x^(2/3) / alpha
  // x^(2/3) / alpha <= 2^62
  // x <= (2^62 * alpha)^(3/2)
  //
  double max_x = pow(pow(2.0, 62.0) * alpha, 3.0 / 2.0);
  oss << (int128_t) max_x;
#else
  unused_param(alpha);
  oss << numeric_limits<int64_t>::max();
#endif

  return oss.str();
}

/// Get the time in seconds
double get_time()
{
  auto now = chrono::steady_clock::now();
  auto time = now.time_since_epoch();
  auto micro = chrono::duration_cast<chrono::microseconds>(time);
  return (double) micro.count() / 1e6;
}

int ideal_num_threads(int threads, int64_t sieve_limit, int64_t thread_threshold)
{
  thread_threshold = max((int64_t) 1, thread_threshold);
  threads = (int) min((int64_t) threads, sieve_limit / thread_threshold);
  threads = max(1, threads);
  return threads;
}

void set_alpha(double alpha)
{
  alpha_ = alpha;
}

void set_alpha_y(double alpha_y)
{
  alpha_y_ = alpha_y;
}

void set_alpha_z(double alpha_z)
{
  alpha_z_ = alpha_z;
}

/// Tuning factor used in the Lagarias-Miller-Odlyzko
/// and Deleglise-Rivat algorithms.
///
double get_alpha(maxint_t x, int64_t y)
{
  // y = x13 * alpha, thus alpha = y / x13
  double x13 = (double) iroot<3>(x);
  return (double) y / x13;
}

/// Tuning factor used in Xavier Gourdon's algorithm.
double get_alpha_y(maxint_t x, int64_t y)
{
  // y = x13 * alpha_y, thus alpha = y / x13
  double x13 = (double) iroot<3>(x);
  return (double) y / x13;
}

/// Tuning factor used in Xavier Gourdon's algorithm.
double get_alpha_z(int64_t y, int64_t z)
{
  // z = y * alpha_z, thus alpha_z = z / y
  return (double) z / y;
}

/// Get the Lagarias-Miller-Odlyzko alpha tuning factor.
/// alpha = a log(x)^2 + b log(x) + c
/// a, b and c have been determined empirically.
/// @see doc/alpha-factor-tuning.pdf
///
double get_alpha_lmo(maxint_t x)
{
  double alpha = alpha_;

  // use default alpha if no command-line alpha provided
  if (alpha < 1)
  {
    double a = 0.00156512;
    double b = -0.0261411;
    double c = 0.990948;
    double logx = log((double) x);

    alpha = a * pow(logx, 2) + b * logx + c;
  }

  return in_between(1, alpha, iroot<6>(x));
}

/// Get the Deleglise-Rivat alpha tuning factor.
/// alpha = a log(x)^3 + b log(x)^2 + c log(x) + d
/// a, b, c and d have been determined empirically.
/// @see doc/alpha-tuning-factor.pdf
///
double get_alpha_deleglise_rivat(maxint_t x)
{
  double alpha = alpha_;
  double x2 = (double) x;

  // use default alpha if no command-line alpha provided
  if (alpha < 1)
  {
    double a = 0.00033826;
    double b = 0.0018113;
    double c = -0.110407;
    double d = 1.3724;
    double logx = log(x2);

    alpha = a * pow(logx, 3) + b * pow(logx, 2) + c * logx + d;
  }

  return in_between(1, alpha, iroot<6>(x));
}

/// y = x^(1/3) * alpha_y, with alpha_y >= 1.
/// alpha_y is a tuning factor which should be determined
/// experimentally by running benchmarks.
///
/// Note that in Xavier Gourdon's paper alpha_y is named c
/// but we name it alpha_y since y = x^(1/3) * alpha_y
/// and the tuning factor in Tomás Oliveira e Silva's paper
/// is also named alpha.
///
double get_alpha_y_gourdon(maxint_t x)
{
  double alpha_y = alpha_y_;
  double x2 = (double) x;

  // use default alpha if no command-line alpha provided
  if (alpha_y < 1)
  {
    double a = 0.000451957;
    double b = -0.0128774;
    double c = 0.0999006;
    double d = 0.860792;
    double logx = log(x2);

    alpha_y = a * pow(logx, 3) + b * pow(logx, 2) + c * logx + d;
  }

  return in_between(1, alpha_y, iroot<6>(x));
}

/// z = y * alpha_z, with alpha_z >= 1.
/// In Xavier Gourdon's paper the alpha_z tuning factor
/// is named d. alpha_z should be determined experimentally
/// by running benchmarks.
///
double get_alpha_z_gourdon(maxint_t x)
{
  double alpha_y = get_alpha_y_gourdon(x);
  double alpha_z = alpha_z_;

  if (alpha_z < 1)
  {
    // Xavier Gourdon's fastpix11.exe binary uses d = 2.4 but
    // according to my benchmarks alpha_z should grow very slowly
    // and be much smaller than alpha_y.
    double log_alpha_y = log(max(1.0, alpha_y));
    double loglog_alpha_y = log(max(1.0, log_alpha_y));
    alpha_z = 1 + loglog_alpha_y;
  }

  double x16 = (double) iroot<6>(x);
  double max_alpha = min(alpha_y * alpha_z, x16);
  return in_between(1, alpha_z, max_alpha);
}

/// x_star = max(x^(1/4), x / y^2)
///
/// After my implementation of Xavier Gourdon's algorithm worked for
/// the first time there were still many miscalculations mainly for
/// small numbers < 10^6. By debugging I found that most errors were
/// related to the Sigma formulas (Σ0 - Σ6) and the x_star variable
/// was responsible for most errors. For some unknown reason the
/// bounds from Xavier's paper (max(x^(1/4), x / y^2)) don't seem to
/// be enough. By trial and error I figured out a few more bounds that
/// fix all miscalculations in my implementation.
///
int64_t get_x_star_gourdon(maxint_t x, int64_t y)
{
  // For some unknown reason it is necessary
  // to round up (x / y^2). Without rounding up
  // there are many miscalculations below 2000
  // in my implementation.
  y = max(y, (int64_t) 1);
  maxint_t yy = (maxint_t) y * y;
  maxint_t x_div_yy = ceil_div(x, yy);

  int64_t x_star = (int64_t) max(iroot<4>(x), x_div_yy);
  int64_t sqrt_xy = (int64_t) isqrt(x / y);

  // x_star <= y
  // x_star <= (x / y)^(1/2)
  // The bounds above are missing in Xavier Gourdon's
  // paper. Without these bounds many of the 7 Sigma
  // formulas (Σ0 - Σ6) return incorrect results for
  // numbers below 10^6.
  x_star = min(x_star, y);
  x_star = min(x_star, sqrt_xy);
  x_star = max(x_star, (int64_t) 1);

  return x_star;
}

void set_num_threads(int threads)
{
#ifdef _OPENMP
  threads_ = in_between(1, threads, omp_get_max_threads());
#endif
  primesieve::set_num_threads(threads);
}

int get_num_threads()
{
#ifdef _OPENMP
  if (threads_)
    return threads_;
  else
    return max(1, omp_get_max_threads());
#else
  return 1;
#endif
}

void set_status_precision(int precision)
{
  status_precision_ = in_between(0, precision, 5);
}

int get_status_precision(maxint_t x)
{
  // use default precision when no command-line precision provided
  if (status_precision_ < 0)
  {
    if ((double) x >= 1e23)
      return 2;
    if ((double) x >= 1e21)
      return 1;
  }

  return max(status_precision_, 0);
}

maxint_t to_maxint(const string& expr)
{
  maxint_t n = calculator::eval<maxint_t>(expr);
  return n;
}

string primecount_version()
{
  return PRIMECOUNT_VERSION;
}

} // namespace
<|endoftext|>