# Path: molml/features.py

# 
# Path: molml/crystal.py
# class GenerallizedCrystal(InputTypeMixin, BaseFeature):
#     """
#     A wrapper around other features to facilitate faking crystals.
# 
#     This is done by a brute force expansion of atoms in the molecules based on
#     a given unit cell. This is highly inefficient, but it does set a baseline.
# 
#     Parameters
#     ----------
#     input_type : string, default='list'
#         Specifies the format the input values will be (must be one of 'list'
#         or 'filename').
# 
#     n_jobs : int, default=1
#         Specifies the number of processes to create when generating the
#         features. Positive numbers specify a specifc amount, and numbers less
#         than 1 will use the number of cores the computer has.
# 
#     transformer : BaseFeature, default=None
#         The transformer that will be used once the atoms have been expanded
#         into the crystal.
# 
#     radius : float, default=None
#         The cutoff radius for including unit cells in angstroms.
# 
#     units : list or int, default=None
#         The number of unit cells to include for each axis (if this is an int,
#         then it is the same for all).
# 
#     References
#     ----------
#     Faber, F.; Lindmaa, A; von Lilienfeld, O. A.; Armiento, R. Crystal
#     Structure Representations for Machine Learning Models of Formation
#     Energies. arXiv:1503.07406
#     """
#     ATTRIBUTES = None
#     LABELS = None
# 
#     def __init__(self, input_type=None, n_jobs=1, transformer=None,
#                  radius=None, units=None):
#         super(GenerallizedCrystal, self).__init__(input_type=input_type,
#                                                   n_jobs=n_jobs)
#         self.check_transformer(transformer)
#         self.transformer = transformer
#         if radius is not None and units is not None:
#             msg = "`radius` and `units` can not be set at the same time."
#             raise ValueError(msg)
#         self.radius = radius
#         self.units = units
# 
#         self._old_convert_input = self.transformer.convert_input
#         self.transformer.convert_input = self.convert_input
# 
#     def convert_input(self, X):
#         temp = self._old_convert_input(X)
#         temp.fill_in_crystal(radius=self.radius, units=self.units)
#         return temp
# 
#     def fit(self, X, y=None):
#         return self.transformer.fit(X)
# 
#     def fit_transform(self, X, y=None):
#         return self.transformer.fit_transform(X)
# 
#     def transform(self, X, y=None):
#         return self.transformer.transform(X)
# 
# Path: molml/utils.py
# def load_json(f):
#     """
#     Load the model data from a json file
# 
#     Parameters
#     ----------
#     f : str or file descriptor
#         The path to save the data or a file descriptor to save it to.
# 
#     Returns
#     -------
#     obj : Transformer
#         The transformer object.
#     """
#     try:
#         data = json.load(f)
#     except AttributeError:
#         with open(f, 'r') as in_file:
#             data = json.load(in_file)
#     return _load_transformer(data)


import numpy
from molml.features import CoulombMatrix
from molml.crystal import GenerallizedCrystal
from molml.utils import load_json
    [.25, 1., 0.],
    [0., .3, 1.],
])
H2 = (H2_ELES, H2_COORDS)
H2_FULL = (H2_ELES, H2_COORDS, H2_UNIT)

HCN_ELES = ['H', 'C', 'N']
HCN_COORDS = [
    [-1.0, 0.0, 0.0],
    [0.0, 0.0, 0.0],
    [1.0, 0.0, 0.0],
]
HCN = (HCN_ELES, HCN_COORDS)


if __name__ == "__main__":
    # Example of fitting the Coulomb matrix and then saving it
    feat = CoulombMatrix()
    feat.fit([H2, HCN])
    print("Saving Model")
    feat.save_json("coulomb_model.json")

    print("Loading Model")
    feat2 = load_json("coulomb_model.json")
    print(feat2.transform([H2, HCN]))

    # Example of fitting a generallized crystal with the Coulomb matrix and
    # then saving it
    input_type = ("elements", "coords", "unit_cell")
    radius = 4.1

# Path: molml/features.py

# 
# Path: molml/crystal.py
# class GenerallizedCrystal(InputTypeMixin, BaseFeature):
#     """
#     A wrapper around other features to facilitate faking crystals.
# 
#     This is done by a brute force expansion of atoms in the molecules based on
#     a given unit cell. This is highly inefficient, but it does set a baseline.
# 
#     Parameters
#     ----------
#     input_type : string, default='list'
#         Specifies the format the input values will be (must be one of 'list'
#         or 'filename').
# 
#     n_jobs : int, default=1
#         Specifies the number of processes to create when generating the
#         features. Positive numbers specify a specifc amount, and numbers less
#         than 1 will use the number of cores the computer has.
# 
#     transformer : BaseFeature, default=None
#         The transformer that will be used once the atoms have been expanded
#         into the crystal.
# 
#     radius : float, default=None
#         The cutoff radius for including unit cells in angstroms.
# 
#     units : list or int, default=None
#         The number of unit cells to include for each axis (if this is an int,
#         then it is the same for all).
# 
#     References
#     ----------
#     Faber, F.; Lindmaa, A; von Lilienfeld, O. A.; Armiento, R. Crystal
#     Structure Representations for Machine Learning Models of Formation
#     Energies. arXiv:1503.07406
#     """
#     ATTRIBUTES = None
#     LABELS = None
# 
#     def __init__(self, input_type=None, n_jobs=1, transformer=None,
#                  radius=None, units=None):
#         super(GenerallizedCrystal, self).__init__(input_type=input_type,
#                                                   n_jobs=n_jobs)
#         self.check_transformer(transformer)
#         self.transformer = transformer
#         if radius is not None and units is not None:
#             msg = "`radius` and `units` can not be set at the same time."
#             raise ValueError(msg)
#         self.radius = radius
#         self.units = units
# 
#         self._old_convert_input = self.transformer.convert_input
#         self.transformer.convert_input = self.convert_input
# 
#     def convert_input(self, X):
#         temp = self._old_convert_input(X)
#         temp.fill_in_crystal(radius=self.radius, units=self.units)
#         return temp
# 
#     def fit(self, X, y=None):
#         return self.transformer.fit(X)
# 
#     def fit_transform(self, X, y=None):
#         return self.transformer.fit_transform(X)
# 
#     def transform(self, X, y=None):
#         return self.transformer.transform(X)
# 
# Path: molml/utils.py
# def load_json(f):
#     """
#     Load the model data from a json file
# 
#     Parameters
#     ----------
#     f : str or file descriptor
#         The path to save the data or a file descriptor to save it to.
# 
#     Returns
#     -------
#     obj : Transformer
#         The transformer object.
#     """
#     try:
#         data = json.load(f)
#     except AttributeError:
#         with open(f, 'r') as in_file:
#             data = json.load(in_file)
#     return _load_transformer(data)


# Path: examples/load_save.py
import numpy
from molml.features import CoulombMatrix
from molml.crystal import GenerallizedCrystal
from molml.utils import load_json

    [.25, 1., 0.],
    [0., .3, 1.],
])
H2 = (H2_ELES, H2_COORDS)
H2_FULL = (H2_ELES, H2_COORDS, H2_UNIT)

HCN_ELES = ['H', 'C', 'N']
HCN_COORDS = [
    [-1.0, 0.0, 0.0],
    [0.0, 0.0, 0.0],
    [1.0, 0.0, 0.0],
]
HCN = (HCN_ELES, HCN_COORDS)


if __name__ == "__main__":
    # Example of fitting the Coulomb matrix and then saving it
    feat = CoulombMatrix()
    feat.fit([H2, HCN])
    print("Saving Model")
    feat.save_json("coulomb_model.json")

    print("Loading Model")
    feat2 = load_json("coulomb_model.json")
    print(feat2.transform([H2, HCN]))

    # Example of fitting a generallized crystal with the Coulomb matrix and
    # then saving it
    input_type = ("elements", "coords", "unit_cell")
    radius = 4.1

    feat = CoulombMatrix(input_type=input_type)