Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added a planning interface and renamed the DDL interface to learners. … #53

Merged
merged 22 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from ..util.data_conversion import *

class DataDrivenLearning:
class LearnersInterface:
def __init__(self, headers, _ai_plugins={}):
assert(len(headers)>0), 'Headers are required'
self.headers = headers
Expand Down
46 changes: 46 additions & 0 deletions onair/src/ai_components/planners_interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# GSC-19165-1, "The On-Board Artificial Intelligence Research (OnAIR) Platform"
#
# Copyright © 2023 United States Government as represented by the Administrator of
# the National Aeronautics and Space Administration. No copyright is claimed in the
# United States under Title 17, U.S. Code. All Other Rights Reserved.
#
# Licensed under the NASA Open Source Agreement version 1.3
# See "NOSA GSC-19165-1 OnAIR.pdf"

"""
Planners interface class for managing all planning-based AI components
"""
import importlib.util
import importlib.util
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import twice?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it's done in learners_interface.py as well


from ..util.data_conversion import *

class PlannersInterface:
def __init__(self, headers, _ai_plugins={}):
assert(len(headers)>0), 'Headers are required'
self.headers = headers
self.planning_constructs = []
for module_name in list(_planning_plugins.keys()):
spec = importlib.util.spec_from_file_location(module_name, _planning_plugins[module_name])
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
self.planning_constructs.append(module.Plugin(module_name,headers))

def update(self, curr_data, status):
input_data = curr_data
output_data = status_to_oneHot(status)
for plugin in self.planning_constructs:
plugin.update(input_data)

def apriori_training(self, batch_data):
for plugin in self.planning_constructs:
plugin.apriori_training(batch_data)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra new lines

def render_reasoning(self):
diagnoses = {}
for plugin in self.planning_constructs:
diagnoses[plugin.component_name] = plugin.render_reasoning()
return diagnoses



4 changes: 2 additions & 2 deletions onair/src/reasoning/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
Agent Class
Deals with supervised learning for diagnosing statuses
"""
from ..data_driven_components.data_driven_learning import DataDrivenLearning
from ..ai_components.learners_interface import LearnersInterface
from ..reasoning.diagnosis import Diagnosis

class Agent:
def __init__(self, vehicle, plugin_list):
self.vehicle_rep = vehicle
self.learning_systems = DataDrivenLearning(self.vehicle_rep.get_headers(),plugin_list)
self.learning_systems = LearnersInterface(self.vehicle_rep.get_headers(),plugin_list)
self.mission_status = self.vehicle_rep.get_status()
self.bayesian_status = self.vehicle_rep.get_bayesian_status()

Expand Down
2 changes: 1 addition & 1 deletion plugins/generic/generic_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# See "NOSA GSC-19165-1 OnAIR.pdf"

import numpy as np
from onair.src.data_driven_components.ai_plugin_abstract.core import AIPlugIn
from onair.src.ai_components.ai_plugin_abstract.core import AIPlugIn

class Plugin(AIPlugIn):
def apriori_training(self,batch_data=[]):
Expand Down
2 changes: 1 addition & 1 deletion plugins/kalman_plugin/kalman_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import simdkalman
import numpy as np
from onair.src.data_driven_components.ai_plugin_abstract.core import AIPlugIn
from onair.src.ai_components.ai_plugin_abstract.core import AIPlugIn

class Plugin(AIPlugIn):
def __init__(self, name, headers, window_size=3):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
import pytest
from mock import MagicMock

import onair.src.data_driven_components.ai_plugin_abstract.core as core
from onair.src.data_driven_components.ai_plugin_abstract.core import AIPlugIn
import onair.src.ai_components.ai_plugin_abstract.core as core
from onair.src.ai_components.ai_plugin_abstract.core import AIPlugIn

class FakeAIPlugIn(AIPlugIn):
def __init__(self, _name, _headers):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
# Licensed under the NASA Open Source Agreement version 1.3
# See "NOSA GSC-19165-1 OnAIR.pdf"

""" Test DataDrivenLearning Functionality """
""" Test LearnersInterface Functionality """
import pytest
from mock import MagicMock

import onair.src.data_driven_components.data_driven_learning as data_driven_learning
from onair.src.data_driven_components.data_driven_learning import DataDrivenLearning
import onair.src.ai_components.learners_interface as learners_interface
from onair.src.ai_components.learners_interface import LearnersInterface

import importlib
from typing import Dict

# __init__ tests
def test_DataDrivenLearning__init__sets_instance_headers_to_given_headers_and_does_nothing_else_when_given__ai_plugins_is_empty(mocker):
def test_LearnersInterface__init__sets_instance_headers_to_given_headers_and_does_nothing_else_when_given__ai_plugins_is_empty(mocker):
# Arrange
arg_headers = []
arg__ai_plugins = {}
Expand All @@ -27,15 +27,15 @@ def test_DataDrivenLearning__init__sets_instance_headers_to_given_headers_and_do
for i in range(num_fake_headers):
arg_headers.append(MagicMock())

cut = DataDrivenLearning.__new__(DataDrivenLearning)
cut = LearnersInterface.__new__(LearnersInterface)

# Act
cut.__init__(arg_headers, arg__ai_plugins)

# Assert
assert cut.headers == arg_headers

def test_DataDrivenLearning__init__throws_AttributeError_when_given_module_file_has_no_attribute_Plugin(mocker):
def test_LearnersInterface__init__throws_AttributeError_when_given_module_file_has_no_attribute_Plugin(mocker):
# Arrange
fake_module_name = MagicMock()
arg_headers = []
Expand All @@ -48,7 +48,7 @@ def test_DataDrivenLearning__init__throws_AttributeError_when_given_module_file_

# Assert

def test_DataDrivenLearning__init__sets_instance_ai_constructs_to_a_list_of_the_calls_AIPlugIn_with_plugin_and_given_headers_for_each_item_in_given__ai_plugins_when_given__ai_plugins_is_occupied(mocker):
def test_LearnersInterface__init__sets_instance_ai_constructs_to_a_list_of_the_calls_AIPlugIn_with_plugin_and_given_headers_for_each_item_in_given__ai_plugins_when_given__ai_plugins_is_occupied(mocker):
# Arrange
arg_headers = []
arg__ai_plugins = {}
Expand Down Expand Up @@ -77,7 +77,7 @@ def test_DataDrivenLearning__init__sets_instance_ai_constructs_to_a_list_of_the_
for i, module in enumerate(fake_module_list):
mocker.patch.object(module,'Plugin',return_value=expected_ai_constructs[i])

cut = DataDrivenLearning.__new__(DataDrivenLearning)
cut = LearnersInterface.__new__(LearnersInterface)

# Act
cut.__init__(arg_headers, arg__ai_plugins)
Expand All @@ -99,32 +99,32 @@ def test_DataDrivenLearning__init__sets_instance_ai_constructs_to_a_list_of_the_
assert cut.ai_constructs == expected_ai_constructs

# update tests
def test_DataDrivenLearning_update_only_calls_flotify_input_with_given_curr_data_and_status_to_oneHot_with_given_status_when_instance_ai_constructs_is_empty(mocker):
def test_LearnersInterface_update_only_calls_flotify_input_with_given_curr_data_and_status_to_oneHot_with_given_status_when_instance_ai_constructs_is_empty(mocker):
# Arrange
arg_curr_data = MagicMock()
arg_status = MagicMock()

mocker.patch(data_driven_learning.__name__ + '.status_to_oneHot')
mocker.patch(learners_interface.__name__ + '.status_to_oneHot')

cut = DataDrivenLearning.__new__(DataDrivenLearning)
cut = LearnersInterface.__new__(LearnersInterface)
cut.ai_constructs = []

# Act
result = cut.update(arg_curr_data, arg_status)

# Assert
assert data_driven_learning.status_to_oneHot.call_count == 1
assert data_driven_learning.status_to_oneHot.call_args_list[0].args == (arg_status,)
assert learners_interface.status_to_oneHot.call_count == 1
assert learners_interface.status_to_oneHot.call_args_list[0].args == (arg_status,)
assert result == None

def test_DataDrivenLearning_update_calls_flotify_input_with_given_curr_data_and_status_to_oneHot_with_given_status_and_calls_update_on_each_ai_construct_with_input_data_when_instance_ai_constructs_is_occupied(mocker):
def test_LearnersInterface_update_calls_flotify_input_with_given_curr_data_and_status_to_oneHot_with_given_status_and_calls_update_on_each_ai_construct_with_input_data_when_instance_ai_constructs_is_occupied(mocker):
# Arrange
arg_curr_data = MagicMock()
arg_status = MagicMock()

mocker.patch(data_driven_learning.__name__ + '.status_to_oneHot')
mocker.patch(learners_interface.__name__ + '.status_to_oneHot')

cut = DataDrivenLearning.__new__(DataDrivenLearning)
cut = LearnersInterface.__new__(LearnersInterface)
cut.ai_constructs = []

num_fake_ai_constructs = pytest.gen.randint(1, 10) # arbitrary, from 1 to 10 (0 has own test)
Expand All @@ -137,19 +137,19 @@ def test_DataDrivenLearning_update_calls_flotify_input_with_given_curr_data_and_
result = cut.update(arg_curr_data, arg_status)

# Assert
assert data_driven_learning.status_to_oneHot.call_count == 1
assert data_driven_learning.status_to_oneHot.call_args_list[0].args == (arg_status,)
assert learners_interface.status_to_oneHot.call_count == 1
assert learners_interface.status_to_oneHot.call_args_list[0].args == (arg_status,)
for i in range(num_fake_ai_constructs):
assert cut.ai_constructs[i].update.call_count == 1
assert cut.ai_constructs[i].update.call_args_list[0].args == (arg_curr_data,)
assert result == None

# apriori_training tests
def test_DataDrivenLearning_apriori_training_does_nothing_when_instance_ai_constructs_is_empty():
def test_LearnersInterface_apriori_training_does_nothing_when_instance_ai_constructs_is_empty():
# Arrange
arg_batch_data = MagicMock()

cut = DataDrivenLearning.__new__(DataDrivenLearning)
cut = LearnersInterface.__new__(LearnersInterface)
cut.ai_constructs = []

# Act
Expand All @@ -158,11 +158,11 @@ def test_DataDrivenLearning_apriori_training_does_nothing_when_instance_ai_const
# Assert
assert result == None

def test_DataDrivenLearning_apriori_training_calls_apriori_training_on_each_ai_constructs_item(mocker):
def test_LearnersInterface_apriori_training_calls_apriori_training_on_each_ai_constructs_item(mocker):
# Arrange
arg_batch_data = MagicMock()

cut = DataDrivenLearning.__new__(DataDrivenLearning)
cut = LearnersInterface.__new__(LearnersInterface)
cut.ai_constructs = []

num_fake_ai_constructs = pytest.gen.randint(1, 10) # arbitrary, from 1 to 10 (0 has own test)
Expand All @@ -179,9 +179,9 @@ def test_DataDrivenLearning_apriori_training_calls_apriori_training_on_each_ai_c
assert result == None

# render_reasoning tests
def test_DataDrivenLearning_render_reasoning_returns_empty_dict_when_instance_ai_constructs_is_empty(mocker):
def test_LearnersInterface_render_reasoning_returns_empty_dict_when_instance_ai_constructs_is_empty(mocker):
# Arrange
cut = DataDrivenLearning.__new__(DataDrivenLearning)
cut = LearnersInterface.__new__(LearnersInterface)
cut.ai_constructs = []

# Act
Expand All @@ -190,9 +190,9 @@ def test_DataDrivenLearning_render_reasoning_returns_empty_dict_when_instance_ai
# Assert
assert result == {}

def test_DataDrivenLearning_render_reasoning_returns_dict_of_each_ai_construct_as_key_to_the_result_of_its_render_reasoning_when_instance_ai_constructs_is_occupied(mocker):
def test_LearnersInterface_render_reasoning_returns_dict_of_each_ai_construct_as_key_to_the_result_of_its_render_reasoning_when_instance_ai_constructs_is_occupied(mocker):
# Arrange
cut = DataDrivenLearning.__new__(DataDrivenLearning)
cut = LearnersInterface.__new__(LearnersInterface)
cut.ai_constructs = []

expected_result = {}
Expand Down
6 changes: 3 additions & 3 deletions test/onair/src/reasoning/test_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def test_Agent__init__sets_vehicle_rep_to_given_vehicle_and_learning_systems_and
fake_plugin_list = MagicMock()

mocker.patch.object(arg_vehicle, 'get_headers', return_value=fake_headers)
mocker.patch(agent.__name__ + '.DataDrivenLearning', return_value=fake_learning_systems)
mocker.patch(agent.__name__ + '.LearnersInterface', return_value=fake_learning_systems)
mocker.patch.object(arg_vehicle, 'get_status', return_value=fake_mission_status)
mocker.patch.object(arg_vehicle, 'get_bayesian_status', return_value=fake_bayesian_status)

Expand All @@ -39,8 +39,8 @@ def test_Agent__init__sets_vehicle_rep_to_given_vehicle_and_learning_systems_and
assert cut.vehicle_rep == arg_vehicle
assert arg_vehicle.get_headers.call_count == 1
assert arg_vehicle.get_headers.call_args_list[0].args == ()
assert agent.DataDrivenLearning.call_count == 1
assert agent.DataDrivenLearning.call_args_list[0].args == (fake_headers, fake_plugin_list)
assert agent.LearnersInterface.call_count == 1
assert agent.LearnersInterface.call_args_list[0].args == (fake_headers, fake_plugin_list)
assert cut.learning_systems == fake_learning_systems
assert arg_vehicle.get_status.call_count == 1
assert arg_vehicle.get_status.call_args_list[0].args == ()
Expand Down