cpplatex
 All Classes Functions Pages
latex.hpp
1 #ifndef CPPLATEX_LATEX_HPP
2 #define CPPLATEX_LATEX_HPP
3 
4 #include <cmath>
5 #include <stack>
6 #include <string>
7 #include <vector>
8 #include <sstream>
9 
10 namespace latex {
11 
12 constexpr const static char* oparen = "\\left(";
13 constexpr const static char* cparen = "\\right)";
14 constexpr const static char* obracket = "\\left[";
15 constexpr const static char* cbracket = "\\right]";
16 constexpr const static char* obrace = "\\left{";
17 constexpr const static char* cbrace = "\\right}";
18 
19 
20 namespace style {
21  //
22  // font style
23  //
24 
25  class None {
26  public:
27  constexpr const static char* open = "";
28  constexpr const static char* close = "";
29  };
30 
31  class Normal {
32  public:
33  constexpr const static char* open = "\\normal{";
34  constexpr const static char* close = "}";
35  };
36 
37  class Italic {
38  public:
39  constexpr const static char* open = "\\textit{";
40  constexpr const static char* close = "}";
41  };
42 
43  class Bold {
44  public:
45  constexpr const static char* open = "\\textbf{";
46  constexpr const static char* close = "}";
47  };
48 
49  class Underline {
50  public:
51  constexpr const static char* open = "\\underline{";
52  constexpr const static char* close = "}";
53  };
54 
55  //
56  // text sizing
57  //
58 
59  class Tiny {
60  public:
61  constexpr const static char* open = "\\tiny{";
62  constexpr const static char* close = "}";
63  };
64 
65  class Small {
66  public:
67  constexpr const static char* open = "\\small{";
68  constexpr const static char* close = "}";
69  };
70 
71  class Large {
72  public:
73  constexpr const static char* open = "\\large{";
74  constexpr const static char* close = "}";
75  };
76 
77  class Larger {
78  public:
79  constexpr const static char* open = "\\Large{";
80  constexpr const static char* close = "}";
81  };
82 
83  class Largest {
84  public:
85  constexpr const static char* open = "\\LARGE{";
86  constexpr const static char* close = "}";
87  };
88 
89  class Huge {
90  public:
91  constexpr const static char* open = "\\huge{";
92  constexpr const static char* close = "}";
93  };
94 
95  class Huger {
96  public:
97  constexpr const static char* open = "\\Huge{";
98  constexpr const static char* close = "}";
99  };
100 
101 }
102 
103 
104 
109 template <typename Style=style::None, typename... Rest>
110 class Text {
111 public:
112  std::string raw;
113 
114  Text(const char* t) : raw(std::string(t)) {}
115  Text(const std::string& t) : raw(t) {}
116 
117  std::string to_string() const {
118  std::stringstream ss;
119  build(ss);
120  return ss.str();
121  }
122  friend std::ostream& operator<<(std::ostream& os, const Text& t) {
123  t.build(os);
124  return os;
125  }
126 
127  void build(std::ostream& ss) const {
128  print_open(ss, Style::open, Rest::open...);
129 
130  ss << raw;
131 
132  print_close(ss, Style::close, Rest::close...);
133  }
134 
135 protected:
136  template <typename First, typename... T>
137  void print_open(std::ostream& ss, First f) const { ss << f; }
138 
139  template <typename First, typename... T>
140  void print_open(std::ostream& ss, First f, T... rest) const {
141  ss << f;
142  print_open(ss, rest...);
143  }
144 
145  template <typename First, typename... T>
146  void print_close(std::ostream& ss, First f) const { ss << f; }
147 
148  template <typename First, typename... T>
149  void print_close(std::ostream& ss, First f, T... rest) const {
150  print_close(ss, rest...);
151  ss << f;
152  }
153 };
154 
158 
166 
167 
168 //------------------------------------------------
169 //
170 // document generation
171 //
172 //------------------------------------------------
173 
174 namespace doc {
175  //
176  // ::to_string() enable_if "interface"
177  //
178  template <typename T> auto to_string_impl(int) -> decltype(std::declval<T>().to_string(), std::true_type{});
179  template <typename T> auto to_string_impl(...) -> std::false_type;
180  template <typename T> using can_stringify = decltype(to_string_impl<T>(0));
181 
182  //
183  // ::latex() enable_if "interface"
184  //
185  template <typename T> auto latex_impl(int) -> decltype(std::declval<T>().latex(), std::true_type{});
186  template <typename T> auto latex_impl(...) -> std::false_type;
187  template <typename T> using can_latex = decltype(latex_impl<T>(0));
188 
189 
190 
191  namespace listtypes {
193  class Ordered {
194  public:
195  constexpr const static char* open = "\\begin{enumerate}";
196  constexpr const static char* close = "\\end{enumerate}";
197  };
198 
200  class Unordered {
201  public:
202  constexpr const static char* open = "\\begin{itemize}";
203  constexpr const static char* close = "\\end{itemize}";
204  };
205  }
206 
211  template <typename Style=listtypes::Unordered>
212  class List {
213  protected:
214  enum class EntryType : std::uint8_t {
215  String,
216  Sublist,
217  };
218  std::vector<EntryType> ordering;
219 
220  public:
221  std::vector<std::string> items;
222  std::vector<List<Style>> sublists;
223 
224  //
225  // input
226  //
227 
228  List<Style>& operator<<(const char* val) { add(std::string(val)); return *this; }
229  List<Style>& operator<<(const std::string& val) { add(val); return *this; }
230 
231  List<Style>& operator<<(List<Style>& val) { add_sublist(val); return *this; }
232  List<Style>& operator<<(const List<Style>& val) { add_sublist(val); return *this; }
233 
234  template <
235  typename T,
236  typename = typename std::enable_if<
237  can_stringify<T>::value
238  and
239  (not std::is_same<T, List<listtypes::Ordered>>::value and not std::is_same<T, List<listtypes::Unordered>>::value)
240  >::type
241  >
242  List<Style>& operator<<(const T& val) { add(val.to_string()); return *this; }
243 
244  template <typename T>
245  typename std::enable_if<
246  can_latex<T>::value
247  , List<Style>&
248  >::type
249  operator<<(const T& val) { add(val.latex()); return *this; }
250 
251  void add(const std::string& str) {
252  items.push_back(str);
253  ordering.push_back(EntryType::String);
254  }
255 
256  void add_sublist(const List<Style>& list) {
257  sublists.push_back(list);
258  ordering.push_back(EntryType::Sublist);
259  }
260 
261  //
262  // output
263  //
264 
265  std::string to_string() const {
266  std::stringstream ss;
267  build(ss);
268  return ss.str();
269  }
270 
271  friend std::ostream& operator<<(std::ostream& os, List& list) { list.build(os); return os; }
272 
273  void build(std::ostream& os, std::size_t depth = 1) const {
274  auto itemit = items.begin();
275  auto subit = sublists.begin();
276 
277  std::stringstream prefix;
278  for (auto i = 1u; i < depth; ++i) { prefix << "\t"; } // start at 1 to make it one less than the constituent items
279 
280  os << prefix.str() << Style::open << std::endl;
281  for (auto& type : ordering) {
282  switch (type) {
283  case EntryType::String:
284  if (itemit != items.end()) {
285  os << prefix.str() << "\t" /* one more */ << "\\item " << *itemit << std::endl;
286  itemit++;
287  } else {
288  throw std::runtime_error("attempted to output a list item, but no items remaining.");
289  }
290  break;
291 
292  case EntryType::Sublist:
293  if (subit != sublists.end()) {
294  (*subit).build(os, depth+1);
295  subit++;
296  } else {
297  throw std::runtime_error("attempted to output a sublist item, but no sublists remaining.");
298  }
299  break;
300  }
301  }
302  os << prefix.str() << Style::close << std::endl;
303  }
304  };
305 
308 
309 
310  // TODO: "infinitely" nested subsections
317  class Subsection {
318  protected:
319  std::string title;
320  std::vector<std::string> content;
321 
322  public:
323  Subsection(const std::string& title) : title(title) {}
324 
325  Subsection& operator<<(const char* val) {content.push_back(std::string(val)); return *this;}
326  Subsection& operator<<(const std::string& val) {content.push_back(val); return *this;}
327 
328  template <typename T, typename std::enable_if<can_stringify<T>::value, bool>::type = 0>
329  Subsection& operator<<(const T& val) { content.push_back(val.to_string()); return *this; }
330 
331  template <typename T, typename std::enable_if<can_latex<T>::value, char>::type = 0>
332  Subsection& operator<<(const T& val) { content.push_back(val.latex()); return *this; }
333 
334  friend std::ostream& operator<<(std::ostream& os, const Subsection& sub) {
335  os << "\\subsection{" << sub.title << "}\n\n";
336 
337  for (auto& c : sub.content) {
338  os << c << "\n\n";
339  }
340 
341  return os;
342  }
343  };
344 
345 
355  class Section {
356  protected:
357  bool new_page;
358  std::string title;
359  std::vector<Subsection> subs;
360  std::vector<std::string> leading_content;
361 
362  public:
363  Section(const std::string& title, bool new_page = false) : new_page(new_page), title(title) {}
364 
365  Section& operator<<(const char* val) {leading_content.push_back(std::string(val)); return *this;}
366  Section& operator<<(const std::string& val) {leading_content.push_back(val); return *this;}
367  Section& operator<<(const Subsection& val) {subs.push_back(val); return *this;}
368 
369  template <typename T, typename = typename std::enable_if<can_stringify<T>::value>::type>
370  Section& operator<<(const T& val) { leading_content.push_back(val.to_string()); return *this; }
371 
372  void build(std::ostream& os) const {
373  if (new_page) {
374  os << "\n\n\\newpage\n\n";
375  }
376 
377  os << "\\section{" << title << "}\n\n";
378 
379  for (auto& c : leading_content) {
380  os << c << "\n\n";
381  }
382 
383  for (auto& s : subs) {
384  os << s << "\n\n";
385  }
386  }
387 
388 
389  std::string latex() const {
390  std::stringstream ss;
391  build(ss);
392  return ss.str();
393  }
394 
395  friend std::ostream& operator<<(std::ostream& os, const Section& sect) {
396  sect.build(os);
397  return os;
398  }
399 
400  void add_subsection(const Subsection& sub) { *this << sub; }
401  };
402 
403 
404  namespace doctypes {
407  class Article {
408  public:
409  constexpr const static char* header = "article";
410  constexpr const static bool can_toc = false;
411  constexpr const static bool can_subtitle = false;
412  };
413 
416  class Report {
417  public:
418  constexpr const static char* header = "report";
419  constexpr const static bool can_toc = true;
420  constexpr const static bool can_subtitle = true;
421  };
422 
425  class Book {
426  public:
427  constexpr const static char* header = "book";
428  constexpr const static bool can_toc = true;
429  constexpr const static bool can_subtitle = true;
430  };
431  }
432 
433 
434  // TODO: part ordering scheme like in List
446  template<typename DocType=doctypes::Article, std::uint8_t font_size = 12>
447  class Document {
448  public:
449  std::string title;
450  std::string subtitle;
451  bool use_toc;
452 
453  std::vector<std::string> imports;
454  std::vector<std::string> leading_contents;
455  std::vector<Section> sections;
456 
457  //
458  // functions
459  //
460 
461  Document(const std::string& title) : Document(title, "") {}
462  Document(const std::string& title, const std::string& subtitle)
463  : title(title), subtitle(subtitle), use_toc(DocType::can_toc)
464  {}
465 
467  Document& use(const std::string& import) { imports.push_back(import); return *this; }
468 
470  Document& with_leading_content(const std::string& content) { write_leading(content); return *this; }
471 
472 
474  Document& with_toc() { use_toc = DocType::can_toc; return *this; }
475 
477  void write_leading(const std::string& content) { leading_contents.push_back(content); }
478  void insert(const Section& sect) { sections.push_back(sect); }
479 
480  Document& operator<<(const char* val) {write_leading(std::string(val)); return *this;}
481  Document& operator<<(const std::string& val) {write_leading(val); return *this;}
482 
483  Document& operator<<(const Section& val) {
484  sections.push_back(val);
485  return *this;
486  }
487 
488 
489  friend std::ostream& operator<<(std::ostream& os, const Document& doc) { doc.build(os); return os; }
490 
492  std::string to_string() const {
493  std::stringstream ss;
494  build(ss);
495  return ss.str();
496  }
497 
499  void build(std::ostream& ss) const {
500  ss << "\\documentclass[" << (std::size_t)font_size << "pt]{" << DocType::header << "}\n"
501  << "\n";
502 
503  if (DocType::can_subtitle and subtitle.size()) {
504  ss << "\\title{" << title << " \\\\ " << subtitle << "}\n";
505  } else {
506  ss << "\\title{" << title << "}\n";
507  }
508 
509  ss << "\n\n";
510  for (auto& i : imports) {
511  ss << "\\usepackage{" << i << "}\n";
512  }
513  ss << "\n\n";
514 
515  ss << "\\begin{document}\n"
516  << "\n"
517  << "\\maketitle\n"
518  << "\n"
519  << (use_toc ? "\\tableofcontents\n\n\\newpage\n\n" : "")
520  ;
521 
522  ss << "\n\n";
523  for (auto& c : leading_contents) {
524  ss << c << "\n\n";
525  }
526 
527  for (auto& s : sections) {
528  ss << s << "\n\n";
529  }
530 
531  ss << "\\end{document}\n";
532  }
533  };
534 
535  using Article = Document<doctypes::Article>;
536  using Report = Document<doctypes::Report>;
537  using Book = Document<doctypes::Book>;
538 
539 } // doc namespace
540 
541 
542 //------------------------------------------------
543 //
544 // math/equation generation
545 //
546 //------------------------------------------------
547 
548 namespace math {
549  namespace style {
550  class None {
551  public:
552  constexpr const static char* open = "";
553  constexpr const static char* close = "";
554  };
555 
556  class Normal {
557  public:
558  constexpr const static char* open = "\\mathnormal{";
559  constexpr const static char* close = "}";
560  };
561 
562  class Italic {
563  public:
564  constexpr const static char* open = "\\mathit{";
565  constexpr const static char* close = "}";
566  };
567 
568  class Bold {
569  public:
570  constexpr const static char* open = "\\boldsymbol{";
571  constexpr const static char* close = "}";
572  };
573  }
574 
575  //
576  // ::solve() enable_if "interface"
577  //
578  template <typename T> auto solve_impl(int) -> decltype(std::declval<T>().solve(), std::true_type{});
579  template <typename T> auto solve_impl(...) -> std::false_type;
580  template <typename T> using can_solve = decltype(solve_impl<T>(0));
581 
582  template <typename T, typename = typename std::enable_if<can_solve<T>::value>::type>
583  auto reduce(T& val) { return val.solve(); }
584 
585  template <typename T>
586  typename std::enable_if<
587  not can_solve<T>::value || std::is_arithmetic<T>::value
588  , T
589  >::type
590  reduce(T& val) { return val; }
591 
592 
593  // unfortunate fwdecls
594  template <typename LHS, typename RHS> class Addition;
595  template <typename LHS, typename RHS> class Subtraction;
596  template <typename LHS, typename RHS> class Fraction;
597  template <typename LHS, typename RHS> class Multiplication;
598  template <typename LHS, typename RHS> class Power;
599  template <typename Val, typename Power> class Root;
600  template <typename Val, typename Base> class Log;
601  template <typename Val> class NaturalLog;
602 
603 
604 
609  template <typename T>
610  class Number {
611  protected:
612  T val;
613 
614  public:
615  using Self = Number<T>;
616 
617  Number(T val) : val(val) {}
618 
619  auto solve() { return reduce(val); }
620 
621  std::string latex() const {
622  std::stringstream ss;
623  ss << val;
624  return ss.str();
625  }
626 
627  friend std::ostream& operator<<(std::ostream& os, const Number& num) { os << num.latex(); return os; }
628 
629  Self operator-() { return Number<T>(0 - val); }
630 
631  template <typename Pow> Power<Self, Pow> pow(const Pow& power) { return Power<Self, Pow>(*this, power); }
632 
633  template <typename Base> Log<Self, Base> log(Base base) { return Log<Self, Base>(*this, base); }
634 
635  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
636 
637  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
638  };
639 
640  template <typename T>
641  auto make_num(const T& val) { return Number<T>(val); }
642 
643 
646  template <typename T>
647  class Paren {
648  public:
649  T enclosed;
650 
651  Paren(T enc) : enclosed(enc) {}
652 
653  auto solve() { return reduce(enclosed); }
654 
655  std::string latex() const {
656  std::stringstream ss;
657  ss << ::latex::oparen << enclosed << ::latex::cparen;
658  return ss.str();
659  }
660 
661  friend std::ostream& operator<<(std::ostream& os, const Paren& par) { os << par.latex(); return os; }
662  };
663 
664  template <typename T>
665  auto make_paren(const T& val) { return Paren<T>(val); }
666 
667 
668  //
669  // math operations
670  //
671 
672 
673  template <typename Numerator=double, typename Denominator=Numerator>
674  class Fraction {
675  protected:
676  Numerator num;
677  Denominator den;
678 
679  public:
680  using NumeratorType = Numerator;
681  using DenominatorType = Denominator;
682  using Self = Fraction<Numerator, Denominator>;
683 
684  Fraction(Numerator num, Denominator den) : num(num), den(den) {}
685 
686  auto solve() {
687  return reduce(num) / reduce(den);
688  }
689 
690  std::string latex() const {
691  std::stringstream ss;
692  ss << "\\frac{" << num << "}{" << den << "}";
693  return ss.str();
694  }
695 
696  friend std::ostream& operator<<(std::ostream& os, const Fraction& frac) { os << frac.latex(); return os; }
697 
698  template <typename T> Power<Self, T> pow(const T& power) { return Power<Self, T>(*this, power); }
699 
700  template <typename Base> Log<Self, Base> log(Base base) { return Log<Self, Base>(*this, base); }
701 
702  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
703 
704  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
705  };
706 
707  template <typename LHS, typename RHS>
708  auto make_fraction(const LHS& lhs, const RHS& rhs) { return Fraction<LHS, RHS>(lhs, rhs); }
709 
710 
711  template <typename LHS, typename RHS=LHS>
712  class Multiplication {
713  protected:
714  LHS lhs;
715  RHS rhs;
716 
717  public:
718  using LHSType = LHS;
719  using RHSType = RHS;
720  using Self = Multiplication<LHS, RHS>;
721 
722  Multiplication(LHS lhs, RHS rhs) : lhs(lhs), rhs(rhs) {}
723 
724  auto solve() { return reduce(lhs) * reduce(rhs); }
725  std::string latex() const {
726  std::stringstream ss;
727  ss << lhs << " * " << rhs;
728  return ss.str();
729  }
730 
731  friend std::ostream& operator<<(std::ostream& os, const Multiplication& mult) { os << mult.latex(); return os; }
732 
733  template <typename T> Power<Self, T> pow(const T& power) { return Power<Self, T>(*this, power); }
734 
735  template <typename Base> Log<Self, Base> log(Base base) { return Log<Self, Base>(*this, base); }
736 
737  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
738 
739  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
740  };
741 
742  template <typename LHS, typename RHS>
743  auto make_mult(const LHS& lhs, const RHS& rhs) { return Multiplication<LHS, RHS>(lhs, rhs); }
744 
745  template <typename LHS, typename RHS=LHS>
746  class Addition {
747  protected:
748  LHS lhs;
749  RHS rhs;
750 
751  public:
752  using LHSType = LHS;
753  using RHSType = RHS;
754  using Self = Addition<LHS, RHS>;
755 
756  Addition(LHS lhs, RHS rhs) : lhs(lhs), rhs(rhs) {}
757 
758  auto solve() { return reduce(lhs) + reduce(rhs); }
759  std::string latex() const {
760  std::stringstream ss;
761  ss << lhs << " + " << rhs;
762  return ss.str();
763  }
764 
765  friend std::ostream& operator<<(std::ostream& os, const Addition& add) { os << add.latex(); return os; }
766 
767  template <typename T> Power<Self, T> pow(const T& power) { return Power<Self, T>(*this, power); }
768 
769  template <typename Base> Log<Self, Base> log(Base base) { return Log<Self, Base>(*this, base); }
770 
771  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
772 
773  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
774  };
775 
776  template <typename LHS, typename RHS>
777  auto make_add(const LHS& lhs, const RHS& rhs) { return Addition<LHS, RHS>(lhs, rhs); }
778 
779  template <typename LHS, typename RHS=LHS>
780  class Subtraction {
781  protected:
782  LHS lhs;
783  RHS rhs;
784 
785  public:
786  using LHSType = LHS;
787  using RHSType = RHS;
788  using Self = Subtraction<LHS, RHS>;
789 
790  Subtraction(LHS lhs, RHS rhs) : lhs(lhs), rhs(rhs) {}
791 
792  auto solve() { return reduce(lhs) - reduce(rhs); }
793  std::string latex() const {
794  std::stringstream ss;
795  ss << lhs << " - " << rhs;
796  return ss.str();
797  }
798 
799  friend std::ostream& operator<<(std::ostream& os, const Subtraction& sub) { os << sub.latex(); return os; }
800 
801  template <typename T> Power<Self, T> pow(const T& power) { return Power<Self, T>(*this, power); }
802 
803  template <typename Base> Log<Self, Base> log(Base base) { return Log<Self, Base>(*this, base); }
804 
805  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
806 
807  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
808  };
809 
810  template <typename LHS, typename RHS>
811  auto make_sub(const LHS& lhs, const RHS& rhs) { return Subtraction<LHS, RHS>(lhs, rhs); }
812 
813 
814 
815  template <typename LHS, typename RHS=LHS>
816  class Power {
817  protected:
818  LHS lhs;
819  RHS rhs;
820 
821  public:
822  using LHSType = LHS;
823  using RHSType = RHS;
824  using Self = Power<LHS, RHS>;
825 
826  Power(LHS lhs, RHS rhs) : lhs(lhs), rhs(rhs) {}
827 
828  auto solve() { return ::pow(reduce(lhs), reduce(rhs)); }
829 
830  std::string latex() const {
831  std::stringstream ss;
832  ss << "{" << ::latex::oparen << lhs << ::latex::cparen << "}^{" << rhs << "}";
833  return ss.str();
834  }
835 
836  friend std::ostream& operator<<(std::ostream& os, const Power& expo) { os << expo.latex(); return os; }
837 
838  template <typename T> Power<Self, T> pow(const T& power) { return Power<Self, T>(*this, power); }
839 
840  template <typename Base> Log<Self, Base> log(Base base) { return Log<Self, Base>(*this, base); }
841 
842  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
843 
844  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
845  };
846 
847  template <typename LHS, typename RHS>
848  auto make_pow(const LHS& lhs, const RHS& rhs) { return Power<LHS, RHS>(lhs, rhs); }
849 
850 
851 
852  template <typename RHS>
853  class Exponent {
854  protected:
855  RHS rhs;
856 
857  public:
858  using RHSType = RHS;
859  using Self = Exponent<RHS>;
860 
861  Exponent(RHS rhs) : rhs(rhs) {}
862 
863  auto solve() { return ::exp(reduce(rhs)); }
864 
865  std::string latex() const {
866  std::stringstream ss;
867  // TODO: explicit \mathit{} ok to assume?
868  ss << "\\mathit{e}^{" << ::latex::oparen << rhs << ::latex::cparen << "}";
869  return ss.str();
870  }
871 
872  friend std::ostream& operator<<(std::ostream& os, const Exponent& expo) { os << expo.latex(); return os; }
873 
874  template <typename T> Power<Self, T> pow(const T& power) { return Power<Self, T>(*this, power); }
875 
876  template <typename Base> Log<Self, Base> log(Base base) { return Log<Self, Base>(*this, base); }
877 
878  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
879 
880  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
881  };
882 
883  template <typename RHS>
884  auto make_exp(const RHS& rhs) { return Exponent<RHS>(rhs); }
885 
886 
887 
888  template <typename Val, typename Pow=Val>
889  class Root {
890  protected:
891  Val val;
892  Pow base;
893 
894 
895  public:
896  using ValType = Val;
897  using PowType = Pow;
898  using Self = Root<Val, Pow>;
899 
900  Root(Val val, Pow base) : val(val), base(base) {}
901 
902  auto solve() { return ::pow(reduce(val), ((double)1.0)/reduce(base)); }
903 
904  std::string latex() const {
905  std::stringstream ss;
906  ss << '\\' << "sqrt";
907  if (reduce(base) != 2) { ss << "[" << base << "]"; }
908  ss << "{" << val << "}";
909  return ss.str();
910  }
911 
912  friend std::ostream& operator<<(std::ostream& os, const Root& r) { os << r.latex(); return os; }
913 
914  template <typename T> Power<Self, T> pow(const T& power) { return Power<Self, T>(*this, power); }
915 
916  template <typename InnerPower> Log<Self, InnerPower> log() { return Log<Self, InnerPower>(*this); }
917 
918  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
919 
920  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
921  };
922 
923  template <typename Val, typename Base=Val>
924  auto make_root(const Val& val, const Base& base) { return Root<Val, Base>(val, base); }
925 
926 
927 
928  template <typename Val, typename Base=Val>
929  class Log {
930  protected:
931  Val val;
932  Base base;
933 
934  public:
935  using ValType = Val;
936  using BaseType = Base;
937  using Self = Root<Val, Base>;
938 
939  Log(Val val, Base base) : val(val), base(base) {}
940 
941  auto solve() { return ::log(reduce(val)) / ::log(base); }
942  std::string latex() const {
943  std::stringstream ss;
944  ss << '\\' << "log_{" << base << "}{" << oparen << val << cparen << "}";
945  return ss.str();
946  }
947 
948  friend std::ostream& operator<<(std::ostream& os, const Log& loga) { os << loga.latex(); return os;}
949 
950  template <typename T> Power<Self, T> pow(const T& power) { return Power<Self, T>(*this, power); }
951 
952  template <typename InnerBase> Log<Self, Base> log() { return Log<Self, InnerBase>(*this); }
953 
954  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
955 
956  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
957  };
958 
959  template <typename Val, typename Base>
960  auto make_log(const Val& val, const Base& base) { return Log<Val, Base>(val, base); }
961 
962 
963 
964  template <typename Val>
965  class NaturalLog {
966  protected:
967  Val val;
968 
969  public:
970  using ValType = Val;
971  using Self = NaturalLog<Val>;
972 
973  NaturalLog(Val val) : val(val) {}
974 
975  auto solve() { return ::log(reduce(val)); }
976  std::string latex() const {
977  std::stringstream ss;
978  ss << "\\ln{" << oparen << val << cparen << "}";
979  return ss.str();
980  }
981 
982  friend std::ostream& operator<<(std::ostream& os, const NaturalLog& loga) { os << loga.latex(); return os;}
983 
984  template <typename T> Power<Self, T> pow(const T& power) { return Power<Self, T>(*this, power); }
985 
986  template <typename Base> Log<Self, Base> log(Base base) { return Log<Self, Base>(*this, base); }
987 
988  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
989 
990  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
991  };
992 
993  template <typename Val>
994  auto make_ln(const Val& val) { return NaturalLog<Val>(val); }
995 
996 
997  //
998  // composed equations
999  //
1000 
1001 
1002  template<typename LHS, typename RHS>
1003  class Equation {
1004  protected:
1005  LHS lhs;
1006  RHS rhs;
1007  std::string label;
1008 
1009  constexpr const static char* open_context = "\\begin{equation}";
1010  constexpr const static char* close_context = "\\end{equation}";
1011 
1012  public:
1013  using LHSType = LHS;
1014  using RHSType = RHS;
1015 
1016  Equation(LHS lhs, RHS rhs) : lhs(lhs), rhs(rhs) {}
1017 
1018  Equation(const std::string& label, LHS lhs, RHS rhs) : lhs(lhs), rhs(rhs), label(label) {}
1019 
1020  void insert_label(std::ostream& os) const {
1021  if (label.size()) {
1022  os << "\\label{eq:" << label << "}\n";
1023  } else {
1024  os << "\n";
1025  }
1026  }
1027 
1033  auto solve() { return rhs.solve(); }
1034 
1037  std::string latex() const {
1038  std::stringstream ss;
1039  ss << open_context;
1040 
1041  insert_label(ss);
1042  ss << lhs << " = " << rhs << "\n";
1043 
1044  ss << close_context << "\n";
1045  return ss.str();
1046  }
1047 
1048  friend std::ostream& operator<<(std::ostream& os, const Equation& eq) { os << eq.latex(); return os; }
1049  };
1050 
1051  template <typename LHS, typename RHS>
1052  auto make_eqn(const LHS& lhs, const RHS& rhs) { return Equation<LHS, RHS>(lhs, rhs); }
1053 
1054 
1055  template <typename LHS, typename... Steps>
1057  protected:
1058  std::string eqn;
1059  // TODO: label
1060 
1061  constexpr const static char* open_context = "\\begin{equation}";
1062  constexpr const static char* close_context = "\\end{equation}";
1063  constexpr const static char* split_eq = " & = ";
1064 
1065  template <typename First, typename... T>
1066  void print_steps(std::ostream& os, First& f, T... rest) {
1067  os << split_eq << f << "\\\\\n";
1068  print_steps(os, rest...);
1069  }
1070 
1071  template <typename First, typename... T>
1072  void print_steps(std::ostream& os, First& f) {
1073  os << split_eq << f << "\n";
1074  }
1075 
1076  public:
1077  AlignedEquation(const LHS& lhs, Steps... steps) {
1078  std::stringstream ss;
1079  ss << open_context << "\n";
1080 
1081  ss << "\\begin{split}\n";
1082 
1083  ss << lhs;
1084  print_steps(ss, steps...);
1085 
1086  ss << "\\end{split}\n";
1087  ss << close_context << "\n";
1088 
1089  eqn = ss.str();
1090  }
1091 
1092  std::string latex() const { return eqn; }
1093 
1094  friend std::ostream& operator<<(std::ostream& os, const AlignedEquation& eq) { os << eq.latex(); return os;}
1095  };
1096 
1097  template <typename LHS, typename... Steps>
1098  auto make_aligned_eqn(const LHS& lhs, const Steps... steps) { return AlignedEquation<LHS, Steps...>(lhs, steps...); }
1099 
1100 
1101  // TODO: reference other equation(s)' label
1102 
1103 
1104  //
1105  // text
1106  //
1107 
1108  template <typename T=std::string>
1109  class Variable {
1110  public:
1111  T name;
1112 
1113  Variable(const T& name) : name(name) {}
1114 
1115  void solve() {
1116  std::stringstream ss;
1117  ss << "attempted to solve an equation containing variable '" << name << "'\n";
1118  throw std::runtime_error(ss.str());
1119  }
1120 
1121  std::string latex() const {
1122  std::stringstream ss;
1123  ss << name;
1124  return ss.str();
1125  }
1126 
1127  friend std::ostream& operator<<(std::ostream& os, const Variable& var) {
1128  os << var.latex();
1129  return os;
1130  }
1131  };
1132 
1133  template <typename T, typename StrType=std::string>
1135  protected:
1136  bool use_name;
1137 
1138  public:
1139  T val;
1140  StrType name;
1141 
1143 
1144  ValuedVariable(const T& val, const StrType& name, bool use_name=true)
1145  : use_name(use_name), val(val), name(name)
1146  {}
1147 
1148  auto solve() { return reduce(val); }
1149 
1150  std::string latex() const {
1151  std::stringstream ss;
1152  if (use_name) {
1153  ss << name;
1154  } else {
1155  ss << val;
1156  }
1157  return ss.str();
1158  }
1159 
1160  friend std::ostream& operator<<(std::ostream& os, const ValuedVariable& var) {
1161  os << var.latex();
1162  return os;
1163  }
1164 
1165  template <typename U> Power<Self, U> pow(const U& power) { return Power<Self, U>(*this, power); }
1166 
1167  template <typename Base> Log<Self, Base> log(Base base) { return Log<Self, Base>(*this, base); }
1168 
1169  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
1170 
1171  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
1172  };
1173 
1174  template <typename Upper, typename Lower=Upper>
1176  public:
1177  Upper upper;
1178  Lower lower;
1179 
1180  SubscriptedVariable(const Upper& up, const Lower& low) : upper(up), lower(low) {}
1181 
1182  void solve() {
1183  std::stringstream ss;
1184  ss << "attempted to solve an equation containing variable '" << upper << "_" << lower << "'\n";
1185  throw std::runtime_error(ss.str());
1186  }
1187 
1188  std::string latex() const {
1189  std::stringstream ss;
1190  ss << upper << "_{" << lower << "}";
1191  return ss.str();
1192  }
1193 
1194  friend std::ostream& operator<<(std::ostream& os, const SubscriptedVariable& var) {
1195  os << var.latex();
1196  return os;
1197  }
1198  };
1199 
1200 
1201 
1202  template <typename Val>
1203  class Sin {
1204  protected:
1205  Val val;
1206 
1207  public:
1208  using ValType = Val;
1209  using Self = Sin<Val>;
1210 
1211  Sin(Val val) : val(val) {}
1212 
1213  auto solve() { return ::sin(reduce(val)); }
1214  std::string latex() const {
1215  std::stringstream ss;
1216  ss << "\\sin{" << latex::oparen << val << latex::cparen << "}";
1217  return ss.str();
1218  }
1219 
1220  friend std::ostream& operator<<(std::ostream& os, const Sin& s) { os << s.latex(); return os;}
1221 
1222  template <typename T> Power<Self, T> pow(const T& power) { return Power<Self, T>(*this, power); }
1223 
1224  template <typename Base> Log<Self, Base> log(Base base) { return Log<Self, Base>(*this, base); }
1225 
1226  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
1227 
1228  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
1229  };
1230 
1231  template <typename Val>
1232  auto make_sin(const Val& val) { return Sin<Val>(val); }
1233 
1234 
1235 
1236  template <typename Val>
1237  class Cos {
1238  protected:
1239  Val val;
1240 
1241  public:
1242  using ValType = Val;
1243  using Self = Cos<Val>;
1244 
1245  Cos(Val val) : val(val) {}
1246 
1247  auto solve() { return ::sin(reduce(val)); }
1248  std::string latex() const {
1249  std::stringstream ss;
1250  ss << "\\cos{" << latex::oparen << val << latex::cparen << "}";
1251  return ss.str();
1252  }
1253 
1254  friend std::ostream& operator<<(std::ostream& os, const Cos& s) { os << s.latex(); return os;}
1255 
1256  template <typename T> Power<Self, T> pow(const T& power) { return Power<Self, T>(*this, power); }
1257 
1258  template <typename Base> Log<Self, Base> log(Base base) { return Log<Self, Base>(*this, base); }
1259 
1260  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
1261 
1262  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
1263  };
1264 
1265  template <typename Val>
1266  auto make_cos(const Val& val) { return Cos<Val>(val); }
1267 
1268 
1269 
1270  template <typename Val>
1271  class Tan {
1272  protected:
1273  Val val;
1274 
1275  public:
1276  using ValType = Val;
1277  using Self = Tan<Val>;
1278 
1279  Tan(Val val) : val(val) {}
1280 
1281  auto solve() { return ::sin(reduce(val)); }
1282  std::string latex() const {
1283  std::stringstream ss;
1284  ss << "\\tan{" << latex::oparen << val << latex::cparen << "}";
1285  return ss.str();
1286  }
1287 
1288  friend std::ostream& operator<<(std::ostream& os, const Tan& s) { os << s.latex(); return os;}
1289 
1290  template <typename T> Power<Self, T> pow(const T& power) { return Power<Self, T>(*this, power); }
1291 
1292  template <typename Base> Log<Self, Base> log(Base base) { return Log<Self, Base>(*this, base); }
1293 
1294  NaturalLog<Self> ln() { return NaturalLog<Self>(*this); }
1295 
1296  Root<Self, int> sqrt() { return Root<Self, int>(*this, 2); }
1297  };
1298 
1299  template <typename Val>
1300  auto make_tan(const Val& val) { return Tan<Val>(val); }
1301 
1302 
1303 
1304 } // math namespace
1305 
1306 
1307 
1308 } // latex namespace
1309 
1310 
1311 //
1312 // global operators for math
1313 //
1314 
1315 template <
1316  typename T,
1317  typename L,
1318  typename = typename std::enable_if<
1319  latex::math::can_solve<T>::value ||
1320  latex::math::can_solve<L>::value
1321  >::type
1322 >
1323 latex::math::Addition<T, L> operator+(const T& lhs, L rhs) { return latex::math::Addition<T, L>(lhs, rhs); }
1324 
1325 //template <typename T, typename L, typename = typename std::enable_if<latex::math::can_solve<L>::value>::type>
1326 
1327 template <
1328  typename T,
1329  typename L,
1330  typename = typename std::enable_if<
1331  latex::math::can_solve<T>::value ||
1332  latex::math::can_solve<L>::value
1333  >::type
1334 >
1335 latex::math::Subtraction<T, L> operator-(const T& lhs, L rhs) { return latex::math::Subtraction<T, L>(lhs, rhs); }
1336 
1337 //template <typename T, typename L, typename = typename std::enable_if<latex::math::can_solve<L>::value>::type>
1338 
1339 template <
1340  typename T,
1341  typename L,
1342  typename = typename std::enable_if<
1343  latex::math::can_solve<T>::value ||
1344  latex::math::can_solve<L>::value
1345  >::type
1346 >
1347 latex::math::Multiplication<T, L> operator*(const T& lhs, L rhs) { return latex::math::Multiplication<T, L>(lhs, rhs); }
1348 
1349 //template <typename T, typename L, typename = typename std::enable_if<latex::math::can_solve<L>::value>::type>
1350 template <
1351  typename T,
1352  typename L,
1353  typename = typename std::enable_if<
1354  latex::math::can_solve<T>::value ||
1355  latex::math::can_solve<L>::value
1356  >::type
1357 >
1358 latex::math::Fraction<T, L> operator/(const T& lhs, L rhs) { return latex::math::Fraction<T, L>(lhs, rhs); }
1359 
1360 #endif