From ea369b9fbe20885d634d0ad24c405ce8a96b2f3b Mon Sep 17 00:00:00 2001 From: T-Flet Date: Wed, 14 Jul 2021 17:32:51 +0100 Subject: [PATCH] Version bump to 1.1: README updates with accepted paper and more concise example. Change of arguments in the main function (explore_model_space): buffer was renamed to beam, and it now also accepts lists of integers, dynamic_buffer was consequently removed, and some other arguments were reordered. Added checkModelSearchREADMEexample.py for easier future README example updates. Added the KE classes to the default __init__.py exports. Updated requirements.txt and made setup.py read it to ensure dependency installation. --- .gitignore | 1 + GPy_ABCD/Models/modelSearch.py | 58 +++++++------- GPy_ABCD/__init__.py | 3 +- README.rst | 102 +++++++++++-------------- Tests/checkModelSearch.py | 50 +++++++----- Tests/checkModelSearchREADMEexample.py | 28 +++++++ requirements.txt | 17 ++--- setup.py | 2 +- 8 files changed, 145 insertions(+), 116 deletions(-) create mode 100644 Tests/checkModelSearchREADMEexample.py diff --git a/.gitignore b/.gitignore index c36d8c3..0981b3b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .idea/ Tests/Plots Tests/Stats +Tests/Pickles # Byte-compiled / optimized / DLL files diff --git a/GPy_ABCD/Models/modelSearch.py b/GPy_ABCD/Models/modelSearch.py index 7baa88c..ed4ed11 100644 --- a/GPy_ABCD/Models/modelSearch.py +++ b/GPy_ABCD/Models/modelSearch.py @@ -2,7 +2,7 @@ from copy import deepcopy from operator import attrgetter from multiprocessing import Pool, cpu_count -from typing import Callable, List, Dict, Tuple +from typing import Callable, List, Dict, Tuple, Union from GPy_ABCD.KernelExpressions.base import KernelExpression from GPy_ABCD.KernelExpansion.grammar import start_kernels, production_rules, make_simple_kexs, expand @@ -11,11 +11,11 @@ # TODO: -# - group input parameters into dictionaries +# - group input parameters into dictionaries? # - make utility functions take in the kernel expression (or even full model) so that further criteria may be applied (e.g. presence of specific kernels etc)? # - focus on documenting end-user and generic developer functions etc in sphinx # - make the dynamic buffer configurable, or even allow inputting a list of numbers of models to keep per round -# - make an interactive mode which asks whether to go further, retaining how many etc +# - make an interactive/interruptable mode which asks whether to go further, retaining how many etc # - allow the model lists in each round to be fit in batches, with interactive request to continue (timed response maybe) # - show a live count of models fitted so far in each round (probably by batches) @@ -39,33 +39,32 @@ def fit_mods_parallel_processes(X, Y, k_exprs, restarts = 5, optimiser = GPy_opt def explore_model_space(X, Y, - start_kernels: Dict[str, List[KernelExpression]] = start_kernels['Default'], p_rules: Dict[str, List[Callable]] = production_rules['Default'], utility_function: Callable = BIC, - rounds: int = 2, buffer: int = 4, dynamic_buffer: bool = True, verbose: bool = True, - restarts: int = 5, model_list_fitter: Callable = fit_mods_parallel_processes, optimiser: str = GPy_optimisers[0]) -> Tuple[List[GPModel], List[List[GPModel]], List[KernelExpression], List[GPModel], List[GPModel]]: + start_kernels: List[Union[str, KernelExpression]] = start_kernels['Default'], p_rules: List[Callable] = production_rules['Default'], utility_function: Callable = BIC, + rounds: int = 2, beam: Union[int, List[int]] = [3, 2, 1], restarts: int = 5, + model_list_fitter: Callable = fit_mods_parallel_processes, optimiser: str = GPy_optimisers[0], + verbose: bool = True) -> Tuple[List[GPModel], List[List[GPModel]], List[KernelExpression], List[GPModel], List[GPModel]]: '''Perform `rounds` rounds of kernel expansion followed by model fit starting from the given `start_kernels` with and expanding the best `buffer` of them with `p_rules` production rules NOTE: if the default `model_list_fitter` argument `fit_mods_parallel_processes` is used the function should be called from within a :code:`if __name__ == '__main__':` for full OS-agnostic use. - :param start_kernels: the starting kernels - :type start_kernels: Dict[str, List[KernelExpression]] + :param start_kernels: the 0th-round starting kernels + :type start_kernels: List[Union[str, KernelExpression]] :param p_rules: the production rules applied at each expansion - :type p_rules: Dict[str, List[Callable]] + :type p_rules: List[Callable] :param utility_function: model-scoring utility function: inputs are log-likelihood (ll), number of data points (n) and number of estimated parameters (k); AIC, AICc and BIC functions exported; arbitrary ones accepted :type utility_function: Callable :param rounds: number of rounds of model exploration :type rounds: Int - :param buffer: number of best fit-models' kernels to expand each round - :type buffer: Int - :param dynamic_buffer: if True: buffer is increased by 2 at the beginning and decreased by 1 in the first two and last two rounds - :type dynamic_buffer: Boolean - :param verbose: produce verbose logs - :type verbose: Boolean + :param beam: number of best fit-models' kernels to expand each round, either an integer or a list of integers; in the latter case, if its length is less than rounds then the last value will be repeated until required + :type beam: Union[Int, List[Int]] :param restarts: number of GPy model-fitting restarts with different parameters :type restarts: Int :param model_list_fitter: function handling the fitting of a list of kernels to the same data; this is where parallelisation implementation can be changed :type model_list_fitter: Callable :param optimiser: identifying string for the model optimiser function; GPy 1.9.9 optimiser strings (GPy > paramz > optimization > optimization.py): 'lbfgsb', 'org-bfgs', 'fmin_tnc', 'scg', 'simplex', 'adadelta', 'rprop', 'adam' :type optimiser: str + :param verbose: produce verbose logs + :type verbose: Boolean :rtype: (sorted_models: [GPModel], tested_models: [[GPModel]], tested_k_exprs: [KernelExpression], expanded: [GPModel], not_expanded: [GPModel]) ''' @@ -82,21 +81,25 @@ def score(m): return m.compute_utility(utility_function) expanded = [] tested_k_exprs = deepcopy(start_kexs) - original_buffer = buffer - if dynamic_buffer: buffer += 2 # Higher for the 1st round - if verbose: print(f'(All models are listed by descending {utility_function.__name__})\n\nBest round-{0} models [{len(tested_models[0])} new; {buffer} moving forward]: {print_k_list(not_expanded[:buffer])}') + # Handle beam argument: ensure it is a list of integers of length rounds + if isinstance(beam, list) and all(isinstance(x, int) for x in beam): + beam = beam + ([beam[-1]] * more) if (more := rounds - len(beam)) > 0 else beam[:rounds] + elif isinstance(beam, int): beam = [beam] * rounds + else: raise TypeError(f'The given beam argument ({beam}) is neither an integer nor a list of integers') + + if verbose: print(f'(All models are listed by descending {utility_function.__name__})\n\nBest round-{0} models [{len(tested_models[0])} new; {beam[0]} moving forward]: {print_k_list(not_expanded[:beam[0]])}') sorted_models, tested_models, tested_k_exprs, expanded, not_expanded = model_search_rounds(X, Y, - original_buffer, sorted_models, tested_models, tested_k_exprs, expanded, not_expanded, model_list_fitter, - p_rules, utility_function, restarts, rounds, buffer, dynamic_buffer, verbose, optimiser) + sorted_models, tested_models, tested_k_exprs, expanded, not_expanded, + model_list_fitter, p_rules, utility_function, rounds, beam, restarts, optimiser, verbose) - if verbose: print(f'\nBest models overall: {print_k_list(sorted_models[:original_buffer])}\n') + if verbose: print(f'\nBest models overall: {print_k_list(sorted_models[:beam[0]])}\n') return sorted_models, tested_models, tested_k_exprs, expanded, not_expanded # This function is split from the above both for tidiness and to allow the possibility of continuing a search if desired -def model_search_rounds(X, Y, original_buffer, sorted_models, tested_models, tested_k_exprs, expanded, not_expanded, - model_list_fitter, p_rules, utility_function, restarts, rounds, buffer, dynamic_buffer, verbose, optimiser): +def model_search_rounds(X, Y, sorted_models, tested_models, tested_k_exprs, expanded, not_expanded, + model_list_fitter, p_rules, utility_function, rounds, beam, restarts, optimiser, verbose): ''' See explore_model_space description and source code for argument explanation and context @@ -104,17 +107,16 @@ def model_search_rounds(X, Y, original_buffer, sorted_models, tested_models, tes ''' def score(m): return m.compute_utility(utility_function) - for d in range(1, rounds + 1): - new_k_exprs = [kex for kex in unique(flatten([expand(mod.kernel_expression, p_rules) for mod in not_expanded[:buffer]])) if kex not in tested_k_exprs] + for r, b in zip(range(1, rounds + 1), beam): + new_k_exprs = [kex for kex in unique(flatten([expand(mod.kernel_expression, p_rules) for mod in not_expanded[:b]])) if kex not in tested_k_exprs] tested_models.append(sorted(model_list_fitter(X, Y, new_k_exprs, restarts, optimiser), key = score)) # tested_models[d] sorted_models = sorted(flatten(tested_models), key = attrgetter('cached_utility_function')) # Merge-sort would be applicable - expanded += not_expanded[:buffer] + expanded += not_expanded[:b] not_expanded = diff(sorted_models, expanded) # More efficient than sorting another whole list tested_k_exprs += new_k_exprs - buffer -= 1 if dynamic_buffer and (d <= 2 or d in range(rounds - 1, rounds + 1)) else 0 - if verbose: print(f'Round-{d} models [{len(tested_models[d])} new; {buffer} moving forward]:\n\tBest new: {print_k_list(tested_models[d][:original_buffer])}\n\tBest so far: {print_k_list(sorted_models[:original_buffer])}\n\tBest not-already-expanded: {print_k_list(not_expanded[:buffer])}') + if verbose: print(f'Round-{r} models [{len(tested_models[r])} new; {b} moving forward]:\n\tBest new: {print_k_list(tested_models[r][:beam[0]])}\n\tBest so far: {print_k_list(sorted_models[:beam[0]])}\n\tBest not-already-expanded: {print_k_list(not_expanded[:b])}') return sorted_models, tested_models, tested_k_exprs, expanded, not_expanded diff --git a/GPy_ABCD/__init__.py b/GPy_ABCD/__init__.py index 97d9b18..1ee717f 100644 --- a/GPy_ABCD/__init__.py +++ b/GPy_ABCD/__init__.py @@ -1,6 +1,6 @@ """GPy-ABCD - Basic implementation with GPy of an Automatic Bayesian Covariance Discovery (ABCD) system""" -__version__ = '1.0.3' # Change it in setup.py too +__version__ = '1.1' # Change it in setup.py too __author__ = 'Thomas Fletcher ' # __all__ = [] @@ -10,5 +10,6 @@ from GPy_ABCD.Util.modelUtil import BIC, AIC, AICc, fit_kex, fit_GPy_kern, model_printout, GPy_optimisers from GPy_ABCD.KernelExpansion.grammar import start_kernels, production_rules_by_type, production_rules from GPy_ABCD.KernelExpansion.kernelOperations import base_kerns, base_sigmoids +from GPy_ABCD.KernelExpressions.all import SumKE, ProductKE, ChangeKE diff --git a/README.rst b/README.rst index 78f8299..7e2407b 100644 --- a/README.rst +++ b/README.rst @@ -23,21 +23,15 @@ GPy-ABCD Basic implementation with GPy of an Automatic Bayesian Covariance Discovery (ABCD) system -Briefly: a modelling system which consists in exploring a space of compositional kernels -(i.e. covariances of gaussian processes) built from a few carefully selected base ones, -returning the best fitting gaussian process models using them and generating simple text -descriptions of the fits based on the functional shapes of the final composed covariance -kernels and parameter values. +Briefly: ABCD is a modelling system which consists in exploring a space of compositional kernels +(i.e. covariances of Gaussian Processes) constructed by iteratively combining a small set of base ones, +returning the best fitting models using them, and capable of generating simple text descriptions of the +fits based on the identified functional shapes. -See the picture in `Usage` below to get a feeling for it and -read one of the papers on the original ABCD for further details: +See the picture in `Usage` below for an example input/output and read the paper for further details: -Lloyd, James Robert; Duvenaud, David Kristjanson; Grosse, Roger Baker; Tenenbaum, Joshua B.; Ghahramani, Zoubin (2014): -Automatic construction and natural-language description of nonparametric regression models. -In: National Conference on Artificial Intelligence, 7/27/2014, pp. 1242-1250. -Available online at https://academic.microsoft.com/paper/1950803081. - -(A paper on GPy-ABCD and its differences from the original ABCD is planned) +`Fletcher, T., Bundy, A., & Nuamah, K. . GPy-ABCD: A Configurable Automatic Bayesian Covariance Discovery Implementation. +8th ICML Workshop on Automated Machine Learning (2021) `_ @@ -58,46 +52,37 @@ the function should be called from within a :code:`if __name__ == '__main__':` f A minimal example to showcase the various parameters follows: -:: +.. code-block:: Python import numpy as np from GPy_ABCD import * + if __name__ == '__main__': # Example data X = np.linspace(-10, 10, 101)[:, None] - Y = np.cos( (X - 5) / 2 )**2 * X * 2 + np.random.randn(101, 1) + Y = np.cos((X - 5) / 2) ** 2 * X * 2 + np.random.randn(101, 1) - # Main function call with suggested arguments + # Main function call with default arguments best_mods, all_mods, all_exprs, expanded, not_expanded = explore_model_space(X, Y, - start_kernels = start_kernels['Default'], p_rules = production_rules['Default'], utility_function = BIC, - rounds = 2, buffer = 3, dynamic_buffer = False, verbose = True, - restarts = 4, model_list_fitter = fit_mods_parallel_processes, optimiser = GPy_optimisers[0]) + start_kernels = start_kernels['Default'], p_rules = production_rules['Default'], + utility_function = BIC, rounds = 2, beam = [3, 2, 1], restarts = 5, + model_list_fitter = fit_mods_parallel_processes, optimiser = GPy_optimisers[0], + verbose = True) - # Typical output exploration printout + print('\nFull lists of models by round:') for mod_depth in all_mods: print(', '.join([str(mod.kernel_expression) for mod in mod_depth]) + f'\n{len(mod_depth)}') - print() - # Explore the best 3 models in detail - from matplotlib import pyplot as plt - for bm in best_mods[:3]: model_printout(bm) - # NOTE: model_printout is a provided convenience function, its definition showcases model parameter access: - # def model_printout(m): - # print(m.kernel_expression) - # print(m.model.kern) - # print(f'Log-Lik: {m.model.log_likelihood()}') - # print(f'{m.cached_utility_function_type}: {m.cached_utility_function}') - # m.model.plot() - # print(m.interpret()) - - # Perform some predictions - predict_X = np.linspace(10, 15, 10)[:, None] - preds = best_mods[0].predict(predict_X) - print(preds) + print('\n\nTop-3 models\' details:') + for bm in best_mods[:3]: + model_printout(bm) # See the definition of this convenience function for examples of model details' extraction + print('Prediction at X = 11:', bm.predict(np.array([11])[:, None]), '\n') + from matplotlib import pyplot as plt plt.show() + .. figure:: selected_output_example.png :align: center :figclass: align-center @@ -121,7 +106,8 @@ main model search function plus a few convenient tools (refer to the section bel - The frozensets of :code:`base_kerns` and :code:`base_sigmoids` (The purpose of exporting elements in the last 3 lines is for users to create alternative sets of production -rules and starting kernels lists by mixing kernel expressions and raw strings of base kernels) +rules and starting kernels lists by mixing kernel expressions and raw strings of base kernels; +see the definitions of entries of the :code:`start_kernels` and :code:`production_rules` dictionaries for examples) @@ -134,37 +120,37 @@ However, briefly, it consists in exploring a space of compositional kernels buil returning the best fitting models using them and generating simple text interpretations of the fits based on the functional shapes of the final composed covariance kernels and parameter values. -The key pillars of this project's ABCD system implementation structure are the following: +The core components of this project's ABCD implementation are the following: - :code:`Kernels.baseKernels` contains the "mathematical" base kernels (i.e. GPy kernel objects) for the whole machinery - - Some of the base kernels are simply wrapped GPy-provided kernels (White-Noise, Constant and Squared-Exponential) - - The others are either not present in GPy's default arsenal or are improved versions of ones which are (Linear which can identify polynomial roots and purely-Periodic standard-periodic kernel) - - It contains sigmoidal kernels (both base sigmoids and indicator-like ones, i.e. sigmoidal hat/well) which are not used directly in the symbolic expressions but are substituted in by change-type kernels - - It contains change-point and change-window kernels which use the aforementioned sigmoidals + - Some of the base kernels are simply wrapped GPy-provided kernels (White-Noise, Constant and Squared-Exponential) + - The others are either not present in GPy's default arsenal or are improved versions of ones which are (Linear which can identify polynomial roots and purely-Periodic standard-periodic kernel) + - It contains sigmoidal kernels (both base sigmoids and indicator-like ones, i.e. sigmoidal hat/well) which are not used directly in the symbolic expressions but are substituted in by change-type kernels + - It contains change-point and change-window kernels which use the aforementioned sigmoidals - :code:`KernelExpression` contains the "symbolic" kernel classes constituting the nodes with which to build complex kernel expressions in the form of trees - - The non-abstract kernel expression classes are :code:`SumKE`, :code:`ProductKE` and :code:`ChangeKE` - - :code:`SumKE` and :code:`ProductKE` are direct subclasses of the abstract class `SumOrProductKE` and only really differ in how they self-simplify and distribute over the other - - :code:`ChangeKE` could be split into separate change-point and change-window classes, but a single argument difference allows full method overlap - - :code:`SumOrProductKE` and :code:`ChangeKE` are direct subclasses of the abstract base class :code:`KernelExpression` + - The non-abstract kernel expression classes are :code:`SumKE`, :code:`ProductKE` and :code:`ChangeKE` + - :code:`SumKE` and :code:`ProductKE` are direct subclasses of the abstract class `SumOrProductKE` and only really differ in how they self-simplify and distribute over the other + - :code:`ChangeKE` could be split into separate change-point and change-window classes, but a single argument difference allows full method overlap + - :code:`SumOrProductKE` and :code:`ChangeKE` are direct subclasses of the abstract base class :code:`KernelExpression` - The above kernel expression classes have a wide variety of methods providing the following general functionality in order to make the rest of the project light of ad-hoc functions: - - They self-simplify when modified through the appropriate methods (they are symbolic expressions after all) - - They can produce GPy kernel objects - - They can line-up with and absorb fit model parameters from a matching GPy object - - They can rearrange to a sum-of-products form - - They can generate text interpretations of their sum-of-products form + - They self-simplify when modified through the appropriate methods (they are symbolic expressions after all) + - They can produce GPy kernel objects + - They can line-up with and absorb fit model parameters from a matching GPy object + - They can rearrange to a sum-of-products form + - They can generate text interpretations of their sum-of-products form - :code:`KernelExpansion.grammar` contains the various production rules and default starting kernel lists used in model space exploration - :code:`Models.modelSearch` contains the system front-end elements: - - The :code:`GPModel` class, which is where the GPy kernels/models interact with the symbolic kernel expressions - - The aforementioned functions to fit lists of models :code:`fit_mods_not_parallel` and :code:`fit_mods_parallel_processes` - - The :code:`explore_model_space` function, which is the point of it all - - The :code:`model_search_rounds` function, which is used by the above but also meant to continue searching by building on past exploration results + - The :code:`GPModel` class, which is where the GPy kernels/models interact with the symbolic kernel expressions + - The aforementioned functions to fit lists of models :code:`fit_mods_not_parallel` and :code:`fit_mods_parallel_processes` + - The :code:`explore_model_space` function, which is the point of it all + - The :code:`model_search_rounds` function, which is used by the above but also meant to continue searching by building on past exploration results + +Note: a :code:`config.py` file is present, and it contains a few global-behaviour-altering flags (e.g. enabling/disabling the Squared-Exponential kernel) -Note: a :code:`config.py` file is present, and it contains a few global-behaviour-altering flags; -these may become more easily accessible in future versions (e.g. as additional optional arguments to :code:`model_search_rounds`) Further Notes diff --git a/Tests/checkModelSearch.py b/Tests/checkModelSearch.py index ab29983..5114700 100644 --- a/Tests/checkModelSearch.py +++ b/Tests/checkModelSearch.py @@ -1,4 +1,5 @@ import numpy as np +import pickle from GPy_ABCD.Models.modelSearch import * from GPy_ABCD.Util.modelUtil import * @@ -10,7 +11,7 @@ if __name__ == '__main__': # np.seterr(all='raise') # Raise exceptions instead of RuntimeWarnings. The exceptions can then be caught by the debugger - ## Forced data (using X and Y from synthetic_datasets otherwise + ## Forced data (using X and Y from synthetic_datasets otherwise) # X = np.linspace(-10, 10, 101)[:, None] # Y = np.cos((X - 5) / 2) ** 2 * X * 2 + np.random.randn(101, 1) @@ -37,29 +38,40 @@ ## Model search best_mods, all_mods, all_exprs, expanded, not_expanded = explore_model_space(X, Y, - start_kernels = start_kernels['Default'], p_rules = production_rules['Default'], utility_function = BIC, - rounds = 1, buffer = 3, dynamic_buffer = False, verbose = True, - restarts = 4, model_list_fitter = fit_mods_parallel_processes, optimiser = GPy_optimisers[0]) + start_kernels = start_kernels['Default'], p_rules = production_rules['Default'], utility_function = BIC, + rounds = 2, beam = [3, 2, 1], restarts = 5, + model_list_fitter = fit_mods_parallel_processes, optimiser = GPy_optimisers[0], + verbose = True) + # with open(f'./Pickles/TEST', 'wb') as f: pickle.dump({'a': best_mods[:10]}, f) + # with open(f'./Pickles/TEST', 'rb') as f: IMPORTED = pickle.load(f) + # print(IMPORTED) - for mod_depth in all_mods: print(', '.join([str(mod.kernel_expression) for mod in mod_depth]) + f'\n{len(mod_depth)}') - + # for mod_depth in all_mods: print(', '.join([str(mod.kernel_expression) for mod in mod_depth]) + f'\n{len(mod_depth)}') + # print() + # + # + # from matplotlib import pyplot as plt + # for bm in best_mods[:3]: + # model_printout(bm) + # # print('2022:', bm.predict(np.array([2022])[:, None])) + # + # + # # predict_X = np.linspace(10, 15, 10)[:, None] + # # preds = best_mods[0].predict(predict_X) + # # print(preds) + # + # + # plt.show() + + + + # bms2 = sorted(best_mods[:5], key = lambda m: LA_LOO(*m._ordered_score_ps())) + # for bm in bms2[:3]: model_printout(bm) + # plt.show() - from matplotlib import pyplot as plt - for bm in best_mods[:3]: - model_printout(bm) - # print('2022:', bm.predict(np.array([2022])[:, None])) - - - # predict_X = np.linspace(10, 15, 10)[:, None] - # preds = best_mods[0].predict(predict_X) - # print(preds) - - - plt.show() - # save_one_run(dataset, correct_k, best_mods, all_mods, all_exprs) diff --git a/Tests/checkModelSearchREADMEexample.py b/Tests/checkModelSearchREADMEexample.py new file mode 100644 index 0000000..8692e71 --- /dev/null +++ b/Tests/checkModelSearchREADMEexample.py @@ -0,0 +1,28 @@ +import numpy as np +from GPy_ABCD import * + + +if __name__ == '__main__': + # Example data + X = np.linspace(-10, 10, 101)[:, None] + Y = np.cos((X - 5) / 2) ** 2 * X * 2 + np.random.randn(101, 1) + + # Main function call with default arguments + best_mods, all_mods, all_exprs, expanded, not_expanded = explore_model_space(X, Y, + start_kernels = start_kernels['Default'], p_rules = production_rules['Default'], + utility_function = BIC, rounds = 2, beam = [3, 2, 1], restarts = 5, + model_list_fitter = fit_mods_parallel_processes, optimiser = GPy_optimisers[0], + verbose = True) + + print('\nFull lists of models by round:') + for mod_depth in all_mods: print(', '.join([str(mod.kernel_expression) for mod in mod_depth]) + f'\n{len(mod_depth)}') + + print('\n\nTop-3 models\' details:') + for bm in best_mods[:3]: + model_printout(bm) # See the definition of this convenience function for examples of model details' extraction + print('Prediction at X = 11:', bm.predict(np.array([11])[:, None]), '\n') + + from matplotlib import pyplot as plt + plt.show() + + diff --git a/requirements.txt b/requirements.txt index 2edf5e7..57f21ab 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,8 @@ -Cython>=0.29.14 -paramz>=0.9.5 -pandas>=0.25.2 -matplotlib>=3.1.1 -numpy>=1.17.3 -plotnine>=0.6.0 -pytest>=5.3.2 -GPy>=1.9.9 -ipython>=7.11.1 +# paramz>=0.9.5 +plotnine>=0.7.1 +numpy>=1.19.2 +matplotlib>=3.3.2 +scipy>=1.6.2 +pandas>=1.2.4 +GPy>=1.10.0 +# ipython>=7.25.0 diff --git a/setup.py b/setup.py index fad4bad..c0e0e0b 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ def read_requirements(): setup( name = 'GPy-ABCD', - version = '1.0.3', # Change it in __init__.py too + version = '1.1', # Change it in __init__.py too url = 'https://github.com/T-Flet/GPy-ABCD', license = 'BSD 3-Clause',