Skip to content

Commit

Permalink
Merge branch '484-configuration-remove-combined-config' of https://gi…
Browse files Browse the repository at this point in the history
…thub.com/hpi-epic/BP2021 into 484-configuration-remove-combined-config
  • Loading branch information
NikkelM committed Jun 2, 2022
2 parents b8c43b7 + f50fe65 commit caf5c01
Show file tree
Hide file tree
Showing 27 changed files with 387 additions and 327 deletions.
1 change: 0 additions & 1 deletion tests/test_vendors.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ def test_storage_evaluation_with_rebuy_price(state, expected_prices):
changed_config.max_price = 10
changed_config.production_price = 2
agent = circular_vendors.RuleBasedCERebuyAgent(config_market=changed_config)
print('*********************************')
assert expected_prices == agent.policy(state)


Expand Down
51 changes: 51 additions & 0 deletions webserver/alpha_business_app/adjustable_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from recommerce.configuration.utils import get_class

from .utils import convert_python_type_to_input_type


def get_agent_hyperparameter(agent: str, formdata: dict) -> list:

# get all fields that are possible for this agent
agent_class = get_class(agent)
agent_specs = agent_class.get_configurable_fields()

# we want to keep values already inside the html, so we need to parse existing html
parameter_values = _convert_form_to_value_dict(formdata)
# convert parameter into special list format for view
all_parameter = []
for spec in agent_specs:
this_parameter = {}
this_parameter['name'] = spec[0]
this_parameter['input_type'] = convert_python_type_to_input_type(spec[1])
this_parameter['prefill'] = _get_value_from_dict(spec[0], parameter_values)
all_parameter += [this_parameter]
return all_parameter


def get_rl_parameter_prefill(prefill: dict, error: dict) -> list:
# returns list of dictionaries
all_parameter = []
for key, value in prefill.items():
this_parameter = {}
this_parameter['name'] = key
this_parameter['prefill'] = value if value else ''
this_parameter['error'] = error[key] if error[key] else ''
all_parameter += [this_parameter]
return all_parameter


def _convert_form_to_value_dict(config_form) -> dict:
final_values = {}
for index in range((len(config_form) - 2) // 2):
current_name = config_form[f'formdata[{index}][name]']
current_value = config_form[f'formdata[{index}][value]']
if 'hyperparameter-rl' in current_name:
final_values[current_name.replace('hyperparameter-rl-', '')] = current_value
return final_values


def _get_value_from_dict(key, value_dict) -> dict:
try:
return value_dict[key]
except KeyError:
return ''
4 changes: 3 additions & 1 deletion webserver/alpha_business_app/buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from recommerce.configuration.config_validation import validate_config

from .adjustable_fields import get_rl_parameter_prefill
from .config_merger import ConfigMerger
from .config_parser import ConfigFlatDictParser
from .container_parser import parse_response_to_database
Expand Down Expand Up @@ -279,7 +280,8 @@ def _prefill(self) -> HttpResponse:
if 'config_id' not in post_request:
return self._decide_rendering()
merger = ConfigMerger()
final_dict, error_dict = merger.merge_config_objects(post_request['config_id'])
final_dict, error_dict = merger.merge_config_objects(post_request['config_id'], post_request)
final_dict['hyperparameter']['rl'] = get_rl_parameter_prefill(final_dict['hyperparameter']['rl'], error_dict['hyperparameter']['rl'])
# set an id for each agent (necessary for view)
for agent_index in range(len(final_dict['environment']['agents'])):
final_dict['environment']['agents'][agent_index]['display_name'] = 'Agent' if agent_index == 0 else 'Competitor'
Expand Down
7 changes: 3 additions & 4 deletions webserver/alpha_business_app/config_merger.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@ def merge_config_objects(self, config_object_ids: list) -> tuple:
"""
configuration_objects = [Config.objects.get(id=config_id) for config_id in config_object_ids]
configuration_dicts = [config.as_dict() for config in configuration_objects]
for c in configuration_dicts:
print(c)
print('--------------------------------------')
# for c in configuration_dicts:
# print(c)
# print('--------------------------------------')
# get initial empty dict to merge into
final_config = Config.get_empty_structure_dict()
for config in configuration_dicts:
final_config = self._merge_config_into_base_config(final_config, config)
print(final_config, '\n*******************************\n')
return final_config, self.error_dict

def _merge_config_into_base_config(self, base_config: dict, merging_config: dict, current_config_path: str = '') -> dict:
Expand Down
30 changes: 22 additions & 8 deletions webserver/alpha_business_app/handle_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,37 @@ def handle_uploaded_file(request, uploaded_config) -> HttpResponse:
except ValueError as value:
return render(request, 'upload.html', {'error': str(value)})

# Validate the config file using the recommerce validation functionality
validate_status, validate_data = validate_config(content_as_dict, False)
if not validate_status:
return render(request, 'upload.html', {'error': validate_data})
hyperparameter_config, environment_config = validate_data
config = validate_data
assert len(config.keys()) == 1, f'This config ({config} as multiple keys, should only be one ("environment", "rl" or "sim_market"))'

# recommerce returns either {'environment': {}}, {'rl': {}} or {'sim_markte': {}}}
# for parsing we need to know what the toplevel key is
top_level = config.keys()[0]
if top_level != 'environment':
top_level = 'hyperparameter'

# parse config model to datastructure
parser = ConfigModelParser()
web_hyperparameter_config = None
web_environment_config = None
try:
web_hyperparameter_config = parser.parse_config_dict_to_datastructure('hyperparameter', hyperparameter_config)
web_environment_config = parser.parse_config_dict_to_datastructure('environment', environment_config)
except ValueError:
return render(request, 'upload.html', {'error': 'Your config is wrong'})
resulting_config_part = parser.parse_config_dict_to_datastructure(top_level, config)
except ValueError as e:
return render(request, 'upload.html', {'error': f'Your config is wrong {e}'})

# Make it a real config object
environment_config = None
hyperparameter_config = None
if top_level == 'environment':
environment_config = resulting_config_part
else:
hyperparameter_config = resulting_config_part

given_name = request.POST['config_name']
config_name = given_name if given_name else uploaded_config.name
Config.objects.create(environment=web_environment_config, hyperparameter=web_hyperparameter_config, name=config_name, user=request.user)
Config.objects.create(environment=environment_config, hyperparameter=hyperparameter_config, name=config_name, user=request.user)
return redirect('/configurator', {'success': 'You successfully uploaded a config file'})


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Generated by Django 4.0.1 on 2022-06-01 18:36

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('alpha_business_app', '0012_config_user_container_user'),
]

operations = [
migrations.AddField(
model_name='rlconfig',
name='stable_baseline_test',
field=models.FloatField(default=None, null=True),
),
migrations.AddField(
model_name='rlconfig',
name='testvalue2',
field=models.FloatField(default=None, null=True),
),
migrations.AlterField(
model_name='rlconfig',
name='batch_size',
field=models.IntegerField(default=None, null=True),
),
migrations.AlterField(
model_name='rlconfig',
name='epsilon_decay_last_frame',
field=models.IntegerField(default=None, null=True),
),
migrations.AlterField(
model_name='rlconfig',
name='epsilon_final',
field=models.FloatField(default=None, null=True),
),
migrations.AlterField(
model_name='rlconfig',
name='epsilon_start',
field=models.FloatField(default=None, null=True),
),
migrations.AlterField(
model_name='rlconfig',
name='gamma',
field=models.FloatField(default=None, null=True),
),
migrations.AlterField(
model_name='rlconfig',
name='learning_rate',
field=models.FloatField(default=None, null=True),
),
migrations.AlterField(
model_name='rlconfig',
name='replay_size',
field=models.IntegerField(default=None, null=True),
),
migrations.AlterField(
model_name='rlconfig',
name='replay_start_size',
field=models.IntegerField(default=None, null=True),
),
migrations.AlterField(
model_name='rlconfig',
name='sync_target_frames',
field=models.IntegerField(default=None, null=True),
),
]
3 changes: 3 additions & 0 deletions webserver/alpha_business_app/models/agents_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ class AgentsConfig(AbstractConfig, models.Model):
def as_list(self) -> dict:
referencing_agents = self.agentconfig_set.all()
return [agent.as_dict() for agent in referencing_agents]

def as_dict(self) -> dict:
assert False, 'This should not be implemented as agents are a list.'
12 changes: 12 additions & 0 deletions webserver/alpha_business_app/models/environment_config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.db import models

from ..utils import remove_none_values_from_dict
from .abstract_config import AbstractConfig


Expand All @@ -10,3 +11,14 @@ class EnvironmentConfig(AbstractConfig, models.Model):
plot_interval = models.IntegerField(null=True)
marketplace = models.CharField(max_length=150, null=True)
task = models.CharField(max_length=14, choices=((1, 'training'), (2, 'agent_monitoring'), (3, 'exampleprinter')), null=True)

def as_dict(self) -> dict:
agents_list = self.agents.as_list() if self.agents is not None else None
return remove_none_values_from_dict({
'enable_live_draw': self.enable_live_draw,
'episodes': self.episodes,
'plot_interval': self.plot_interval,
'marketplace': self.marketplace,
'task': self.task,
'agents': agents_list
})
9 changes: 9 additions & 0 deletions webserver/alpha_business_app/models/hyperparameter_config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.db import models

from ..utils import remove_none_values_from_dict
from .abstract_config import AbstractConfig
from .rl_config import RlConfig
from .sim_market_config import SimMarketConfig
Expand All @@ -8,3 +9,11 @@
class HyperparameterConfig(AbstractConfig, models.Model):
rl = models.ForeignKey('alpha_business_app.RLConfig', on_delete=models.CASCADE, null=True)
sim_market = models.ForeignKey('alpha_business_app.SimMarketConfig', on_delete=models.CASCADE, null=True)

def as_dict(self) -> dict:
sim_market_dict = self.sim_market.as_dict() if self.sim_market is not None else {'sim_market': None}
rl_dict = self.rl.as_dict() if self.rl is not None else {'rl': None}
return remove_none_values_from_dict({
'rl': rl_dict,
'sim_market': sim_market_dict
})
11 changes: 5 additions & 6 deletions webserver/alpha_business_app/models/rl_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@


class RlConfig(AbstractConfig, models.Model):
stable_baseline_test = models.FloatField(null=True, default=None)
epsilon_decay_last_frame = models.IntegerField(null=True, default=None)
epsilon_start = models.FloatField(null=True, default=None)
sync_target_frames = models.IntegerField(null=True, default=None)
replay_start_size = models.IntegerField(null=True, default=None)
testvalue2 = models.FloatField(null=True, default=None)
gamma = models.FloatField(null=True, default=None)
epsilon_final = models.FloatField(null=True, default=None)
replay_size = models.IntegerField(null=True, default=None)
batch_size = models.IntegerField(null=True, default=None)
stable_baseline_test = models.FloatField(null=True, default=None)
learning_rate = models.FloatField(null=True, default=None)
epsilon_decay_last_frame = models.IntegerField(null=True, default=None)
testvalue2 = models.FloatField(null=True, default=None)
epsilon_final = models.FloatField(null=True, default=None)
threshold = models.FloatField(null=True, default=None)
gamma = models.FloatField(null=True, default=None)
9 changes: 5 additions & 4 deletions webserver/alpha_business_app/static/js/custom.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,19 +63,20 @@ $(document).ready(function() {

function addChangeToAgent () {
$("select.agent-agent-class").change(function () {
// will be called when another marketplace has been selected
// will be called when agent dropdown has changed, we need to change rl hyperparameter for that
var self = $(this);
console.log('here')
var form = $("form.config-form");
var formdata = form.serializeArray();
const csrftoken = getCookie("csrftoken");
$.ajax({
type: "POST",
url: self.data("url"),
data: {
csrfmiddlewaretoken: csrftoken,
"agent": self.val()
"agent": self.val(),
formdata
},
success: function (data) {
console.log(data)
$("div.rl-parameter").empty().append(data)
}
});
Expand Down
13 changes: 7 additions & 6 deletions webserver/alpha_business_app/tests/constant_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
'environment-episodes': [''],
'environment-plot_interval': [''],
'environment-marketplace': ['recommerce.market.circular.circular_sim_market.CircularEconomyRebuyPriceMonopoly'],
'environment-agents-name': ['Rule_Based Agent'],
'environment-agents-agent_class': ['recommerce.market.circular.circular_vendors.RuleBasedCERebuyAgent'],
'environment-agents-name': ['QLearning Agent'],
'environment-agents-agent_class': ['recommerce.rl.q_learning.q_learning_agent.QLearningAgent'],
'environment-agents-argument': [''],
'hyperparameter-rl-gamma': ['0.99'],
'hyperparameter-rl-batch_size': ['32'],
Expand All @@ -35,8 +35,8 @@
'enable_live_draw': False,
'agents': [
{
'name': 'Rule_Based Agent',
'agent_class': 'recommerce.market.circular.circular_vendors.RuleBasedCERebuyAgent',
'name': 'QLearning Agent',
'agent_class': 'recommerce.rl.q_learning.q_learning_agent.QLearningAgent',
'argument': ''
}
]
Expand Down Expand Up @@ -126,7 +126,9 @@
'replay_start_size': None,
'epsilon_decay_last_frame': None,
'epsilon_start': None,
'epsilon_final': None
'epsilon_final': None,
'testvalue2': None,
'stable_baseline_test': None
},
'sim_market': {
'max_storage': None,
Expand All @@ -142,7 +144,6 @@

EXAMPLE_RL_DICT = {
'rl': {
'class': 'recommerce.rl.q_learning.q_learning_agent.QLearningAgent',
'gamma': 0.99,
'batch_size': 32,
'replay_size': 100000,
Expand Down
16 changes: 16 additions & 0 deletions webserver/alpha_business_app/tests/test_adjustable_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from django.test import TestCase

from ..adjustable_fields import get_rl_parameter_prefill


class AdjustableFieldsTests(TestCase):
def test_rl_hyperparameter_with_prefill(self):
prefill_dict = {'gamma': 0.9, 'learning_rate': 0.4, 'test': None}
error_dict = {'gamma': 'test', 'learning_rate': None, 'test': None}
expected_list = [
{'name': 'gamma', 'prefill': 0.9, 'error': 'test'},
{'name': 'learning_rate', 'prefill': 0.4, 'error': ''},
{'name': 'test', 'prefill': '', 'error': ''}
]
actual_list = get_rl_parameter_prefill(prefill_dict, error_dict)
assert actual_list == expected_list
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,8 @@ def test_parsing_config_dict(self):

all_agents = environment_agents.agentconfig_set.all()
assert 1 == len(all_agents)
assert 'recommerce.market.circular.circular_vendors.RuleBasedCERebuyAgent' == all_agents[0].agent_class
assert 'Rule_Based Agent' == all_agents[0].name
assert 'recommerce.rl.q_learning.q_learning_agent.QLearningAgent' == all_agents[0].agent_class
assert 'QLearning Agent' == all_agents[0].name
assert '' == all_agents[0].argument

def test_parsing_agents(self):
Expand Down
Loading

0 comments on commit caf5c01

Please sign in to comment.