<commit_before>//
// Created by david on 2020-05-12.
//

#include "class_env_base.h"
#include <general/nmspc_tensor_extra.h>
#include <general/nmspc_tensor_omp.h>
#include <tensors/model/class_mpo_site.h>
#include <tensors/state/class_mps_site.h>
#include <tools/common/fmt.h>
#include <math/hash.h>
#include <math/num.h>
#include <config/debug.h>
#include <utility>

// We need to define the destructor and other special functions
// because we enclose data in unique_ptr for this pimpl idiom.
// Otherwise unique_ptr will forcibly inline its own default deleter.
// Here we follow "rule of five", so we must also define
// our own copy/move ctor and copy/move assignments
// This has the side effect that we must define our own
// operator= and copy assignment constructor.
// Read more: https://stackoverflow.com/questions/33212686/how-to-use-unique-ptr-with-forward-declared-type
// And here:  https://stackoverflow.com/questions/6012157/is-stdunique-ptrt-required-to-know-the-full-definition-of-t
class_env_base::class_env_base() : block(std::make_unique<Eigen::Tensor<Scalar, 3>>()) { assert_block(); } // default ctor
class_env_base::~class_env_base()                               = default;                                 // default dtor
class_env_base::class_env_base(class_env_base &&other) noexcept = default;                                 // default move ctor
class_env_base &class_env_base::operator=(class_env_base &&other) noexcept = default;                      // default move assign

class_env_base::class_env_base(const class_env_base &other)
    : edge_has_been_set(other.edge_has_been_set), block(std::make_unique<Eigen::Tensor<Scalar, 3>>(*other.block)), sites(other.sites), position(other.position),
      side(other.side), tag(other.tag) {
    assert_block();
}

class_env_base::class_env_base(std::string side_, size_t position_)
    : block(std::make_unique<Eigen::Tensor<Scalar, 3>>()), position(position_), side(std::move(side_)) {
    assert_block();
}
class_env_base::class_env_base(std::string side_, const class_mps_site &MPS, const class_mpo_site &MPO)
    : block(std::make_unique<Eigen::Tensor<Scalar, 3>>()), side(std::move(side_)) {
    if(MPS.get_position() != MPO.get_position())
        throw std::logic_error(fmt::format("MPS and MPO have different positions: {} != {}", MPS.get_position(), MPO.get_position()));
    position = MPS.get_position();
    assert_block();
}

class_env_base &class_env_base::operator=(const class_env_base &other) {
    if(this != &other) {
        edge_has_been_set = other.edge_has_been_set;
        block             = std::make_unique<Eigen::Tensor<Scalar, 3>>(*other.block);
        sites             = other.sites;
        position          = other.position;
        side              = other.side;
        tag               = other.tag;
        unique_id         = other.unique_id;
        unique_id_env     = other.unique_id_env;
        unique_id_mps     = other.unique_id_mps;
        unique_id_mpo     = other.unique_id_mpo;
    }
    assert_block();
    return *this;
}

using Scalar = class_env_base::Scalar;

void class_env_base::assert_block() const {
    if(not block) throw std::runtime_error(fmt::format("env {} {} at pos {} is null", tag, side, get_position()));
}

void class_env_base::build_block(Eigen::Tensor<Scalar, 3> &otherblock, const Eigen::Tensor<Scalar, 3> &mps, const Eigen::Tensor<Scalar, 4> &mpo){
    /*!< Contracts a site into the block-> */
    // Note that otherblock, mps and mpo should correspond to the same site! I.e. their "get_position()" are all equal.
    // This can't be checked here though, so do that before calling this function.

    if(not block) block = std::make_unique<Eigen::Tensor<Scalar, 3>>();
    if(side == "L") {
        /*! # Left environment block contraction
         *   [       ]--0         [       ]--0 0--[LB]--1 1--[  GA    ]--2
         *   [       ]            [       ]                      |
         *   [       ]            [       ]                      0
         *   [       ]            [       ]
         *   [       ]            [       ]                      2
         *   [       ]            [       ]                      |
         *   [ block ]--2     =   [lblock ]--2            0--[   M    ]--1
         *   [       ]            [       ]                      |
         *   [       ]            [       ]                      3
         *   [       ]            [       ]
         *   [       ]            [       ]                      0
         *   [       ]            [       ]                      |
         *   [       ]--1         [       ]--1 0--[LB]--1  1--[GA conj ]--2
         */

        if(mps.dimension(0) != mpo.dimension(2))
            throw std::runtime_error(fmt::format("env{} {} pos {} dimension mismatch: mps dim[{}]:{} != mpo   dim[{}]:{}",side,tag , position.value(), 0,
                                                 mps.dimension(0), 2, mpo.dimension(2)));
        if(mps.dimension(1) != otherblock.dimension(0))
            throw std::runtime_error(fmt::format("env{} {} pos {} dimension mismatch: mps dim[{}]:{} != left-block dim[{}]:{}",side,tag , position.value(), 1,
                                                 mps.dimension(1), 0, otherblock.dimension(0)));
        if(mpo.dimension(0) != otherblock.dimension(2))
            throw std::runtime_error(fmt::format("env{} {} pos {} dimension mismatch: mpo dim[{}]:{} != left-block dim[{}]:{}",side,tag , position.value(), 0,
                                                 mpo.dimension(0), 2, otherblock.dimension(2)));<commit_msg>Reset id's when building a new block<commit_after>//
// Created by david on 2020-05-12.
//

#include "class_env_base.h"
#include <general/nmspc_tensor_extra.h>
#include <general/nmspc_tensor_omp.h>
#include <tensors/model/class_mpo_site.h>
#include <tensors/state/class_mps_site.h>
#include <tools/common/fmt.h>
#include <math/hash.h>
#include <math/num.h>
#include <config/debug.h>
#include <utility>

// We need to define the destructor and other special functions
// because we enclose data in unique_ptr for this pimpl idiom.
// Otherwise unique_ptr will forcibly inline its own default deleter.
// Here we follow "rule of five", so we must also define
// our own copy/move ctor and copy/move assignments
// This has the side effect that we must define our own
// operator= and copy assignment constructor.
// Read more: https://stackoverflow.com/questions/33212686/how-to-use-unique-ptr-with-forward-declared-type
// And here:  https://stackoverflow.com/questions/6012157/is-stdunique-ptrt-required-to-know-the-full-definition-of-t
class_env_base::class_env_base() : block(std::make_unique<Eigen::Tensor<Scalar, 3>>()) { assert_block(); } // default ctor
class_env_base::~class_env_base()                               = default;                                 // default dtor
class_env_base::class_env_base(class_env_base &&other) noexcept = default;                                 // default move ctor
class_env_base &class_env_base::operator=(class_env_base &&other) noexcept = default;                      // default move assign

class_env_base::class_env_base(const class_env_base &other)
    : edge_has_been_set(other.edge_has_been_set), block(std::make_unique<Eigen::Tensor<Scalar, 3>>(*other.block)), sites(other.sites), position(other.position),
      side(other.side), tag(other.tag) {
    assert_block();
}

class_env_base::class_env_base(std::string side_, size_t position_)
    : block(std::make_unique<Eigen::Tensor<Scalar, 3>>()), position(position_), side(std::move(side_)) {
    assert_block();
}
class_env_base::class_env_base(std::string side_, const class_mps_site &MPS, const class_mpo_site &MPO)
    : block(std::make_unique<Eigen::Tensor<Scalar, 3>>()), side(std::move(side_)) {
    if(MPS.get_position() != MPO.get_position())
        throw std::logic_error(fmt::format("MPS and MPO have different positions: {} != {}", MPS.get_position(), MPO.get_position()));
    position = MPS.get_position();
    assert_block();
}

class_env_base &class_env_base::operator=(const class_env_base &other) {
    if(this != &other) {
        edge_has_been_set = other.edge_has_been_set;
        block             = std::make_unique<Eigen::Tensor<Scalar, 3>>(*other.block);
        sites             = other.sites;
        position          = other.position;
        side              = other.side;
        tag               = other.tag;
        unique_id         = other.unique_id;
        unique_id_env     = other.unique_id_env;
        unique_id_mps     = other.unique_id_mps;
        unique_id_mpo     = other.unique_id_mpo;
    }
    assert_block();
    return *this;
}

using Scalar = class_env_base::Scalar;

void class_env_base::assert_block() const {
    if(not block) throw std::runtime_error(fmt::format("env {} {} at pos {} is null", tag, side, get_position()));
}

void class_env_base::build_block(Eigen::Tensor<Scalar, 3> &otherblock, const Eigen::Tensor<Scalar, 3> &mps, const Eigen::Tensor<Scalar, 4> &mpo){
    /*!< Contracts a site into the block-> */
    // Note that otherblock, mps and mpo should correspond to the same site! I.e. their "get_position()" are all equal.
    // This can't be checked here though, so do that before calling this function.
    unique_id = std::nullopt;
    unique_id_env = std::nullopt;
    unique_id_mps = std::nullopt;
    unique_id_mpo = std::nullopt;

    if(not block) block = std::make_unique<Eigen::Tensor<Scalar, 3>>();
    if(side == "L") {
        /*! # Left environment block contraction
         *   [       ]--0         [       ]--0 0--[LB]--1 1--[  GA    ]--2
         *   [       ]            [       ]                      |
         *   [       ]            [       ]                      0
         *   [       ]            [       ]
         *   [       ]            [       ]                      2
         *   [       ]            [       ]                      |
         *   [ block ]--2     =   [lblock ]--2            0--[   M    ]--1
         *   [       ]            [       ]                      |
         *   [       ]            [       ]                      3
         *   [       ]            [       ]
         *   [       ]            [       ]                      0
         *   [       ]            [       ]                      |
         *   [       ]--1         [       ]--1 0--[LB]--1  1--[GA conj ]--2
         */

        if(mps.dimension(0) != mpo.dimension(2))
            throw std::runtime_error(fmt::format("env{} {} pos {} dimension mismatch: mps dim[{}]:{} != mpo   dim[{}]:{}",side,tag , position.value(), 0,
                                                 mps.dimension(0), 2, mpo.dimension(2)));
        if(mps.dimension(1) != otherblock.dimension(0))
            throw std::runtime_error(fmt::format("env{} {} pos {} dimension mismatch: mps dim[{}]:{} != left-block dim[{}]:{}",side,tag , position.value(), 1,
                                                 mps.dimension(1), 0, otherblock.dimension(0)));
        if(mpo.dimension(0) != otherblock.dimension(2))
            throw std::runtime_error(fmt::format("env{} {} pos {} dimension mismatch: mpo dim[{}]:{} != left-block dim[{}]:{}",side,tag , position.value(), 0,
                                                 mpo.dimension(0), 2, otherblock.dimension(2)));
{'fraction_non_alphanumeric': 0.14373952175063973, 'fraction_numerical': 0.012353304508956145, 'mean_word_length': 2.010358565737052, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 53, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 58, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7575351', 'n_tokens_mistral': 3579, 'n_tokens_neox': 3393, 'n_words': 699}