Program Listing for File latex.hpp

Return to documentation for file (SeQuant/core/latex.hpp)

//
// Created by Eduard Valeyev on 3/30/18.
//

#ifndef SEQUANT_CORE_LATEX_HPP
#define SEQUANT_CORE_LATEX_HPP

#include <SeQuant/core/meta.hpp>
#include <SeQuant/core/wstring.hpp>

#include <cmath>
#include <complex>
#include <limits>
#include <string>
#include <string_view>
#include <type_traits>

namespace sequant {

template <typename T>
std::enable_if_t<meta::has_memfn_to_latex_v<std::decay_t<T>>, std::wstring>
to_latex(T&& t) {
  return t.to_latex();
}

template <typename T>
std::enable_if_t<std::is_arithmetic_v<std::decay_t<T>> &&
                     !std::is_floating_point_v<std::decay_t<T>>,
                 std::wstring>
to_latex(T&& t) {
  std::wstring result = L"{";
  using ::sequant::to_wstring;
  result += to_wstring(t) + L"}";
  return result;
}

template <typename T>
std::enable_if_t<std::is_arithmetic_v<std::decay_t<T>> &&
                     std::is_floating_point_v<std::decay_t<T>>,
                 std::wstring>
to_latex(T&& t) {
  using Real = std::decay_t<T>;
  static const auto eps_sqrt = std::sqrt(std::numeric_limits<Real>::epsilon());

  std::wstring result = L"{";
  using ::sequant::to_wstring;

  const long round_t = std::lround(t);
  if (std::abs(round_t - t) < eps_sqrt)  // exact integer
    result += to_wstring(round_t) + L"}";
  else {  // TODO detect rationals
    const auto inv_t = Real(1) / t;
    const long round_inv_t = std::lround(inv_t);
    if (std::abs(round_inv_t - inv_t) < eps_sqrt) {  // exact inverse of an
                                                     // integer
      long denom = round_inv_t;
      using namespace std::literals;
      result += (std::signbit(t) ? L"-"s : L""s) + L"\\frac{1}{"s +
                std::to_wstring(std::abs(denom)) + L"}}"s;
    } else
      result += to_wstring(t) + L"}";
  }
  return result;
}

template <typename T>
std::wstring to_latex(const std::complex<T>& t) {
  std::wstring result = L"{";
  result += to_latex(t.real());
  if (t.imag() > 0) {
    result += L" + i " + to_latex(t.imag());
  } else if (t.imag() < 0)
    result += L" - i " + to_latex(-t.imag());
  result += L"}";
  return result;
}

namespace detail {

template <typename Char, typename Traits, typename Alloc>
std::basic_string<Char, Traits, Alloc> greek_characters_to_latex_impl(
    std::basic_string_view<Char, Traits> str);

}  // namespace detail

// chang-format off
// chang-format on
template <typename Char, typename Traits>
std::basic_string<Char, Traits> greek_characters_to_latex(
    const std::basic_string_view<Char, Traits>& str) {
  return detail::greek_characters_to_latex_impl<Char, Traits,
                                                std::allocator<Char>>(str);
}

template <typename Char, typename Traits, typename Alloc>
std::basic_string<Char, Traits, Alloc> greek_characters_to_latex(
    const std::basic_string<Char, Traits, Alloc>& str) {
  return detail::greek_characters_to_latex_impl<Char, Traits, Alloc>(str);
}

namespace detail {

template <typename Char, typename Traits, typename Alloc>
std::basic_string<Char, Traits, Alloc> diactrics_to_latex_impl(
    std::basic_string_view<Char, Traits> str);

}  // namespace detail

// chang-format off
// chang-format on
template <typename Char, typename Traits>
std::basic_string<Char, Traits> diactrics_to_latex(
    const std::basic_string_view<Char, Traits>& str) {
  return detail::diactrics_to_latex_impl<Char, Traits, std::allocator<Char>>(
      str);
}

template <typename Char, typename Traits, typename Alloc>
std::basic_string<Char, Traits, Alloc> diactrics_to_latex(
    const std::basic_string<Char, Traits, Alloc>& str) {
  return detail::diactrics_to_latex_impl<Char, Traits, Alloc>(str);
}

// chang-format off
// chang-format on
template <typename Char, typename Traits>
std::basic_string<Char, Traits> utf_to_latex(
    const std::basic_string_view<Char, Traits>& str) {
  // replace diacritics first since it relies on wide character structure
  auto tmp = diactrics_to_latex(str);
  return greek_characters_to_latex(tmp);
}

template <typename Char, typename Traits, typename Alloc>
std::basic_string<Char, Traits, Alloc> utf_to_latex(
    const std::basic_string<Char, Traits, Alloc>& str) {
  auto tmp = diactrics_to_latex(str);
  return greek_characters_to_latex(tmp);
}

}  // namespace sequant

#endif  // SEQUANT_CORE_LATEX_HPP