Module loda.mine.miner

Miner class for finding integer sequence programs.

Expand source code
"""Miner class for finding integer sequence programs."""

import os
import time

from loda.lang import Program
from loda.oeis import PrefixIndex, Sequence
from loda.runtime import Evaluator, Interpreter


class Miner:

    def __init__(self, sequences: list, interpreter: Interpreter, generator):
        self.__sequences = sequences
        self.__index = PrefixIndex(sequences)
        self.__interpreter = interpreter
        self.__generator = generator
        self.__basic_timeout = 60
        self.__extended_timeout = 600
        self.__back_off_after = 3
        self.__failed_matches = {}

    def __call__(self):
        program = self.__generator()
        evaluator = Evaluator(program, self.__interpreter)
        match = self.__index.global_match()
        refine = True
        start_time = time.time()
        try:
            while refine:
                term = evaluator()
                refine = self.__index.refine_match(match, term)
                if (time.time() - start_time) > self.__basic_timeout:
                    print("Timeout")
                    return
        except Exception as e:
            print("Evaluation error: {}".format(e))
            return
        ids = self.__index.get_match_ids(match)
        for id in ids:
            seq = self.__index.get(id)
            if self.__check_match(program, id):
                print("Found match for {}".format(seq))
                p = "~/loda/programs/local/{}.asm".format(seq.id_str())
                with open(os.path.expanduser(p), "w") as asm_file:
                    asm_file.write("; {}\n".format(seq))
                    asm_file.write(str(program))
            elif self.__back_off_after > 0:
                if id not in self.__failed_matches:
                    self.__failed_matches[id] = 1
                else:
                    self.__failed_matches[id] += 1
                if self.__failed_matches[id] >= self.__back_off_after:
                    print("Back off matching {}".format(seq))
                    self.__sequences = list(
                        filter(lambda s: s.id != id, self.__sequences))
                    self.__index = PrefixIndex(self.__sequences)

    def __check_match(self, program: Program, id: int):
        seq = self.__index.get(id)
        terms = seq.load_b_file(os.path.expanduser("~/loda/oeis"))
        if terms is None or len(terms) == len(seq.terms):
            print("Skipping check for {}".format(seq))
            return False
        print("Checking match for {}".format(seq))
        start_time = time.time()
        if len(terms) > 1000:
            terms = terms[0:1000]
        evaluator = Evaluator(program, self.__interpreter)
        for t in terms:
            n = evaluator()
            if n != t:
                return False
            if (time.time() - start_time) > self.__extended_timeout:
                print("Timeout")
                return False
        return True

Classes

class Miner (sequences: list, interpreter: Interpreter, generator)
Expand source code
class Miner:

    def __init__(self, sequences: list, interpreter: Interpreter, generator):
        self.__sequences = sequences
        self.__index = PrefixIndex(sequences)
        self.__interpreter = interpreter
        self.__generator = generator
        self.__basic_timeout = 60
        self.__extended_timeout = 600
        self.__back_off_after = 3
        self.__failed_matches = {}

    def __call__(self):
        program = self.__generator()
        evaluator = Evaluator(program, self.__interpreter)
        match = self.__index.global_match()
        refine = True
        start_time = time.time()
        try:
            while refine:
                term = evaluator()
                refine = self.__index.refine_match(match, term)
                if (time.time() - start_time) > self.__basic_timeout:
                    print("Timeout")
                    return
        except Exception as e:
            print("Evaluation error: {}".format(e))
            return
        ids = self.__index.get_match_ids(match)
        for id in ids:
            seq = self.__index.get(id)
            if self.__check_match(program, id):
                print("Found match for {}".format(seq))
                p = "~/loda/programs/local/{}.asm".format(seq.id_str())
                with open(os.path.expanduser(p), "w") as asm_file:
                    asm_file.write("; {}\n".format(seq))
                    asm_file.write(str(program))
            elif self.__back_off_after > 0:
                if id not in self.__failed_matches:
                    self.__failed_matches[id] = 1
                else:
                    self.__failed_matches[id] += 1
                if self.__failed_matches[id] >= self.__back_off_after:
                    print("Back off matching {}".format(seq))
                    self.__sequences = list(
                        filter(lambda s: s.id != id, self.__sequences))
                    self.__index = PrefixIndex(self.__sequences)

    def __check_match(self, program: Program, id: int):
        seq = self.__index.get(id)
        terms = seq.load_b_file(os.path.expanduser("~/loda/oeis"))
        if terms is None or len(terms) == len(seq.terms):
            print("Skipping check for {}".format(seq))
            return False
        print("Checking match for {}".format(seq))
        start_time = time.time()
        if len(terms) > 1000:
            terms = terms[0:1000]
        evaluator = Evaluator(program, self.__interpreter)
        for t in terms:
            n = evaluator()
            if n != t:
                return False
            if (time.time() - start_time) > self.__extended_timeout:
                print("Timeout")
                return False
        return True