<commit_before>//
// Created by david on 2018-01-31.
//

#include "class_flbit.h"
#include <config/nmspc_settings.h>
#include <general/nmspc_tensor_extra.h>
#include <iostream>
#include <physics/nmspc_quantum_mechanics.h>
#include <tensors/state/class_state_finite.h>
#include <tools/common/fmt.h>
#include <tools/common/io.h>
#include <tools/common/log.h>
#include <tools/common/prof.h>
#include <tools/finite/io.h>
#include <tools/finite/measure.h>
#include <tools/finite/mps.h>
#include <tools/finite/ops.h>
#include <tools/finite/opt.h>
#include <tensors/state/class_mps_site.h>
#include <unsupported/Eigen/CXX11/Tensor>

class_flbit::class_flbit(std::shared_ptr<h5pp::File> h5pp_file_) : class_algorithm_finite(std::move(h5pp_file_), AlgorithmType::fLBIT) {
    tools::log->trace("Constructing class_flbit");
}

void class_flbit::resume() {
    // Resume can imply many things
    // 1) Resume a simulation which terminated prematurely
    // 2) Resume a previously successful simulation. This may be desireable if the config
    //    wants something that is not present in the file.
    //      a) A certain number of states
    //      b) A state inside of a particular energy window
    //      c) The ground or "roof" states
    // To guide the behavior, we check the setting ResumePolicy.

    auto state_prefix = tools::common::io::h5resume::find_resumable_state(*h5pp_file, algo_type);
    if(state_prefix.empty()) throw std::runtime_error("Could not resume: no valid state candidates found for resume");
    tools::log->info("Resuming state [{}]", state_prefix);
    tools::finite::io::h5resume::load_simulation(*h5pp_file, state_prefix, tensors, status);
    clear_convergence_status();
    // Our first task is to decide on a state name for the newly loaded state
    // The simplest is to inferr it from the state prefix itself
    auto name = tools::common::io::h5resume::extract_state_name(state_prefix);

    // Initialize a custom task list
    std::list<flbit_task> task_list;

    if(not status.algorithm_has_finished) {
        // This could be a checkpoint state
        // Simply "continue" the algorithm until convergence
        if(name.find("emax") != std::string::npos) task_list.emplace_back(flbit_task::FIND_HIGHEST_STATE);
        else if(name.find("emin") != std::string::npos)
            task_list.emplace_back(flbit_task::FIND_GROUND_STATE);
        else
            throw std::runtime_error(fmt::format("Unrecognized state name for flbit: [{}]", name));
        task_list.emplace_back(flbit_task::POST_DEFAULT);
        run_task_list(task_list);
    }
    // If we reached this point the current state has finished for one reason or another.
    // TODO: We may still have some more things to do, e.g. the config may be asking for more states
}

void class_flbit::run_task_list(std::list<flbit_task> &task_list) {
    while(not task_list.empty()) {
        auto task = task_list.front();
        switch(task) {
            case flbit_task::INIT_RANDOMIZE_MODEL: randomize_model(); break;
            case flbit_task::INIT_RANDOMIZE_INTO_PRODUCT_STATE: randomize_state(ResetReason::INIT, StateInit::RANDOM_PRODUCT_STATE); break;
            case flbit_task::INIT_RANDOMIZE_INTO_ENTANGLED_STATE: randomize_state(ResetReason::INIT, StateInit::RANDOM_ENTANGLED_STATE); break;
            case flbit_task::INIT_BOND_DIM_LIMITS: init_bond_dimension_limits(); break;
            case flbit_task::INIT_WRITE_MODEL: write_to_file(StorageReason::MODEL); break;
            case flbit_task::INIT_CLEAR_STATUS: status.clear(); break;
            case flbit_task::INIT_DEFAULT: run_preprocessing(); break;
            case flbit_task::FIND_GROUND_STATE:
                ritz       = StateRitz::SR;
                state_name = "state_e_min";
                run_algorithm();
                break;
            case flbit_task::FIND_HIGHEST_STATE:
                ritz       = StateRitz::LR;
                state_name = "state_e_max";
                run_algorithm();
                break;
            case flbit_task::POST_WRITE_RESULT: write_to_file(StorageReason::FINISHED); break;
            case flbit_task::POST_PRINT_RESULT: print_status_full(); break;
            case flbit_task::POST_PRINT_PROFILING: tools::common::profile::print_profiling(algo_type); break;
            case flbit_task::POST_DEFAULT: run_postprocessing(); break;
            case flbit_task::PROF_RESET: tools::common::profile::reset_profiling(algo_type); break;
        }
        task_list.pop_front();
    }
}

void class_flbit::run_default_task_list() {
    std::list<flbit_task> default_task_list = {
        flbit_task::INIT_DEFAULT,
        flbit_task::FIND_GROUND_STATE,
        flbit_task::POST_DEFAULT,
    };

    run_task_list(default_task_list);
    if(not default_task_list.empty()) {
        for(auto &task : default_task_list) tools::log->critical("Unfinished task: {}", enum2str(task));
        throw std::runtime_error("Simulation ended with unfinished tasks");
    }
}

void class_flbit::run_preprocessing() {
    tools::log->info("Running {} preprocessing", algo_name);
    tools::common::profile::prof[algo_type]["t_pre"]->tic();
    status.clear();
    randomize_model(); // First use of random!
    init_bond_dimension_limits();
    randomize_state(ResetReason::INIT, settings::strategy::initial_state);
    Eigen::Tensor<Scalar,3>   zminus_spinor  = Textra::MatrixToTensor(tools::finite::mps::internal::get_spinor("z", -1).normalized(), 2, 1, 1);
    tensors.state->get_mps_site(2).set_M(zminus_spinor);

    auto unitary_twosite_operators0 = qm::lbit::get_unitary_twosite_operators(settings::model::model_size,0.1);
    auto unitary_twosite_operators1 = qm::lbit::get_unitary_twosite_operators(settings::model::model_size,0.1);
    auto unitary_twosite_operators2 = qm::lbit::get_unitary_twosite_operators(settings::model::model_size,0.1);
    auto unitary_twosite_operators3 = qm::lbit::get_unitary_twosite_operators(settings::model::model_size,0.1);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators0,false, status.chi_lim);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators1,false, status.chi_lim);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators2,false, status.chi_lim);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators3,false, status.chi_lim);

    // Time evolve here


    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators3,true, status.chi_lim);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators2,true, status.chi_lim);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators1,true, status.chi_lim);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators0,true, status.chi_lim);<commit_msg>Work in progress: building flbit algorithm<commit_after>//
// Created by david on 2018-01-31.
//

#include "class_flbit.h"
#include <config/nmspc_settings.h>
#include <general/nmspc_tensor_extra.h>
#include <physics/nmspc_quantum_mechanics.h>
#include <tensors/model/class_model_finite.h>
#include <tensors/state/class_mps_site.h>
#include <tensors/state/class_state_finite.h>
#include <tools/common/fmt.h>
#include <tools/common/io.h>
#include <tools/common/log.h>
#include <tools/common/prof.h>
#include <tools/finite/io.h>
#include <tools/finite/measure.h>
#include <tools/finite/mps.h>
#include <tools/finite/ops.h>
#include <tools/finite/opt.h>
#include <tools/finite/print.h>
#include <unsupported/Eigen/CXX11/Tensor>

class_flbit::class_flbit(std::shared_ptr<h5pp::File> h5pp_file_) : class_algorithm_finite(std::move(h5pp_file_), AlgorithmType::fLBIT) {
    tools::log->trace("Constructing class_flbit");
}

void class_flbit::resume() {
    // Resume can imply many things
    // 1) Resume a simulation which terminated prematurely
    // 2) Resume a previously successful simulation. This may be desireable if the config
    //    wants something that is not present in the file.
    //      a) A certain number of states
    //      b) A state inside of a particular energy window
    //      c) The ground or "roof" states
    // To guide the behavior, we check the setting ResumePolicy.

    auto state_prefix = tools::common::io::h5resume::find_resumable_state(*h5pp_file, algo_type);
    if(state_prefix.empty()) throw std::runtime_error("Could not resume: no valid state candidates found for resume");
    tools::log->info("Resuming state [{}]", state_prefix);
    tools::finite::io::h5resume::load_simulation(*h5pp_file, state_prefix, tensors, status);
    clear_convergence_status();
    // Our first task is to decide on a state name for the newly loaded state
    // The simplest is to inferr it from the state prefix itself
    auto name = tools::common::io::h5resume::extract_state_name(state_prefix);

    // Initialize a custom task list
    std::list<flbit_task> task_list;

    if(not status.algorithm_has_finished) {
        // This could be a checkpoint state
        // Simply "continue" the algorithm until convergence
        if(name.find("emax") != std::string::npos) task_list.emplace_back(flbit_task::FIND_HIGHEST_STATE);
        else if(name.find("emin") != std::string::npos)
            task_list.emplace_back(flbit_task::FIND_GROUND_STATE);
        else
            throw std::runtime_error(fmt::format("Unrecognized state name for flbit: [{}]", name));
        task_list.emplace_back(flbit_task::POST_DEFAULT);
        run_task_list(task_list);
    }
    // If we reached this point the current state has finished for one reason or another.
    // TODO: We may still have some more things to do, e.g. the config may be asking for more states
}

void class_flbit::run_task_list(std::list<flbit_task> &task_list) {
    while(not task_list.empty()) {
        auto task = task_list.front();
        switch(task) {
            case flbit_task::INIT_RANDOMIZE_MODEL: randomize_model(); break;
            case flbit_task::INIT_RANDOMIZE_INTO_PRODUCT_STATE: randomize_state(ResetReason::INIT, StateInit::RANDOM_PRODUCT_STATE); break;
            case flbit_task::INIT_RANDOMIZE_INTO_ENTANGLED_STATE: randomize_state(ResetReason::INIT, StateInit::RANDOM_ENTANGLED_STATE); break;
            case flbit_task::INIT_BOND_DIM_LIMITS: init_bond_dimension_limits(); break;
            case flbit_task::INIT_WRITE_MODEL: write_to_file(StorageReason::MODEL); break;
            case flbit_task::INIT_CLEAR_STATUS: status.clear(); break;
            case flbit_task::INIT_DEFAULT: run_preprocessing(); break;
            case flbit_task::FIND_GROUND_STATE:
                ritz       = StateRitz::SR;
                state_name = "state_e_min";
                run_algorithm();
                break;
            case flbit_task::FIND_HIGHEST_STATE:
                ritz       = StateRitz::LR;
                state_name = "state_e_max";
                run_algorithm();
                break;
            case flbit_task::POST_WRITE_RESULT: write_to_file(StorageReason::FINISHED); break;
            case flbit_task::POST_PRINT_RESULT: print_status_full(); break;
            case flbit_task::POST_PRINT_PROFILING: tools::common::profile::print_profiling(algo_type); break;
            case flbit_task::POST_DEFAULT: run_postprocessing(); break;
            case flbit_task::PROF_RESET: tools::common::profile::reset_profiling(algo_type); break;
        }
        task_list.pop_front();
    }
}

void class_flbit::run_default_task_list() {
    std::list<flbit_task> default_task_list = {
        flbit_task::INIT_DEFAULT,
        flbit_task::FIND_GROUND_STATE,
        flbit_task::POST_DEFAULT,
    };

    run_task_list(default_task_list);
    if(not default_task_list.empty()) {
        for(auto &task : default_task_list) tools::log->critical("Unfinished task: {}", enum2str(task));
        throw std::runtime_error("Simulation ended with unfinished tasks");
    }
}

void class_flbit::run_preprocessing() {
    tools::log->info("Running {} preprocessing", algo_name);
    tools::common::profile::prof[algo_type]["t_pre"]->tic();
    status.clear();
    randomize_model(); // First use of random!
    init_bond_dimension_limits();
    randomize_state(ResetReason::INIT, settings::strategy::initial_state);
    Eigen::Tensor<Scalar,3>   xplus_spinor  = Textra::MatrixToTensor(tools::finite::mps::internal::get_spinor("x", 1).normalized(), 2, 1, 1);
    Eigen::Tensor<Scalar,3>   zminus_spinor  = Textra::MatrixToTensor(tools::finite::mps::internal::get_spinor("z", -1).normalized(), 2, 1, 1);
    tensors.state->get_mps_site(1).set_M(xplus_spinor);
    tensors.state->get_mps_site(2).set_M(zminus_spinor);
    tools::finite::print::model(*tensors.model);


    // Time evolve here
    auto delta_t =  std::complex<double>(0.0,-0.3);
    std::vector<Eigen::Tensor<Scalar,2>> twosite_hamiltonian_operators;
    for(size_t pos = 0; pos < settings::model::model_size-1; pos++)
        twosite_hamiltonian_operators.emplace_back(tensors.model->get_multisite_ham({pos,pos+1}));

    auto time_evolution_operators = qm::lbit::get_twosite_time_evolution_operators(settings::model::model_size, delta_t, twosite_hamiltonian_operators);

    tools::finite::mps::apply_twosite_gates(*tensors.state,time_evolution_operators,false, status.chi_lim);
//    tools::finite::mps::apply_twosite_gates(*tensors.state,time_evolution_operators,true, status.chi_lim);

    exit(0);
    auto unitary_twosite_operators0 = qm::lbit::get_unitary_twosite_operators(settings::model::model_size,0.1);
    auto unitary_twosite_operators1 = qm::lbit::get_unitary_twosite_operators(settings::model::model_size,0.1);
    auto unitary_twosite_operators2 = qm::lbit::get_unitary_twosite_operators(settings::model::model_size,0.1);
    auto unitary_twosite_operators3 = qm::lbit::get_unitary_twosite_operators(settings::model::model_size,0.1);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators0,false, status.chi_lim);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators1,false, status.chi_lim);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators2,false, status.chi_lim);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators3,false, status.chi_lim);




    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators3,true, status.chi_lim);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators2,true, status.chi_lim);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators1,true, status.chi_lim);
    tools::finite::mps::apply_twosite_gates(*tensors.state,unitary_twosite_operators0,true, status.chi_lim);
{'fraction_non_alphanumeric': 0.1243498817966903, 'fraction_numerical': 0.0073623775751435324, 'mean_word_length': 4.51023446222553, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 64, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2343405', 'n_tokens_mistral': 5028, 'n_tokens_neox': 4858, 'n_words': 815}