ngraymon/termfactory

Create the code generator for the LHS

Closed this issue · 15 comments

If possible it would be convient to be able to have the LHS and RHS code in the same code_eT_zhz.py file.
Need to check if this is possible

  1. first try to wrap your head around latex_eT_zhz.py changes on lhs_code_generator branch
  2. add argument to argparse (store_true) -lhs so you can play around from the command line.
  3. running the code generator and the latex generator for eT zhz and comparing the latex to the code to see where the lines come from:

R0xqHh7aTA

fs5AzyLkoJ

Later on you can see how the LHS vs RHS latex are different by checking issue #40

First steps for changing the code would be:

  1. replicate the simplest facsimile of the latex changes, so
    • change t_args to s_args and check if it propagates correctly
    • change h_args to dt_args and check if it propagates correctly
    • more complicated print dt_args only when order of the 'h-like' term is not zero (match the logic of the latex
    • print dz_args only when order of the z term is not zero or it is zero but so is the h-like term (match the logic of the latex
  2. Then you probably want to start comparing to the output here and get a sense of where your goal is.
    reference_subtraction_equations.py

New bits:

  • function names `compute_m#_n#_dz_lhs(...)
  • instead of R = np.zeros( etc do dz = np.zeros(
  • your adding each contribution to the dz term but then when you return it it will be subtracted return dz
  • for each add_m#_n#_HZ_terms we don't actually want to add the first term where dt_args is all zeros and dz_args[(m, n)] with m and n equal to the value of the function its inside
  • if the input tuple to h_args is (0, 0) then it shouldn't be printed as an argument of the einsum call
  • function calls should take the following arguments Z, t_conj, dT, dz_args
    where dz_args is a list of dz_# where if Z is max order 3 then the length is 3 - the value of the current function call. So compute_z_0_residual(Z, t_conj, dT, dz_args) that dz_args would be length 3 (3-0) and include dz_3, dz_2, dz_1
  • dz_args like z_args indexed by tuples
  • for cases where dt is 0,0 then you should
R += np.einsum('i, ac, ci -> a', t_args[(0, 1)], h_args[(0, 0)], z_args[(1, 0)])

change that into (only print two terms at all)

R += np.einsum('i, ci -> a', t_args[(0, 1)],  z_args[(1, 0)])
  • all y's in the example are actually c's because we can assign them to the Z[0] term which we know uses the c label not y
  • write a new _lhs_einsum_electronic_components function and try to put good documentation / notes explaining whats going on in it
    all your outputs are always one surface label and then all other labels are vibrational (there is no a ever only c and it is never traced out and always comes from Z[#] and always is present in the output) whether dz or z there is always one surface label c
  • write a new _lhs_einsum_subscript_generator
  • write a new _lhs_einsum_vibrational_components` AND THE DOCSTRINGS
  • we 100% need to rename the LHS term which represents theprojection operator as we now actually use LHS/RHS flags and this is supppppeeer confusing

First check of compute_z_0 left hand side looking pretty good
aI0w4CJGI3

  • maybe eventually have a thermal flag?
# unpack kwargs
thermal = kwargs['thermal ']
only_ground_state = kwargs['only_ground_state']
lhs_rhs = kwargs['lhs_rhs']

then we could do

if thermal:  # until we work with thermal equations this should always be true (need to remove when working on thermal stuff)
    master_omega.operator_list[:] = [p for p in master_omega.operator_list if p.m == 0]

instead of

if True:  # until we work with thermal equations this should always be true (need to remove when working on thermal stuff)
    master_omega.operator_list[:] = [p for p in master_omega.operator_list if p.m == 0]

commit 045919bf3183c396949c2747908731ae8f18b2d8 fixes the red boxes

checked z1 and its all good
bzUqtT0kSW

  • make a few tests of specific input arguments and just confirm that the output has been unchanged, probably just use the whole output file and then compare strings
    for inputs like

python3 driver.py -t (1-2) (1-4) 1 (1-6) (1-6) -lhs -c

Reminder for myself need to write up glue stuff

# compute the common factor (t^k)^*(idt^k/dtau)
X = np.einsum('k,k->', T_conj[1], dT[1])

if not generated_flag
    # they have to be in this order as Z1 depends on Z2 and Z0 depends on Z1
    dz_3 = compute_z_3_residual(Z, T_conj, X, dT, z_opt_flag)
    dz_2 = compute_z_2_residual(Z, T_conj, X, dT, dz_3, z_opt_flag)
    dz_1 = compute_z_1_residual(Z, T_conj, X, dT, dz_3, dz_2, z_opt_flag)
    dz_0 = compute_z_0_residual(Z, T_conj, X, dT, dz_3, dz_2, dz_1, z_opt_flag)
else:
    dz_args = {}

    dz_3 = a.compute_m0_n0_amplitude(A, N, ansatz, truncation, t_conj, dT, z_args, dz_args)
    dz_args[(3, 0)] = dz_3

    dz_2 = a.compute_m0_n0_amplitude(A, N, ansatz, truncation, t_conj, dT, z_args, dz_args)
    dz_args[(2, 0)] = dz_2

    dz_1 = a.compute_m0_n0_amplitude(A, N, ansatz, truncation, t_conj, dT, z_args, dz_args)
    dz_args[(1, 0)] = dz_1

    dz_0 = a.compute_m0_n0_amplitude(A, N, ansatz, truncation, t_conj, dT, z_args, dz_args)


dZ = {
    3: dz_3,
    2: dz_2,
    1: dz_1,
    0: dz_0,
}

return dZ

check z2 ALMOST all good, one problematic term it disagrees with the current code AND the latex

Xj1r9HZDET

1FLhMVWfI9

checked z3 and all good!!

SQayGXwUsP

Confirmed that LHS latex prefactors are slightly wrong; probably because they consider h_n contracting with z^m components which cannot happen to dT/dtau

@bsonghao and I had a talk and confirmed that the prefactor should be 1/2 and the code generator is correct