Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions src/citrine/informatics/design_spaces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from .data_source_design_space import *
from .design_space import *
from .design_space_settings import *
from .enumerated_design_space import *
from .formulation_design_space import *
from .product_design_space import *
from .hierarchical_design_space import *
from .product_design_space import *
from .subspace import *
from .top_level_design_space import *
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from citrine._rest.engine_resource import EngineResource
from citrine._rest.resource import Resource
from citrine._serialization import properties
from citrine.informatics.data_sources import DataSource
from citrine.informatics.design_spaces.design_space import DesignSpace
from citrine.informatics.design_spaces.subspace import DesignSubspace

__all__ = ['DataSourceDesignSpace']


class DataSourceDesignSpace(EngineResource['DataSourceDesignSpace'], DesignSpace):
class DataSourceDesignSpace(Resource['DataSourceDesignSpace'], DesignSubspace):
"""An enumeration of candidates stored in a data source.

Parameters
Expand All @@ -20,10 +20,9 @@ class DataSourceDesignSpace(EngineResource['DataSourceDesignSpace'], DesignSpace

"""

data_source = properties.Object(DataSource, 'data.instance.data_source')
data_source = properties.Object(DataSource, 'data_source')

typ = properties.String('data.instance.type', default='DataSourceDesignSpace',
deserializable=False)
typ = properties.String('type', default='DataSourceDesignSpace', deserializable=False)

def __init__(self,
name: str,
Expand Down
85 changes: 4 additions & 81 deletions src/citrine/informatics/design_spaces/design_space.py
Original file line number Diff line number Diff line change
@@ -1,87 +1,10 @@
"""Tools for working with design spaces."""
from typing import Optional, Type
from uuid import UUID

from citrine._rest.asynchronous_object import AsynchronousObject
from citrine._serialization import properties
from citrine._serialization.polymorphic_serializable import PolymorphicSerializable
from citrine._serialization.serializable import Serializable
from citrine._session import Session
from citrine.resources.sample_design_space_execution import \
SampleDesignSpaceExecutionCollection


__all__ = ['DesignSpace']


class DesignSpace(PolymorphicSerializable['DesignSpace'], AsynchronousObject):
"""A Citrine Design Space describes the set of materials that can be made.
class DesignSpace:
"""Parent type of the individual design space on the Citrine Platform.

Abstract type that returns the proper type given a serialized dict.
The Predictor class unifies TopLevelDesignSpace types and the DesignSubspace types,
but does not provide any functionality on its own.

"""

uid = properties.Optional(properties.UUID, 'id', serializable=False)
""":Optional[UUID]: Citrine Platform unique identifier"""
name = properties.String('data.name')
description = properties.Optional(properties.String(), 'data.description')

locked_by = properties.Optional(properties.UUID, 'metadata.locked.user',
serializable=False)
""":Optional[UUID]: id of the user whose action cause the design space to
be locked, if it is locked"""
lock_time = properties.Optional(properties.Datetime, 'metadata.locked.time',
serializable=False)
""":Optional[datetime]: date and time at which the resource was locked,
if it is locked"""

@staticmethod
def wrap_instance(subspace_data: dict) -> dict:
"""Insert a serialized embedded design space into an entity envelope.

This facilitates deserialization.
"""
return {
"data": {
"name": subspace_data.get("name", ""),
"description": subspace_data.get("description", ""),
"instance": subspace_data
}
}

_response_key = None
_project_id: Optional[UUID] = None
_session: Optional[Session] = None
_in_progress_statuses = ["VALIDATING", "CREATED"]
_succeeded_statuses = ["READY"]
_failed_statuses = ["INVALID", "ERROR"]

@classmethod
def get_type(cls, data) -> Type[Serializable]:
"""Return the subtype."""
from .data_source_design_space import DataSourceDesignSpace
from .enumerated_design_space import EnumeratedDesignSpace
from .formulation_design_space import FormulationDesignSpace
from .product_design_space import ProductDesignSpace
from .hierarchical_design_space import HierarchicalDesignSpace

return {
'Univariate': ProductDesignSpace,
'ProductDesignSpace': ProductDesignSpace,
'EnumeratedDesignSpace': EnumeratedDesignSpace,
'FormulationDesignSpace': FormulationDesignSpace,
'DataSourceDesignSpace': DataSourceDesignSpace,
'HierarchicalDesignSpace': HierarchicalDesignSpace
}[data['data']['instance']['type']]

@property
def is_locked(self) -> bool:
"""If is_locked is true, edits to the design space will be rejected."""
return self.locked_by is not None

@property
def sample_design_space_executions(self):
"""Start a Sample Design Space Execution using the current Design Space."""
return SampleDesignSpaceExecutionCollection(
project_id=self._project_id, design_space_id=self.uid, session=self._session
)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from typing import Mapping, Optional, Set

from citrine._rest.engine_resource import EngineResource
from citrine._rest.resource import Resource
from citrine._serialization import properties
from citrine.informatics.constraints import Constraint
from citrine.informatics.descriptors import FormulationDescriptor
from citrine.informatics.design_spaces.design_space import DesignSpace
from citrine.informatics.design_spaces.subspace import DesignSubspace

__all__ = ['FormulationDesignSpace']


class FormulationDesignSpace(EngineResource['FormulationDesignSpace'], DesignSpace):
class FormulationDesignSpace(Resource['FormulationDesignSpace'], DesignSubspace):
"""Design space composed of mixtures of ingredients.

Parameters
Expand All @@ -36,23 +36,16 @@ class FormulationDesignSpace(EngineResource['FormulationDesignSpace'], DesignSpa

"""

formulation_descriptor = properties.Object(
FormulationDescriptor,
'data.instance.formulation_descriptor'
)
ingredients = properties.Set(properties.String, 'data.instance.ingredients')
formulation_descriptor = properties.Object(FormulationDescriptor, 'formulation_descriptor')
ingredients = properties.Set(properties.String, 'ingredients')
labels = properties.Optional(properties.Mapping(
properties.String,
properties.Set(properties.String)
), 'data.instance.labels')
constraints = properties.Set(properties.Object(Constraint), 'data.instance.constraints')
resolution = properties.Float('data.instance.resolution')
), 'labels')
constraints = properties.Set(properties.Object(Constraint), 'constraints')
resolution = properties.Float('resolution')

typ = properties.String(
'data.instance.type',
default='FormulationDesignSpace',
deserializable=False
)
typ = properties.String('type', default='FormulationDesignSpace', deserializable=False)

def __init__(self,
name: str,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from citrine.informatics.data_sources import DataSource
from citrine.informatics.dimensions import Dimension
from citrine.informatics.design_spaces import FormulationDesignSpace
from citrine.informatics.design_spaces.design_space import DesignSpace
from citrine.informatics.design_spaces.top_level_design_space import TopLevelDesignSpace
from citrine.informatics.design_spaces.design_space_settings import DesignSpaceSettings

__all__ = [
Expand Down Expand Up @@ -108,7 +108,7 @@ def __repr__(self):
return f"<MaterialNodeDefinition {display_name}>"


class HierarchicalDesignSpace(EngineResource["HierarchicalDesignSpace"], DesignSpace):
class HierarchicalDesignSpace(EngineResource["HierarchicalDesignSpace"], TopLevelDesignSpace):
"""A design space that produces hierarchical candidates representing a material history.

A hierarchical design space always contains a root node that defines the
Expand Down Expand Up @@ -185,41 +185,7 @@ def _post_dump(self, data: dict) -> dict:
if self._settings:
data["settings"] = self._settings.dump()

root_node = data["instance"]["root"]
data["instance"]["root"] = self.__unwrap_node(root_node)

data["instance"]["subspaces"] = [
self.__unwrap_node(sub_node)
for sub_node in data['instance']['subspaces']
]
return data

@classmethod
def _pre_build(cls, data: dict) -> dict:
root_node = data["data"]["instance"]["root"]
data["data"]["instance"]["root"] = cls.__wrap_node(root_node)

data["data"]["instance"]["subspaces"] = [
cls.__wrap_node(sub_node) for sub_node in data['data']['instance']['subspaces']
]

return data

@staticmethod
def __wrap_node(node_data: dict) -> dict:
formulation_subspace = node_data.pop('formulation', None)
if formulation_subspace:
node_data['formulation'] = DesignSpace.wrap_instance(formulation_subspace)
return node_data

@staticmethod
def __unwrap_node(node_data: dict) -> dict:
formulation_subspace = node_data.pop('formulation', None)
if formulation_subspace:
node_data['formulation'] = formulation_subspace['data']['instance']
node_data['formulation']['name'] = formulation_subspace['data']['name']
node_data['formulation']['description'] = formulation_subspace['data']['description']
return node_data

def __repr__(self):
return f'<HierarchicalDesignSpace {self.name}>'
27 changes: 8 additions & 19 deletions src/citrine/informatics/design_spaces/product_design_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@

from citrine._rest.engine_resource import EngineResource
from citrine._serialization import properties
from citrine.informatics.design_spaces.design_space import DesignSpace
from citrine.informatics.design_spaces.top_level_design_space import TopLevelDesignSpace
from citrine.informatics.design_spaces.design_space_settings import DesignSpaceSettings
from citrine.informatics.design_spaces.subspace import DesignSubspace
from citrine.informatics.dimensions import Dimension

__all__ = ['ProductDesignSpace']


class ProductDesignSpace(EngineResource['ProductDesignSpace'], DesignSpace):
class ProductDesignSpace(EngineResource['ProductDesignSpace'], TopLevelDesignSpace):
"""A Cartesian product of design spaces.

Factors can be other design spaces and/or univariate dimensions.
Expand All @@ -21,17 +22,16 @@ class ProductDesignSpace(EngineResource['ProductDesignSpace'], DesignSpace):
the name of the design space
description:str
the description of the design space
subspaces: List[Union[UUID, DesignSpace]]
the list of subspaces to combine, either design spaces defined in-line
or UUIDs that reference design spaces on the platform
subspaces: List[Union[UUID, DesignSubspace]]
the list of subspaces to combine, defined in-line
dimensions: list[Dimension]
univariate dimensions that are factors of the design space; can be enumerated or continuous

"""

_settings = properties.Optional(properties.Object(DesignSpaceSettings), "metadata.settings")

subspaces = properties.List(properties.Object(DesignSpace), 'data.instance.subspaces',
subspaces = properties.List(properties.Object(DesignSubspace), 'data.instance.subspaces',
default=[])
dimensions = properties.Optional(
properties.List(properties.Object(Dimension)), 'data.instance.dimensions'
Expand All @@ -44,11 +44,11 @@ def __init__(self,
name: str,
*,
description: str,
subspaces: Optional[List[Union[UUID, DesignSpace]]] = None,
subspaces: Optional[List[Union[UUID, DesignSubspace]]] = None,
dimensions: Optional[List[Dimension]] = None):
self.name: str = name
self.description: str = description
self.subspaces: List[Union[UUID, DesignSpace]] = subspaces or []
self.subspaces: List[Union[UUID, DesignSubspace]] = subspaces or []
self.dimensions: List[Dimension] = dimensions or []

def _post_dump(self, data: dict) -> dict:
Expand All @@ -57,17 +57,6 @@ def _post_dump(self, data: dict) -> dict:
if self._settings:
data["settings"] = self._settings.dump()

for i, subspace in enumerate(data['instance']['subspaces']):
if isinstance(subspace, dict):
# embedded design spaces are not modules, so only serialize their config
data['instance']['subspaces'][i] = subspace['instance']
return data

@classmethod
def _pre_build(cls, data: dict) -> dict:
for i, subspace_data in enumerate(data['data']['instance']['subspaces']):
if isinstance(subspace_data, dict):
data['data']['instance']['subspaces'][i] = DesignSpace.wrap_instance(subspace_data)
return data

def __str__(self):
Expand Down
Loading
Loading