This notebook is an example of finding an arithmetic expression that evaluates to a given number. In this case, the arithmetic expression shall take the form of a continued fraction such as 1 / (4 + 1 / (4 +...))
and evaluate to Euler's number e. The code evolves a simple MeTTa program that can be evaluated with the current experimental version of OpenCog Hyperon.
References
from math import e
import alogos as al
import unified_map as um
from hyperon.common import MeTTa
metta = MeTTa()
ebnf_text = """
FRAC = "(+ " CONST " (/ " CONST " " FRAC "))" | CONST
CONST = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
"""
grammar = al.Grammar(ebnf_text=ebnf_text)
The objective function gets a candidate solution (=a string of the grammar's language) and returns a fitness value for it. This is done by 1) executing the string as MeTTa program with OpenCog Hyperon, which evaluates the arithmetic expression and returns the number it produces and 2) determining how much this number differs from a target number.
def objective_function(string):
if len(string) > 200:
return None # prevent too long expressions
result = metta.interpret(string)
number = result[0].get_object().value
return abs(number-e)
Check if grammar and objective function work as intended.
random_string = grammar.generate_string()
print(random_string)
result = metta.interpret(random_string)
print(result)
objective_function(random_string)
num_gen = 100
num_ind = 300
ea = al.EvolutionaryAlgorithm(
grammar, objective_function, 'min', verbose=True,
max_or_min_fitness=0.0, max_generations=num_gen, population_size=num_ind, offspring_size=num_ind,
evaluator=um.univariate.parallel.futures
)
The search is performed one generation after another and some intermediate results are reported to see how the solutions improve gradually.
best_ind = ea.run()
Show the phenotype of the best individual found so far. If more computing time is provided, increasingly better solutions may be discovered.
string = best_ind.phenotype
print(string)
print('Target:', e)
print('Found: ', metta.interpret(string)[0])