Bardo.Core (Bardo v0.1.0)
View SourceCore API for Bardo neuroevolution library.
This module serves as the main entry point for users who are importing Bardo as a dependency. It provides a clean, well-documented API that focuses on the essential neuroevolution functionality while hiding implementation details.
Key Features
- Neural Network Creation - Define neural network architectures with sensors and actuators
- Evolutionary Training - Train neural networks through evolutionary algorithms
- Agent Management - Create and manage neuroevolutionary agents
- Experiment Control - Run controlled experiments with multiple populations
Usage Example
# Define a simple neural network morphology
morphology = Bardo.Core.create_morphology(%{
name: "XOR Network",
dimensions: 2,
inputs: 2,
outputs: 1,
hidden_layers: [3]
})
# Create an experiment
{:ok, experiment_id} = Bardo.Core.create_experiment("XOR Experiment")
# Configure the experiment with our morphology
:ok = Bardo.Core.configure_experiment(experiment_id, %{
morphology: morphology,
population_size: 50,
generations: 100
})
# Define a fitness function for XOR
fitness_fn = fn agent ->
accuracy = Bardo.Core.evaluate_agent(agent, [
{[0.0, 0.0], [0.0]},
{[0.0, 1.0], [1.0]},
{[1.0, 0.0], [1.0]},
{[1.0, 1.0], [0.0]}
])
1.0 - accuracy # Convert accuracy to error (lower is better)
end
# Set the fitness function and run the experiment
:ok = Bardo.Core.set_fitness_function(experiment_id, fitness_fn)
:ok = Bardo.Core.run_experiment(experiment_id)
# Get the best solution when the experiment completes
{:ok, solution} = Bardo.Core.get_best_solution(experiment_id)
Summary
Functions
Activates a neural network agent with the given inputs.
Adds an actuator to a morphology.
Adds an agent to a scape.
Adds a sensor to a morphology.
Configures an existing experiment with the given parameters.
Creates a new experiment with the given name.
Creates a new neural network morphology with the given options.
Creates a new population of neural network agents.
Creates a new scape (virtual environment) for agents to interact with.
Evaluates an agent's performance on a set of test cases.
Evolves a population for the specified number of generations.
Gets the status of an experiment.
Exports experiment results to a file.
Gets the best agent from a population.
Gets the best solution from a completed experiment.
Lists all experiments.
Lists all saved morphologies.
Loads an agent from a file.
Loads a morphology from persistent storage.
Runs a complete experiment with minimal setup.
Starts an experiment with the given ID.
Saves an agent to a file for later use.
Saves a morphology to persistent storage for later use.
Sets the fitness function for evaluating solutions in an experiment.
Solves the XOR problem as a simple demonstration.
Steps a scape forward in time, updating all agents.
Stops an ongoing experiment.
Functions
Activates a neural network agent with the given inputs.
This function passes input values through the neural network and returns the resulting output values.
Parameters
agent
- The agent (neural network) to activateinputs
- List of input values for the network
Returns
- List of output values from the network
Examples
outputs = Bardo.Core.activate_agent(agent, [0.0, 1.0])
# For an XOR network with one output, this might return [1.0]
@spec add_actuator(Bardo.Morphology.t(), map()) :: Bardo.Morphology.t()
Adds an actuator to a morphology.
Parameters
morphology
- The morphology to add the actuator toactuator_opts
- Options for the actuator
Actuator Options
:name
- The name of the actuator (required, as atom):type
- The type of actuator (default: :standard):vl
- Vector length, number of inputs to this actuator (required):parameters
- Additional parameters for the actuator
Returns
- An updated morphology with the new actuator
Examples
# Add a motor actuator to a morphology
morphology = Bardo.Core.create_morphology()
updated_morphology = Bardo.Core.add_actuator(morphology, %{
name: :motor,
vl: 2,
parameters: %{max_speed: 10.0}
})
Adds an agent to a scape.
Parameters
scape_id
- ID of the scapeagent_id
- ID of the agent to addagent
- The agent to addposition
- Position to place the agent at
Returns
:ok
- If the agent was added successfully{:error, reason}
- If there was an error adding the agent
Examples
:ok = Bardo.Core.add_agent_to_scape("flatland", "agent1", agent, [50, 50])
@spec add_sensor(Bardo.Morphology.t(), map()) :: Bardo.Morphology.t()
Adds a sensor to a morphology.
Parameters
morphology
- The morphology to add the sensor tosensor_opts
- Options for the sensor
Sensor Options
:name
- The name of the sensor (required, as atom):type
- The type of sensor (default: :standard):vl
- Vector length, number of outputs from this sensor (required):parameters
- Additional parameters for the sensor
Returns
- An updated morphology with the new sensor
Examples
# Add a vision sensor to a morphology
morphology = Bardo.Core.create_morphology()
updated_morphology = Bardo.Core.add_sensor(morphology, %{
name: :vision,
vl: 100,
parameters: %{fov: 120}
})
Configures an existing experiment with the given parameters.
Parameters
experiment_id
- ID of the experiment to configureconfig
- Configuration parameters for the experiment
Configuration Options
:runs
- Number of separate evolutionary runs to perform (default: 1):generations
- Maximum number of generations per run (default: 100):population_size
- Number of individuals in the population (default: 50):morphology
- The morphology to use (either a morphology map or an ID):selection_method
- Method for selecting parents, one of: [:tournament, :roulette, :rank] (default: :tournament):crossover_rate
- Probability of crossover (default: 0.7):mutation_rate
- Probability of mutation (default: 0.3):elitism
- Fraction of top individuals to preserve unchanged (default: 0.1):backup_flag
- Whether to back up best solutions (default: true):visualize
- Whether to generate visualizations (default: false):distributed
- Whether to use distributed evolution (default: false)
Returns
:ok
- If the experiment was configured successfully{:error, reason}
- If there was an error configuring the experiment
Examples
:ok = Bardo.Core.configure_experiment(experiment_id, %{
runs: 5,
generations: 50,
population_size: 100,
morphology: morphology,
selection_method: :tournament
})
Creates a new experiment with the given name.
Experiments are the top-level container for evolutionary runs. They manage:
- Population configuration
- Fitness evaluation
- Running multiple evolutionary trials
- Collecting and analyzing results
Parameters
name
- Name of the experiment
Returns
{:ok, experiment_id}
- Experiment ID of the created experiment{:error, reason}
- If there was an error creating the experiment
Examples
{:ok, experiment_id} = Bardo.Core.create_experiment("XOR Experiment")
@spec create_morphology(map()) :: Bardo.Morphology.t()
Creates a new neural network morphology with the given options.
This function defines the structure of the neural network, including:
- Number of inputs and outputs
- Hidden layer configuration
- Sensor and actuator specifications
- Substrate and connection patterns
Parameters
opts
- A map of options for the morphology (see options below)
Options
:name
- The name of the morphology (default: "Generic Morphology"):description
- A description of the morphology:dimensions
- Number of dimensions in the substrate (default: 2):inputs
- Number of input neurons (default: 1):outputs
- Number of output neurons (default: 1):hidden_layers
- List of hidden layer sizes (default: [3]):activation_functions
- List of activation functions (default: [:sigmoid]):substrate_type
- Type of substrate, one of: [:cartesian, :hypercube, :hypersphere, :custom] (default: :cartesian):connection_pattern
- Type of connection pattern, one of: [:feedforward, :recurrent, :dense, :custom] (default: :feedforward):plasticity
- Type of plasticity, one of: [:none, :hebbian, :stdp, :abcn, :iterative] (default: :none):sensors
- List of custom sensor specifications:actuators
- List of custom actuator specifications:parameters
- Additional parameters for the morphology
Returns
- A morphology map with the specified configuration
Examples
# Create a simple XOR network morphology
morphology = Bardo.Core.create_morphology(%{
name: "XOR Network",
dimensions: 2,
inputs: 2,
outputs: 1,
hidden_layers: [3]
})
Creates a new population of neural network agents.
Parameters
population_id
- Unique identifier for the populationconfig
- Configuration for the population
Returns
{:ok, pid}
- If the population was created successfully{:error, reason}
- If there was an error creating the population
Examples
{:ok, pid} = Bardo.Core.create_population("xor_population", %{
morphology: morphology,
population_size: 50,
fitness_function: fn agent -> ... end
})
Creates a new scape (virtual environment) for agents to interact with.
Parameters
scape_id
- Unique identifier for the scapeconfig
- Configuration for the scape
Returns
{:ok, pid}
- If the scape was created successfully{:error, reason}
- If there was an error creating the scape
Examples
{:ok, pid} = Bardo.Core.create_scape("flatland", %{
width: 100,
height: 100,
agents: 10
})
Evaluates an agent's performance on a set of test cases.
This function runs the agent on multiple input/output pairs and returns an accuracy score between 0.0 and 1.0.
Parameters
agent
- The agent (neural network) to evaluatetest_cases
- List of {input, expected_output} tuples
Returns
- Accuracy score between 0.0 and 1.0
Examples
# Evaluate XOR test cases
test_cases = [
{[0.0, 0.0], [0.0]},
{[0.0, 1.0], [1.0]},
{[1.0, 0.0], [1.0]},
{[1.0, 1.0], [0.0]}
]
accuracy = Bardo.Core.evaluate_agent(agent, test_cases)
# A perfect XOR network would return 1.0
@spec evolve_population(String.t(), non_neg_integer()) :: :ok | {:error, term()}
Evolves a population for the specified number of generations.
Parameters
population_id
- ID of the population to evolvegenerations
- Number of generations to evolve
Returns
:ok
- If the population was evolved successfully{:error, reason}
- If there was an error evolving the population
Examples
:ok = Bardo.Core.evolve_population("xor_population", 50)
@spec experiment_status(String.t()) :: {:not_started, map()} | {:in_progress, map()} | {:completed, map()} | {:stopped, map()} | {:error, term()}
Gets the status of an experiment.
Parameters
experiment_id
- ID of the experiment to get status for
Returns
{:not_started, info}
- If the experiment has not started yet{:in_progress, info}
- If the experiment is in progress, with status details{:completed, info}
- If the experiment is completed, with results{:stopped, info}
- If the experiment was stopped before completion{:error, reason}
- If there was an error getting the status
Examples
# Check experiment status
Bardo.Core.experiment_status(experiment_id)
Exports experiment results to a file.
Parameters
experiment_id
- ID of the experiment to exportfile_path
- Path to save the results toformat
- Format to export in (:csv, :json, or :binary)
Returns
:ok
- If the results were exported successfully{:error, reason}
- If there was an error exporting the results
Examples
:ok = Bardo.Core.export_results(experiment_id, "results.json", :json)
Gets the best agent from a population.
Parameters
population_id
- ID of the population
Returns
{:ok, agent}
- The best agent in the population{:error, reason}
- If there was an error getting the agent
Examples
{:ok, best_agent} = Bardo.Core.get_best_agent("xor_population")
Gets the best solution from a completed experiment.
Parameters
experiment_id
- ID of the experiment to get the best solution from
Returns
{:ok, solution}
- Best solution found in the experiment{:error, reason}
- If there was an error getting the best solution
Examples
{:ok, solution} = Bardo.Core.get_best_solution(experiment_id)
# Use the solution for inference
output = Bardo.Core.activate_agent(solution, [0.5, 0.5])
Lists all experiments.
Returns
{:ok, [experiment]}
- List of all experiments with their basic information{:error, reason}
- If there was an error getting the experiments
Examples
# Get all experiments
Bardo.Core.list_experiments()
@spec list_morphologies() :: {:ok, [Bardo.Morphology.t()]} | {:error, term()}
Lists all saved morphologies.
Returns
{:ok, [morphology]}
on success{:error, reason}
on failure
Examples
{:ok, morphologies} = Bardo.Core.list_morphologies()
Loads an agent from a file.
Parameters
file_path
- Path to load the agent from
Returns
{:ok, agent}
- If the agent was loaded successfully{:error, reason}
- If there was an error loading the agent
Examples
{:ok, agent} = Bardo.Core.load_agent("xor_agent.bin")
@spec load_morphology(binary()) :: {:ok, Bardo.Morphology.t()} | {:error, term()}
Loads a morphology from persistent storage.
Parameters
id
- The ID of the morphology to load
Returns
{:ok, morphology}
on success{:error, reason}
on failure
Examples
Bardo.Core.load_morphology("morph_123456789")
@spec quick_experiment(String.t(), Bardo.Morphology.t(), function(), map()) :: {:ok, String.t()} | {:error, term()}
Runs a complete experiment with minimal setup.
This is a convenience function that creates an experiment, sets it up, and runs it with common default parameters.
Parameters
name
- Name of the experimentmorphology
- The morphology to usefitness_function
- Function to evaluate fitnessopts
- Additional options to override defaults
Returns
{:ok, experiment_id}
- ID of the created experiment{:error, reason}
- If there was an error
Examples
# Create and run an XOR experiment
{:ok, experiment_id} = Bardo.Core.quick_experiment(
"XOR Experiment",
morphology,
fn agent ->
# Fitness function implementation
end,
%{population_size: 100, generations: 50}
)
Starts an experiment with the given ID.
This begins the evolutionary process according to the experiment configuration. The function returns immediately, but the experiment continues to run in the background until completion.
Parameters
experiment_id
- ID of the experiment to start
Returns
:ok
- If the experiment was started successfully{:error, reason}
- If there was an error starting the experiment
Examples
:ok = Bardo.Core.run_experiment(experiment_id)
Saves an agent to a file for later use.
Parameters
agent
- The agent (neural network) to savefile_path
- Path to save the agent to
Returns
:ok
- If the agent was saved successfully{:error, reason}
- If there was an error saving the agent
Examples
:ok = Bardo.Core.save_agent(agent, "xor_agent.bin")
@spec save_morphology(Bardo.Morphology.t()) :: :ok | {:error, term()}
Saves a morphology to persistent storage for later use.
Parameters
morphology
- The morphology to save
Returns
:ok
on success{:error, reason}
on failure
Examples
morphology = Bardo.Core.create_morphology(%{name: "XOR"})
Bardo.Core.save_morphology(morphology)
Sets the fitness function for evaluating solutions in an experiment.
The fitness function receives an agent (neural network) and must return a numerical fitness score. Higher values indicate better fitness.
Parameters
experiment_id
- ID of the experimentfitness_function
- Function to evaluate fitness of solutions
Returns
:ok
- If the fitness function was set successfully{:error, reason}
- If there was an error setting the fitness function
Examples
# Define a fitness function for XOR
fitness_fn = fn agent ->
inputs = [[0,0], [0,1], [1,0], [1,1]]
expected = [[0], [1], [1], [0]]
# Calculate error across all cases
errors = Enum.zip(inputs, expected)
|> Enum.map(fn {input, output} ->
actual = Bardo.Core.activate_agent(agent, input)
Enum.zip(actual, output)
|> Enum.map(fn {a, e} -> :math.pow(a - e, 2) end)
|> Enum.sum()
end)
# Return fitness (1 / (1 + error)) so higher is better
1.0 / (1.0 + Enum.sum(errors))
end
:ok = Bardo.Core.set_fitness_function(experiment_id, fitness_fn)
Solves the XOR problem as a simple demonstration.
This is a convenience function that creates and runs an experiment to solve the XOR problem, a classic benchmark in neural networks.
Parameters
opts
- Options to override defaults
Returns
{:ok, agent}
- The best solution found{:error, reason}
- If there was an error
Examples
{:ok, xor_agent} = Bardo.Core.solve_xor()
outputs = Bardo.Core.activate_agent(xor_agent, [1.0, 0.0])
# Should return approximately [1.0]
@spec step_scape(String.t(), non_neg_integer()) :: :ok | {:error, term()}
Steps a scape forward in time, updating all agents.
Parameters
scape_id
- ID of the scapesteps
- Number of time steps to advance
Returns
:ok
- If the scape was stepped successfully{:error, reason}
- If there was an error stepping the scape
Examples
:ok = Bardo.Core.step_scape("flatland", 10)
Stops an ongoing experiment.
Parameters
experiment_id
- ID of the experiment to stop
Returns
:ok
- If the experiment was stopped successfully{:error, reason}
- If there was an error stopping the experiment
Examples
:ok = Bardo.Core.stop_experiment(experiment_id)