Source code for boolean_cayley_graphs.classify_in_parallel

r"""
Classification in parallel using fork
=====================================

The ``classify_in_parallel`` module defines functions that use ``sage.parallel`` and ``fork``
to save Cayley graph classifications or partial classifications in parallel.

AUTHORS:

- Paul Leopardi (2017-05-22)

"""
#*****************************************************************************
#       Copyright (C) 2016 Paul Leopardi paul.leopardi@gmail.com
#
#  Distributed under the terms of the GNU General Public License (GPL)
#  as published by the Free Software Foundation; either version 2 of
#  the License, or (at your option) any later version.
#                  http://www.gnu.org/licenses/
#*****************************************************************************

from sage.functions.other import Function_ceil
from sage.parallel.decorate import parallel

from boolean_cayley_graphs.bent_function_cayley_graph_classification import BentFunctionCayleyGraphClassification
from boolean_cayley_graphs.bent_function_cayley_graph_classification import BentFunctionCayleyGraphClassPart
from boolean_cayley_graphs.bent_function import BentFunction


[docs]def call_in_parallel( f, list_of_tuples, ncpus): r""" Call the function `f` in parallel INPUT: - ``f`` -- Function to call. - ``list_of_tuples`` -- A list of tuples to use as arguments to ``f``. - ``ncpus`` -- Integer. Default=4. The number of cpus to use in parallel. OUTPUT: A list of tuples. Each tuple contains an (args,keywds) pair, and a result. EFFECT: .. Note: :: See http://doc.sagemath.org/html/en/reference/parallel/sage/parallel/decorate.html EXAMPLE: :: sage: from boolean_cayley_graphs.classify_in_parallel import call_in_parallel sage: summ = lambda L: add(L) sage: call_in_parallel(summ,[((1,2),),((5,4),),((3,3),)],2) [((((1, 2),), {}), 3), ((((5, 4),), {}), 9), ((((3, 3),), {}), 6)] """ parallelize = parallel(p_iter='fork', ncpus=ncpus) return list(parallelize(f)(list_of_tuples))
[docs]def classify( n, form): r""" Given an algebraic normal form of a bent function, construct the corresponding Cayley graph classification. INPUT: - ``n`` -- Integer. Tuple number. - ``form`` -- A Boolean function or an algebraic normal form. OUTPUT: The Cayley graph classification corresponding to the bent function defined by ``form``. .. Note: :: The parameters ``n`` and ``form`` as used here conform to the interface used by ``parallel``. See http://doc.sagemath.org/html/en/reference/parallel/sage/parallel/decorate.html EXAMPLE: :: sage: from boolean_cayley_graphs.bent_function import BentFunction sage: from boolean_cayley_graphs.classify_in_parallel import classify sage: bentf = BentFunction([0,0,0,1]) sage: bentf.algebraic_normal_form() x0*x1 sage: classify(0, bentf).report() Algebraic normal form of Boolean function: x0*x1 Function is bent. <BLANKLINE> <BLANKLINE> SDP design incidence structure t-design parameters: (True, (1, 4, 1, 1)) <BLANKLINE> Classification of Cayley graphs and classification of Cayley graphs of duals are the same: <BLANKLINE> There are 2 extended Cayley classes in the extended translation class. """ return BentFunctionCayleyGraphClassification.from_function(BentFunction(form))
[docs]def classify_in_parallel( list_of_f, start=0, stop=None, ncpus=4): r""" In parallel, construct a list of Cayley graph classifications corresponding to a list of bent functions. INPUT: - ``list_of_f`` -- List of forms or bent functions. - ``start`` -- Integer. Default=0. Index of start position in the list. - ``stop`` -- Integer. Default=None. Index after end position, or ``None`` if whole remaining list. - ``ncpus`` -- Integer. Default=4. The number of cpus to use in parallel. OUTPUT: A list of tuples. Each tuple contains an (args,keywds) pair of arguments to `classify`, and a classification result. EXAMPLE: :: sage: from boolean_cayley_graphs.bent_function import BentFunction sage: from boolean_cayley_graphs.classify_in_parallel import classify_in_parallel sage: bentf0 = BentFunction([0,0,0,1]) sage: bentf0.algebraic_normal_form() x0*x1 sage: bentf1 = BentFunction([0,0,1,0]) sage: bentf1.algebraic_normal_form() x0*x1 + x1 sage: classes = classify_in_parallel([bentf0,bentf1],ncpus=2) sage: cl = classes[0][1] if classes[0][0][0][0] == 0 else classes[1][1] sage: cl.report() Algebraic normal form of Boolean function: x0*x1 Function is bent. <BLANKLINE> <BLANKLINE> SDP design incidence structure t-design parameters: (True, (1, 4, 1, 1)) <BLANKLINE> Classification of Cayley graphs and classification of Cayley graphs of duals are the same: <BLANKLINE> There are 2 extended Cayley classes in the extended translation class. """ if stop == None: stop = len(list_of_f) list_of_tuples = [ ((n, list_of_f[n])) for n in range(start, stop)] return call_in_parallel( classify, list_of_tuples, ncpus)
[docs]def save_one_classification( name, form, dir=None): r""" Given an algebraic normal form of a bent function, construct and save the corresponding Cayley graph classification. INPUT: - ``name`` -- String. Name to use with ``save_mangled`` to save the classification. - ``form`` -- A Boolean function or an algebraic normal form. - ``dir`` -- string, optional. The directory where the object is to be saved. Default is None, meaning the current directory. OUTPUT: A copy of the string ``name``. EFFECT: Uses ``name`` to save the classification corresponding to ``form``. EXAMPLE: :: sage: import os sage: from boolean_cayley_graphs.bent_function import BentFunction sage: from boolean_cayley_graphs.bent_function_cayley_graph_classification import BentFunctionCayleyGraphClassification as BFC sage: from boolean_cayley_graphs.classify_in_parallel import save_one_classification sage: R2.<x1,x2> = BooleanPolynomialRing(2) sage: p = x1+x2+x1*x2 sage: f = BentFunction(p) sage: name = 'test_save_one_classification' sage: d = tmp_dir() sage: s = save_one_classification(name, f, dir=d) sage: c = BFC.load_mangled(name, dir=d) sage: c.report() Algebraic normal form of Boolean function: x0*x1 + x0 + x1 Function is bent. <BLANKLINE> <BLANKLINE> SDP design incidence structure t-design parameters: (True, (1, 4, 1, 1)) <BLANKLINE> Classification of Cayley graphs and classification of Cayley graphs of duals are the same: <BLANKLINE> There are 2 extended Cayley classes in the extended translation class. sage: print(BFC.mangled_name(name)) BentFunctionCayleyGraphClassification__test_save_one_classification sage: BFC.remove_mangled(name, dir=d) sage: os.rmdir(d) """ c = BentFunctionCayleyGraphClassification.from_function( BentFunction(form)) c.save_mangled( name, dir=dir) return name
[docs]def save_classifications_in_parallel( name_prefix, list_of_f, start=0, stop=None, ncpus=4, dir=None): r""" In parallel, construct and save a number of Cayley graph classifications corresponding to a list of bent functions. INPUT: - ``name_prefix`` -- String. Name prefix to use with ``save_mangled`` to save each classification. - ``list_of_f`` -- List of forms or bent functions. - ``start`` -- Integer. Default=0. Index of start position in the list. - ``stop`` -- Integer. Default=None. Index after end position, or ``None`` if whole remaining list. - ``ncpus`` -- Integer. Default=4. The number of cpus to use in parallel. - ``dir`` -- string, optional. The directory where the object is to be saved. Default is None, meaning the current directory. OUTPUT: EFFECT: Uses ``name`` to save the classifications corresponding to ``list_of_f``. EXAMPLE: :: sage: from boolean_cayley_graphs.bent_function import BentFunction sage: from boolean_cayley_graphs.bent_function_cayley_graph_classification import BentFunctionCayleyGraphClassification as BFC sage: from boolean_cayley_graphs.classify_in_parallel import save_classifications_in_parallel sage: bentf0 = BentFunction([0,0,0,1]) sage: bentf0.algebraic_normal_form() x0*x1 sage: bentf1 = BentFunction([0,0,1,0]) sage: bentf1.algebraic_normal_form() x0*x1 + x1 sage: name_prefix = 'test_save_classifications_in_parallel' sage: d = tmp_dir() sage: names = save_classifications_in_parallel(name_prefix, [bentf0,bentf1], ncpus=2, dir=d) sage: name_1 = name_prefix + '_1' sage: c = BFC.load_mangled(name_1, dir=d) sage: c.report() Algebraic normal form of Boolean function: x0*x1 + x1 Function is bent. <BLANKLINE> <BLANKLINE> SDP design incidence structure t-design parameters: (True, (1, 4, 1, 1)) <BLANKLINE> Classification of Cayley graphs and classification of Cayley graphs of duals are the same: <BLANKLINE> There are 2 extended Cayley classes in the extended translation class. sage: for n in range(2): ....: name = name_prefix + '_' + str(n) ....: print(BFC.mangled_name(name)) ....: BFC.remove_mangled(name, dir=d) ....: BentFunctionCayleyGraphClassification__test_save_classifications_in_parallel_0 BentFunctionCayleyGraphClassification__test_save_classifications_in_parallel_1 sage: os.rmdir(d) """ if stop == None: stop = len(list_of_f) list_of_tuples = [ ((name_prefix + '_' + str(n), list_of_f[n], dir)) for n in range(start, stop)] return call_in_parallel( save_one_classification, list_of_tuples, ncpus)
[docs]def save_one_class_part( name, bentf, c_start, c_stop, dir=None): r""" Construct and save a partial Cayley graph classification corresponding to a given bent function. INPUT: - ``name`` -- Name to use with ``save_mangled`` to save the class part. - ``bentf`` -- A Bent function. - ``c_start`` -- smallest value of `c` to use for extended translates. Integer. Default is 0. - ``c_stop`` -- one more than largest value of `c` to use for extended translates. Integer. Default is ``None``, meaning use all remaining values. - ``dir`` -- string, optional. The directory where the object is to be saved. Default is None, meaning the current directory. OUTPUT: A copy of the string ``name``. EFFECT: Uses ``name`` to save the partial classification corresponding to ``bentf``. EXAMPLE: :: sage: import os sage: from boolean_cayley_graphs.bent_function import BentFunction sage: from boolean_cayley_graphs.bent_function_cayley_graph_classification import BentFunctionCayleyGraphClassPart as BFCP sage: from boolean_cayley_graphs.classify_in_parallel import save_one_class_part sage: R2.<x1,x2> = BooleanPolynomialRing(2) sage: p = x1+x2+x1*x2 sage: f = BentFunction(p) sage: name = 'test_save_one_class_part' sage: d = tmp_dir() sage: s = save_one_class_part(name, f, c_start=1, c_stop=2, dir=d) sage: p1 = BFCP.load_mangled(name, dir=d) sage: dict(sorted(p1.__dict__.items())) {'algebraic_normal_form': x0*x1 + x0 + x1, 'bent_cayley_graph_index_matrix': [0 0 1 0], 'c_start': 1, 'cayley_graph_class_list': ['CK', 'C~'], 'dual_cayley_graph_index_matrix': [0 0 1 0], 'weight_class_matrix': [0 0 1 0]} sage: print(BFCP.mangled_name(name)) BentFunctionCayleyGraphClassPart__test_save_one_class_part sage: BFCP.remove_mangled(name, dir=d) sage: os.rmdir(d) """ p = BentFunctionCayleyGraphClassPart.from_function( bentf, c_start=c_start, c_stop=c_stop) p.save_mangled( name, dir=dir) return name
[docs]def save_class_parts_in_parallel( name_prefix, form, c_len=1, ncpus=4, dir=None): r""" In parallel, construct a complete list of the partial Cayley graph classifications corresponding to a given bent function or algebraic normal form. INPUT: - ``name_prefix`` -- String. Name prefix to use with ``save_mangled`` to save each class part. - ``form`` -- A bent function or an algebraic normal form. - ``c_len`` -- Integer. Default=1. The number of values of `c` to use in each class part. - ``ncpus`` -- Integer. Default=4. The number of cpus to use in parallel. - ``dir`` -- string, optional. The directory where the object is to be saved. Default is None, meaning the current directory. OUTPUT: A list containing tuples, with names. EFFECT: Uses ``name_prefix`` to save all partial classifications corresponding to ``bentf``. EXAMPLE: :: sage: import glob sage: import os sage: from boolean_cayley_graphs.bent_function import BentFunction sage: from boolean_cayley_graphs.bent_function_cayley_graph_classification import BentFunctionCayleyGraphClassPart as BFCP sage: from boolean_cayley_graphs.classify_in_parallel import save_class_parts_in_parallel sage: R2.<x1,x2> = BooleanPolynomialRing(2) sage: p = x1+x2+x1*x2 sage: f = BentFunction(p) sage: name_prefix = 'test_save_class_parts_in_parallel' sage: d = tmp_dir() sage: s = save_class_parts_in_parallel(name_prefix, f, dir=d) sage: p1=BFCP.load_mangled(name_prefix + '_1', dir=d) sage: dict(sorted(p1.__dict__.items())) {'algebraic_normal_form': x0*x1 + x0 + x1, 'bent_cayley_graph_index_matrix': [0 0 1 0], 'c_start': 1, 'cayley_graph_class_list': ['CK', 'C~'], 'dual_cayley_graph_index_matrix': [0 0 1 0], 'weight_class_matrix': [0 0 1 0]} sage: for n in range(4): ....: name = name_prefix + '_' + str(n) ....: print(BFCP.mangled_name(name)) ....: BFCP.remove_mangled(name, dir=d) ....: BentFunctionCayleyGraphClassPart__test_save_class_parts_in_parallel_0 BentFunctionCayleyGraphClassPart__test_save_class_parts_in_parallel_1 BentFunctionCayleyGraphClassPart__test_save_class_parts_in_parallel_2 BentFunctionCayleyGraphClassPart__test_save_class_parts_in_parallel_3 sage: os.rmdir(d) """ bentf = BentFunction(form) dim = bentf.nvariables() v = 2 ** dim ceil = Function_ceil() nbr_parts = ceil(v * 1.0 / c_len) list_of_tuples = [ ((name_prefix + '_' + str(n), bentf, c_len * n, c_len * (n+1), dir)) for n in range(nbr_parts)] return call_in_parallel( save_one_class_part, list_of_tuples, ncpus)