class Blueprint(object):

    def __init__(self, layout, training, score=None):
        self.layout = layout
        self.training = training
        self.score = score

    def scale_layers_size(self, scale):
        for layer in self.layout.get_layers():
            output_dim = layer.parameters.get('output_dim', None)
            if not output_dim:
                continue
            new_size = output_dim * scale
            logging.debug(
                'Scaling output dim: %d=>%d',
                output_dim,
                new_size)
            layer.parameters['output_dim'] = new_size

    def todict(self):
        return {
            'layout': self.layout.todict(),
            'training': self.training.todict(),
            'score': self.score} class Training(object):

    def __init__(self, objective, optimizer, metric,
                 stopping, batch_size, class_weight=None):
        self.objective = objective
        self.optimizer = optimizer
        self.metric = metric
        self.stopping = stopping
        self.batch_size = batch_size
        self.class_weight = class_weight

    def todict(self):
        return {
            'objective': self.objective.todict(),
            'optimizer': self.optimizer.todict(),
            'metric': self.metric.todict(),
            'stopping': self.stopping.todict(),
            'batch_size': self.batch_size,
            'class_weight': self.class_weight} class Layout(object):

    def __init__(self, input_size, output_size,
                 output_activation, block=None, block_input=None, rows=None):
        self.input_size = int(input_size)
        self.output_size = int(output_size)
        self.output_activation = output_activation
        self.block = block
        self.block_input = block_input
        self.rows = rows or list()

    def get_rows(self):
        return self.rows

    def get_blocks(self):
        return [
            block
            for row in self.rows
            for block in row.get_blocks()]

    def get_layers(self):
        return [
            layer
            for row in self.rows
            for layer in row.get_layers()]

    def todict(self):
        dict_repr = dict(vars(self))
        del dict_repr['block']
        dict_repr['rows'] = [row.todict() for row in self.rows]
        return dict_repr class Row(object):

    def __init__(self, blocks=None):
        self.blocks = blocks or list()

    def get_blocks(self):
        return self.blocks

    def get_layers(self):
        return [
            layer
            for block in self.blocks
            for layer in block.get_layers()]

    def todict(self):
        return {
            'blocks': [
                block.todict()
                for block in self.blocks]} class Layer(object):

    def __init__(self, layer_type,
                 parameters=None, parameter_constraints=None):
        self.layer_type = layer_type
        self.parameters = parameters or dict()
        self.parameter_constraints = parameter_constraints or dict()

    def apply_constraints(self):
        self.parameters.update(self.parameter_constraints)

    def todict(self):
        return dict(vars(self)) class Block(object):

    def __init__(self, layers=None, input_layers=None):
        self.layers = layers or list()
        self.input_layers = input_layers or list()

    def get_layers(self):
        return self.layers

    def todict(self):
        return {
            'input_layers': [
                layer.todict()
                for layer in self.input_layers],
            'layers': [
                layer.todict()
                for layer in self.layers]} class Optimizer(object):

    def __init__(self, optimizer=None, parameters=None):
        self.optimizer = optimizer
        self.parameters = parameters or dict()

    def todict(self):
        return dict(vars(self)) def random_initial_param_value(param, mutation_std=0.1):
    if isinstance(param, dict):
        return _random_dict_param_value(param)
    if isinstance(param, list) or isinstance(param, tuple):
        return _random_list_param_value(param)
    if not isinstance(param, Parameter):
        return param
    if param.values:
        return random_list_element(param.values)

    initial_value = None
    if param.default is not None:
        initial_value = param.default
    elif param.lo is not None:
        initial_value = param.lo
    else:
        initial_value = 0
    return mutate_param(param, initial_value, mutation_std) def random_list_element(elements):
    if len(elements) == 0:
        return None
    if len(elements) == 1:
        return elements[0]
    return elements[rand.randint(0, len(elements) - 1)] def mutate_param(param, value, mutation_std=0.1):
    if isinstance(param, dict):
        return {
            name: mutate_param(nested, value.get(name, None))
            for name, nested in param.items()}
    if not isinstance(param, Parameter):
        return value
    if param.optional and value is not None and rand.random() < 0.5:
        return None
    if param.values:
        if len(set(param.values)) == 1:
            return param.values[0]
        element = random_list_element(param.values)
        while element == value:
            element = random_list_element(param.values)
        return element
    elif param.lo == param.hi:
        return value
    value = value or 0
    std = mutation_std * (param.hi - param.lo)
    if param.param_type == int:
        std = max(1, std)
    new_value = value + param.param_type(numpy.random.normal(0, std, 1)[0])
    while not is_valid_param_value(param, new_value) or new_value == value:
        new_value = value + param.param_type(numpy.random.normal(0, std, 1)[0])
    return new_value
from copy import deepcopy
from random import Random, shuffle
from minos.experiment.experiment import Blueprint
from minos.experiment.training import Training
from minos.model.model import Layout, Row, Layer, Block,\
    Optimizer
from minos.model.parameter import random_initial_param_value,\
    random_list_element, mutate_param
'''
Created on Feb 14, 2017

@author: julien
'''



rand = Random()


def create_random_blueprint(experiment):
    return Blueprint(
        _random_layout(
            experiment.layout,
            experiment.settings,
            experiment.parameters,
            mutation_std=experiment.settings.ga['mutation_std']),
        _random_training(experiment))


def _random_training(experiment):
    training = deepcopy(experiment.training)
    if experiment.settings.is_optimizer_search():
        training.optimizer = _random_optimizer(
            training.optimizer,
            experiment.parameters,
            mutation_std=experiment.settings.ga['mutation_std'])
    return training


def _random_optimizer(optimizer, experiment_parameters, mutation_std=0.1):
    ref_parameters = experiment_parameters.get_optimizers_parameters()
    optimizer_id = optimizer.optimizer if optimizer else None
    if not optimizer_id:
        optimizers = list(ref_parameters.keys())
        optimizer_id = optimizers[rand.randint(0, len(optimizers) - 1)]
    if not optimizer_id in ref_parameters:
        raise Exception('Unknown optimizer id: "%s"' % optimizer_id)
    param_space = deepcopy(ref_parameters[optimizer_id])
    if optimizer:
        param_space.update(optimizer.parameters)
    parameters = {
        name: random_initial_param_value(param, mutation_std=mutation_std)
        for name, param in param_space.items()}
    return Optimizer(optimizer_id, parameters)


def _random_layout(layout, experiment_settings,
                   experiment_parameters, mutation_std=0.1):

    layout = Layout(