# Path: drudge/fock.py
# class RestrictedPartHoleDrudge(SpinOneHalfPartHoleDrudge):
#     """Drudge for the particle-hole problems on restricted reference.
# 
#     Similar to :py:class:`SpinOneHalfPartHoldDrudge`, this drudge deals with
#     particle-hole problems with explicit one-half spin.  However, here the spin
#     quantum number is summed symbolically.  This gives **much** faster
#     derivations for theories based on restricted reference, but offers less
#     flexibility.
# 
#     .. attribute:: spin_range
# 
#         The symbolic range for spin values.
# 
#     .. attribute:: spin_dumms
# 
#         The dummies for the spin quantum number.
# 
#     .. attribute:: e_
# 
#         Tensor definition for the unitary group generators.  It should be
#         indexed with the upper and lower indices to the :math:`E` operator.  It
#         is also registered in the name archive as ``e_``.
# 
#     """
# 
#     def __init__(
#             self, *args,
#             spin_range=Range(r'\uparrow\downarrow', 0, 2),
#             spin_dumms=tuple(Symbol('sigma{}'.format(i)) for i in range(50)),
#             **kwargs
#     ):
#         """Initialize the restricted particle-hole drudge."""
# 
#         super().__init__(
#             *args, spin=(spin_range, spin_dumms), **kwargs
#         )
#         self.add_resolver({
#             UP: spin_range,
#             DOWN: spin_range
#         })
# 
#         self.spin_range = spin_range
#         self.spin_dumms = self.dumms.value[spin_range]
# 
#         sigma = self.dumms.value[spin_range][0]
#         p = Symbol('p')
#         q = Symbol('q')
#         self.e_ = TensorDef(Vec('E'), (p, q), self.sum(
#             (sigma, spin_range), self.cr[p, sigma] * self.an[q, sigma]
#         ))
#         self.set_name(e_=self.e_)
# 
# Path: drudge/utils.py
# class Stopwatch:
#     """Utility class for printing timing information.
# 
#     This class helps to timing the progression of batch jobs.  It is capable of
#     getting and formatting the elapsed wall time between consecutive steps.
#     Note that the timing here might not be accurate to one second.
# 
#     """
# 
#     def __init__(self, print_cb=print):
#         """Initialize the stopwatch.
# 
#         Parameters
#         ----------
# 
#         print_cb
#             The function will be called with the formatted time-stamp.  By
#             default, it will just be written to stdout.
# 
#         """
#         self._print = print_cb
#         self.tick(total=True)
# 
#     def tick(self, total=False):
#         """Reset the timer.
# 
#         Parameters
#         ----------
# 
#         total
#             If the total beginning time is going to be reset as well.
# 
#         """
#         self._prev = time.time()
#         if total:
#             self._begin = self._prev
# 
#     def tock(self, label, tensor=None):
#         """Make a timestamp.
# 
#         The formatted timestamp will be given to the callback of the current
#         stamper.  The wall time elapsed since the last :py:meth:`tick` will be
#         printed.
# 
#         Parameters
#         ----------
# 
#         label
#             The label for the current step.
# 
#         tensor
#             When a tensor is given, it will be cached, counted its number of
#             terms.  This method has this parameter since if no reduction is
#             performed on the tensor, it might remain unevaluated inside Spark
#             and give misleading timing information.
# 
#         """
# 
#         if tensor is not None:
#             tensor.cache()
#             n_terms = '{} terms, '.format(tensor.n_terms)
#         else:
#             n_terms = ''
# 
#         now = time.time()
#         elapse = now - self._prev
#         self._prev = now
# 
#         self._print(
#             '{} done, {}wall time: {:.2f} s'.format(label, n_terms, elapse)
#         )
# 
#     def tock_total(self):
#         """Make a timestamp for the total time.
# 
#         The total time will be the time elapsed since the **total** time was
#         last reset.
#         """
# 
#         now = time.time()
#         self._print(
#             'Total wall time: {:.2f} s'.format(now - self._begin)
#         )


from pyspark import SparkConf, SparkContext
from sympy import IndexedBase, Rational, symbols
from drudge import RestrictedPartHoleDrudge, Stopwatch
dr.full_simplify = False

p = dr.names
e_ = p.e_
a, b, c, d = p.V_dumms[:4]
i, j, k, l = p.O_dumms[:4]

#
# Cluster excitation operator
# 
# Here, we first write the cluster excitation operator in terms of the
# unitary group generator.  Then they will be substituted by their fermion
# operator definition.
#

t = IndexedBase('t')

cluster = dr.einst(
    t[a, i] * e_[a, i] +
    Rational(1, 2) * t[a, b, i, j] * e_[a, i] * e_[b, j]
)

dr.set_n_body_base(t, 2)
cluster = cluster.simplify()
cluster.cache()

#
# Similarity transform of the Hamiltonian
# 


# Path: drudge/fock.py
# class RestrictedPartHoleDrudge(SpinOneHalfPartHoleDrudge):
#     """Drudge for the particle-hole problems on restricted reference.
# 
#     Similar to :py:class:`SpinOneHalfPartHoldDrudge`, this drudge deals with
#     particle-hole problems with explicit one-half spin.  However, here the spin
#     quantum number is summed symbolically.  This gives **much** faster
#     derivations for theories based on restricted reference, but offers less
#     flexibility.
# 
#     .. attribute:: spin_range
# 
#         The symbolic range for spin values.
# 
#     .. attribute:: spin_dumms
# 
#         The dummies for the spin quantum number.
# 
#     .. attribute:: e_
# 
#         Tensor definition for the unitary group generators.  It should be
#         indexed with the upper and lower indices to the :math:`E` operator.  It
#         is also registered in the name archive as ``e_``.
# 
#     """
# 
#     def __init__(
#             self, *args,
#             spin_range=Range(r'\uparrow\downarrow', 0, 2),
#             spin_dumms=tuple(Symbol('sigma{}'.format(i)) for i in range(50)),
#             **kwargs
#     ):
#         """Initialize the restricted particle-hole drudge."""
# 
#         super().__init__(
#             *args, spin=(spin_range, spin_dumms), **kwargs
#         )
#         self.add_resolver({
#             UP: spin_range,
#             DOWN: spin_range
#         })
# 
#         self.spin_range = spin_range
#         self.spin_dumms = self.dumms.value[spin_range]
# 
#         sigma = self.dumms.value[spin_range][0]
#         p = Symbol('p')
#         q = Symbol('q')
#         self.e_ = TensorDef(Vec('E'), (p, q), self.sum(
#             (sigma, spin_range), self.cr[p, sigma] * self.an[q, sigma]
#         ))
#         self.set_name(e_=self.e_)
# 
# Path: drudge/utils.py
# class Stopwatch:
#     """Utility class for printing timing information.
# 
#     This class helps to timing the progression of batch jobs.  It is capable of
#     getting and formatting the elapsed wall time between consecutive steps.
#     Note that the timing here might not be accurate to one second.
# 
#     """
# 
#     def __init__(self, print_cb=print):
#         """Initialize the stopwatch.
# 
#         Parameters
#         ----------
# 
#         print_cb
#             The function will be called with the formatted time-stamp.  By
#             default, it will just be written to stdout.
# 
#         """
#         self._print = print_cb
#         self.tick(total=True)
# 
#     def tick(self, total=False):
#         """Reset the timer.
# 
#         Parameters
#         ----------
# 
#         total
#             If the total beginning time is going to be reset as well.
# 
#         """
#         self._prev = time.time()
#         if total:
#             self._begin = self._prev
# 
#     def tock(self, label, tensor=None):
#         """Make a timestamp.
# 
#         The formatted timestamp will be given to the callback of the current
#         stamper.  The wall time elapsed since the last :py:meth:`tick` will be
#         printed.
# 
#         Parameters
#         ----------
# 
#         label
#             The label for the current step.
# 
#         tensor
#             When a tensor is given, it will be cached, counted its number of
#             terms.  This method has this parameter since if no reduction is
#             performed on the tensor, it might remain unevaluated inside Spark
#             and give misleading timing information.
# 
#         """
# 
#         if tensor is not None:
#             tensor.cache()
#             n_terms = '{} terms, '.format(tensor.n_terms)
#         else:
#             n_terms = ''
# 
#         now = time.time()
#         elapse = now - self._prev
#         self._prev = now
# 
#         self._print(
#             '{} done, {}wall time: {:.2f} s'.format(label, n_terms, elapse)
#         )
# 
#     def tock_total(self):
#         """Make a timestamp for the total time.
# 
#         The total time will be the time elapsed since the **total** time was
#         last reset.
#         """
# 
#         now = time.time()
#         self._print(
#             'Total wall time: {:.2f} s'.format(now - self._begin)
#         )


# Path: docs/examples/rccsd.py
from pyspark import SparkConf, SparkContext
from sympy import IndexedBase, Rational, symbols
from drudge import RestrictedPartHoleDrudge, Stopwatch

dr.full_simplify = False

p = dr.names
e_ = p.e_
a, b, c, d = p.V_dumms[:4]
i, j, k, l = p.O_dumms[:4]

#
# Cluster excitation operator
# 
# Here, we first write the cluster excitation operator in terms of the
# unitary group generator.  Then they will be substituted by their fermion
# operator definition.
#

t = IndexedBase('t')

cluster = dr.einst(
    t[a, i] * e_[a, i] +
    Rational(1, 2) * t[a, b, i, j] * e_[a, i] * e_[b, j]
)

dr.set_n_body_base(t, 2)
cluster = cluster.simplify()
cluster.cache()

#
# Similarity transform of the Hamiltonian
# 


stopwatch = Stopwatch()