Virasoro algebra

Virasoro algebra is the central extension of a Lie algebra with wide applications in the two-dimensional conformal field theory. Its generators \(L_n, n \in \mathbb{Z}\) satisfy commutation relations

\[[L_m, L_n] = (m - n) L_{m+n} + c(m^3 - m) \delta_{m, -n},\]

where \(c\) is the central charge commuting with all generators. It was shown in [FNZ88] that the Virasoro algebra can be constructed out of just two generators \(L_3\) and \(L_{-2}\) using the following recurrence relations,

\[\begin{split}\begin{align} L_1 &= \frac{1}{5}[L_3, L_{-2}],\\ L_{-1} &= \frac{1}{3}[L_1, L_{-2}],\\ L_2 &= \frac{1}{4}[L_3, L_{-1}],\\ L_0 &= \frac{1}{2}[L_1, L_{-1}],\\ L_{n+1} &= \frac{1}{n-1}[L_n, L_1] \text{ for } n>2,\\ L_{-n-1} &= \frac{1}{1-n}[L_{-n}, L_{-1}] \text{ for } n>1. \end{align}\end{split}\]

In the example below, we show how to implement the Virasoro algebra in libcommute’s framework and use it to verify the recurrence relations stated above.

  1#include <iostream>
  2#include <memory>
  3#include <tuple>
  4
  5#include <libcommute/libcommute.hpp>
  6
  7namespace libcommute {
  8
  9// Define a new generator type by deriving from the abstract base class
 10// 'libcommute::generator<IndexTypes...>'. Generators of the Virasoro algebra
 11// L_n carry one integer index 'n'.
 12// Canonical order of generators in a monomial L_n * L_m * L_k * ... is such
 13// that n < m < k < ...
 14class generator_virasoro : public generator<int> {
 15
 16  using base = generator<int>;
 17  using linear_function_t = typename base::linear_function_t;
 18
 19  // For the sake of simplicity, we fix the central charge once and for all.
 20  static constexpr double central_charge = 2.0;
 21
 22public:
 23  // This function must return a unique algebra ID shared by all generators
 24  // of a particular algebra.
 25  int algebra_id() const override {
 26    // Use the lowest algebra ID available to user-defined algebras
 27    return min_user_defined_algebra_id;
 28  }
 29
 30  // Construct generator with a given index 'n'
 31  explicit generator_virasoro(int n) : base(n) {}
 32  // Standard constructors, assignments and destructor
 33  generator_virasoro(generator_virasoro const&) = default;
 34  generator_virasoro(generator_virasoro&&) noexcept = default;
 35  generator_virasoro& operator=(generator_virasoro const&) = default;
 36  generator_virasoro& operator=(generator_virasoro&&) noexcept = default;
 37  ~generator_virasoro() override = default;
 38
 39  // Virtual copy-constructor: Make a smart pointer managing
 40  // a copy of this generator
 41  std::unique_ptr<base> clone() const override {
 42    return make_unique<generator_virasoro>(*this);
 43  }
 44
 45  // Given a product L_m * L_n with m > n, transform it to the canonically
 46  // ordered form L_n * L_m plus some linear function of generators.
 47  // For the Virasoro algebra the transformation is
 48  //
 49  // L_m * L_n -> L_n * L_m + (m-n)*L_{m+n} + c(m^3 - m)\delta(m,-n)
 50  //
 51  // L_m will be passed to swap_with() as *this, i.e. L_m.swap_with(L_n, f).
 52  double swap_with(base const& L_n, linear_function_t& f) const override {
 53    // Ensure that L_m > L_n, or equivalently m > n.
 54    assert(*this > L_n);
 55
 56    auto const& L_n_ = dynamic_cast<generator_virasoro const&>(L_n);
 57
 58    // Extract indices from L_m and L_n
 59    int m = std::get<0>(base::indices());
 60    int n = std::get<0>(L_n_.indices());
 61
 62    // Write linear terms of the transformed expressions into 'f'
 63    f.set(m == -n ? (central_charge * (m * m * m - m)) : 0, // Constant term
 64          make_unique<generator_virasoro>(m + n),           // L_{m+n}
 65          m - n // Coefficient in front of L_{m+n}
 66    );
 67
 68    // Return coefficient in front of L_n * L_m in the transformed expression
 69    return 1;
 70  }
 71
 72  // Given a product L_m * L_n with m <= n, optionally transform it to
 73  // some linear function of generators. For the Virasoro algebra such a
 74  // transformation exists for L_m = L_n,
 75  //
 76  // L_m * L_n -> 0
 77  //
 78  // L_m will be passed to simplify_prod() as *this,
 79  // i.e. L_m.simplify_prod(L_n, f).
 80  bool simplify_prod(base const& L_n, linear_function_t& f) const override {
 81    // Ensure that L_m <= L_n, or equivalently m <= n.
 82    assert(!(*this > L_n));
 83
 84    if(*this == L_n) {
 85      // The transformed product is identically zero
 86      f.set(0);
 87      return true;
 88    } else
 89      return false; // No suitable transformation can be applied
 90  }
 91
 92  // Hermitian conjugate: (L_n)^\dagger = L_{-n}
 93  void conj(linear_function_t& f) const override {
 94    int conj_n = -std::get<0>(base::indices());
 95    f.set(0, make_unique<generator_virasoro>(conj_n), 1);
 96  }
 97
 98  // Print L_n to stream
 99  std::ostream& print(std::ostream& os) const override {
100    int n = std::get<0>(base::indices());
101    return os << "L(" << n << ")";
102  }
103};
104
105// Convenience factory function to create expressions made of one
106// monomial L_n.
107expression<double, int> L(int n) {
108  using ret_t = expression<double, int>;
109  return ret_t(1.0, ret_t::monomial_t(generator_virasoro(n)));
110}
111
112} // namespace libcommute
113
114using namespace libcommute;
115
116int main() {
117
118  // Check that L(0) is Hermitian and (L_n)^\dagger = L_{-n}
119  std::cout << "conj(L(0)) = " << conj(L(0)) << '\n';
120  std::cout << "conj(L(1)) = " << conj(L(1)) << '\n';
121
122  // Check that L(n)^2 = 0 for a few n
123  std::cout << "L(0) * L(0) = " << L(0) * L(0) << '\n';
124  std::cout << "L(1) * L(1) = " << L(1) * L(1) << '\n';
125  std::cout << "L(-1) * L(-1) = " << L(-1) * L(-1) << '\n';
126
127  // Check recurrence relations from Eq. (5)
128  std::cout << "L_1 - (1/5)[L_3, L_{-2}] = "
129            << (L(1) - (1.0 / 5) * (L(3) * L(-2) - L(-2) * L(3))) << '\n';
130  std::cout << "L_{-1} - (1/3)[L_1, L_{-2}] = "
131            << (L(-1) - (1.0 / 3) * (L(1) * L(-2) - L(-2) * L(1))) << '\n';
132  std::cout << "L_2 - (1/4)[L_3, L_{-1}] = "
133            << (L(2) - (1.0 / 4) * (L(3) * L(-1) - L(-1) * L(3))) << '\n';
134  std::cout << "L_0 - (1/2)[L_1, L_{-1}] = "
135            << (L(0) - (1.0 / 2) * (L(1) * L(-1) - L(-1) * L(1))) << '\n';
136
137  // Check recurrence relation Eq. (6) for some higher positive n
138  for(int n = 3; n < 10; ++n) {
139    std::cout << "L_" << (n + 1) << " - (1/" << (n - 1) << ")"
140              << "[L_" << n << ", L_1] = "
141              << (L(n + 1) - (1.0 / (n - 1)) * (L(n) * L(1) - L(1) * L(n)))
142              << '\n';
143  }
144  // Check recurrence relation Eq. (7) for some higher negative n
145  for(int n = 2; n < 10; ++n) {
146    std::cout << "L_" << (-n - 1) << " - (1/(" << (1 - n) << "))"
147              << "[L_" << -n << ", L_{-1}] = "
148              << (L(-n - 1) - (1.0 / (1 - n)) * (L(-n) * L(-1) - L(-1) * L(-n)))
149              << '\n';
150  }
151
152  return 0;
153}
[FNZ88]

“A presentation for the Virasoro and super-Virasoro algebras”, D. B. Fairlie, J. Nuyts and C. K. Zachos , Commun. Math. Phys. 117, pp. 595–614 (1988), https://doi.org/10.1007/BF01218387