Program Listing for File Program.hpp¶
↰ Return to documentation for file (include/sgpl/program/Program.hpp)
#pragma once
#ifndef SGPL_PROGRAM_PROGRAM_HPP_INCLUDE
#define SGPL_PROGRAM_PROGRAM_HPP_INCLUDE
#include <algorithm>
#include <cstddef>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include "../../../third-party/cereal/include/cereal/archives/binary.hpp"
#include "../../../third-party/cereal/include/cereal/archives/json.hpp"
#include "../../../third-party/cereal/include/cereal/types/vector.hpp"
#include "../../../third-party/conduit/include/uitsl/polyfill/filesystem.hpp"
#include "../../../third-party/conduit/include/uit_emp/datastructs/hash_utils.hpp"
#include "../../../third-party/conduit/include/uit_emp/polyfill/span.hpp"
#include "../algorithm/mutate_bits.hpp"
#include "../debug/sgpl_error.hpp"
#include "../utility/ThreadLocalRandom.hpp"
#include "Instruction.hpp"
#include "OpCodeRectifier.hpp"
namespace sgpl {
template<typename Spec>
class Program : public std::vector<sgpl::Instruction<Spec>> {
using parent_t = std::vector<sgpl::Instruction<Spec>>;
using library_t = typename Spec::library_t;
using rectifier_t = sgpl::OpCodeRectifier<library_t>;
size_t size_bytes() const {
return this->size() * sizeof( typename parent_t::value_type );
}
public:
Program() = default;
explicit Program( const size_t n ) : parent_t( n ) {
sgpl::tlrand.Get().RandFill(
reinterpret_cast<unsigned char*>( this->data() ),
size_bytes()
);
Rectify();
}
explicit Program(const char* as_json) {
std::istringstream iss(as_json);
cereal::JSONInputArchive archive( iss );
archive( *this );
}
explicit Program(const std::filesystem::path& path) {
if ( path.extension() == ".json" ) {
std::ifstream is(path);
cereal::JSONInputArchive archive( is );
archive( *this );
} else if ( path.extension() == ".bin" ) {
std::ifstream is(path);
cereal::BinaryInputArchive archive( is );
archive( *this );
} else sgpl_error(
"unknown sgpl::Program file format" << path.extension() << path
);
}
Program( const Program& other ) {
// copy all bytes, including padding bytes so that we can
// reliably perform a bytewise hash
parent_t::resize( other.size() );
std::memcpy(
reinterpret_cast< std::byte* >( parent_t::data() ),
reinterpret_cast< const std::byte* >( other.data() ),
parent_t::size() * sizeof( other.front() )
);
}
Program( Program&& other ) : parent_t( std::move(other) ) {}
Program( const parent_t& other ) {
// copy all bytes, including padding bytes so that we can
// reliably perform a bytewise hash
parent_t::resize( other.size() );
std::memcpy(
reinterpret_cast< std::byte* >( parent_t::data() ),
reinterpret_cast< const std::byte* >( other.data() ),
parent_t::size() * sizeof( other.front() )
);
}
Program( parent_t&& other ) : parent_t( std::move(other) ) {}
Program& operator=(const Program& other) {
// copy all bytes, including padding bytes so that we can
// reliably perform a bytewise hash
parent_t::resize( other.size() );
std::memcpy(
reinterpret_cast< std::byte* >( parent_t::data() ),
reinterpret_cast< const std::byte* >( other.data() ),
parent_t::size() * sizeof( other.front() )
);
return *this;
}
Program& operator=(Program&& other) {
parent_t::operator=( std::move(other) );
return *this;
}
Program& operator=(parent_t&& other) {
parent_t::operator=( std::move(other) );
return *this;
}
size_t ApplyPointMutations(
const float p_bit_toggle, const rectifier_t& rectifier=rectifier_t{}
) {
// bail early for p_bit_toggle == 0
if ( p_bit_toggle == 0 ) return 0;
// ideally, we would draw from the binomial distn,
// but that's expensive with varying n...
// so approximate with the poisson distribution instead
// they're similar-ish, e.g., https://www.researchgate.net/figure/Poisson-versus-binomial-distribution-from-number-of-heads-in-a-coin-toss-The-Poisson_fig3_255717571
// (they become more similar for large n)
const size_t n_muts = sgpl::tlrand.Get().GetRandPoisson(
size_bytes() * CHAR_BIT,
p_bit_toggle
);
sgpl::mutate_bits(
std::span<std::byte>(
reinterpret_cast<std::byte*>( this->data() ),
size_bytes()
),
n_muts
);
Rectify(rectifier);
return n_muts;
}
void RotateGlobalAnchorToFront() {
const auto first_anchor = std::find_if(
this->begin(),
this->end(),
[]( const auto& instruction ) {
return library_t::IsAnchorGlobalOpCode( instruction.op_code );
}
);
if ( first_anchor != this->end() ) std::rotate(
this->begin(),
first_anchor,
this->end()
);
}
void Rectify(const rectifier_t& rectifier=rectifier_t{}) {
for (auto& inst : *this) inst.Rectify(rectifier);
}
bool HasGlobalAnchor() const {
const auto first_anchor = std::find_if(
this->begin(),
this->end(),
[]( const auto& instruction ) {
return library_t::IsAnchorGlobalOpCode( instruction.op_code );
}
);
return first_anchor != this->end();
}
};
} // namespace sgpl
namespace std {
template <typename Spec>
struct hash<sgpl::Program<Spec>> {
size_t operator()( const sgpl::Program<Spec>& program ) const {
return uit_emp::murmur_hash( std::span<const std::byte>(
reinterpret_cast<const std::byte*>( program.data() ),
program.size() * sizeof( program.front() )
) );
}
};
} // namespace std
#endif // #ifndef SGPL_PROGRAM_PROGRAM_HPP_INCLUDE