Commit 524be9d2 authored by Brice Videau's avatar Brice Videau

Python bindings tests are on par with Ruby's.

parent f90f8190
......@@ -41,14 +41,18 @@ def _ccs_get_function(method, argtypes = [], restype = ccs_result):
# https://www.python-course.eu/python3_metaclasses.php
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Inactive(metaclass=Singleton):
pass
def __str__(self):
return "Inactive"
def __repr__(self):
return "Inactive"
ccs_inactive = Inactive()
......
......@@ -2,6 +2,7 @@ import ctypes as ct
from .base import Object, Error, ccs_error, _ccs_get_function, ccs_context, ccs_hyperparameter, ccs_configuration_space, ccs_configuration, ccs_rng, ccs_distribution, ccs_expression, ccs_datum, ccs_hash, ccs_int
from .context import Context
from .rng import Rng
from .hyperparameter import Hyperparameter
from .configuration_space import ConfigurationSpace
ccs_create_configuration = _ccs_get_function("ccs_create_configuration", [ccs_configuration_space, ct.c_size_t, ct.POINTER(ccs_datum), ct.c_void_p, ct.POINTER(ccs_configuration)])
......
import ctypes as ct
from .base import Object, Error, CEnumeration, ccs_error, ccs_result, _ccs_get_function, ccs_context, ccs_hyperparameter, ccs_configuration_space, ccs_configuration, ccs_datum, ccs_objective_space, ccs_evaluation
from .base import Object, Error, CEnumeration, ccs_error, ccs_result, _ccs_get_function, ccs_context, ccs_hyperparameter, ccs_configuration_space, ccs_configuration, ccs_datum, ccs_datum_fix, ccs_objective_space, ccs_evaluation
from .context import Context
from .hyperparameter import Hyperparameter
from .configuration_space import ConfigurationSpace
......@@ -20,7 +20,7 @@ ccs_evaluation_get_user_data = _ccs_get_function("ccs_evaluation_get_user_data",
ccs_evaluation_get_error = _ccs_get_function("ccs_evaluation_get_error", [ccs_evaluation, ct.POINTER(ccs_result)])
ccs_evaluation_set_error = _ccs_get_function("ccs_evaluation_set_error", [ccs_evaluation, ccs_result])
ccs_evaluation_get_value = _ccs_get_function("ccs_evaluation_get_value", [ccs_evaluation, ct.c_size_t, ct.POINTER(ccs_datum)])
ccs_evaluation_set_value = _ccs_get_function("ccs_evaluation_set_value", [ccs_evaluation, ct.c_size_t, ccs_datum])
ccs_evaluation_set_value = _ccs_get_function("ccs_evaluation_set_value", [ccs_evaluation, ct.c_size_t, ccs_datum_fix])
ccs_evaluation_get_values = _ccs_get_function("ccs_evaluation_get_values", [ccs_evaluation, ct.c_size_t, ct.POINTER(ccs_datum), ct.POINTER(ct.c_size_t)])
ccs_evaluation_get_value_by_name = _ccs_get_function("ccs_evaluation_get_value_by_name", [ccs_evaluation, ct.c_char_p, ccs_datum])
ccs_evaluation_get_objective_value = _ccs_get_function("ccs_evaluation_get_objective_value", [ccs_evaluation, ct.c_size_t, ct.POINTER(ccs_datum)])
......
......@@ -178,10 +178,10 @@ class Expression(Object):
Error.check(res)
def __str__(self):
t = self.type.value
t = self.type
symbol = ccs_expression_symbols[t]
prec = ccs_expression_precedence[t]
nds = ["({})".format(n) if ccs_expression_precedence[n.type.value] < prec else n.__str__() for n in self.nodes]
nds = ["({})".format(n) if ccs_expression_precedence[n.type] < prec else n.__str__() for n in self.nodes]
if len(nds) == 1:
return "{}{}".format(symbol, nds[0])
else:
......
......@@ -137,7 +137,7 @@ class Hyperparameter(Object):
return [x.value for x in v]
def __eq__(self, other):
return self.__class__ == other.__class__ and self.handle == other.handle
return self.__class__ == other.__class__ and self.handle.value == other.handle.value
ccs_create_numerical_hyperparameter = _ccs_get_function("ccs_create_numerical_hyperparameter", [ct.c_char_p, ccs_numeric_type, ccs_int, ccs_int, ccs_int, ccs_int, ct.c_void_p, ct.POINTER(ccs_hyperparameter)])
......
......@@ -9,7 +9,7 @@ from .configuration import Configuration
class ccs_objective_type(CEnumeration):
_members_ = [
('MINIMIZE', 0),
'MAXINIZE' ]
'MAXIMIZE' ]
ccs_create_objective_space = _ccs_get_function("ccs_create_objective_space", [ct.c_char_p, ct.c_void_p, ct.POINTER(ccs_objective_space)])
ccs_objective_space_get_name = _ccs_get_function("ccs_objective_space_get_name", [ccs_objective_space, ct.POINTER(ct.c_char_p)])
......@@ -119,6 +119,9 @@ class ObjectiveSpace(Context):
Error.check(res)
def add_objectives(self, expressions, types = None):
if isinstance(expressions, dict):
types = expressions.values()
expressions = expressions.keys()
sz = len(expressions)
if sz == 0:
return None
......@@ -153,4 +156,4 @@ class ObjectiveSpace(Context):
t = (ccs_objective_type * sz)()
res = ccs_objective_space_get_objectives(self.handle, sz, v, t, None)
Error.check(res)
return [(Expression.from_handle(ccs_expression(v[x])), t[x]) for x in range(sz)]
return [(Expression.from_handle(ccs_expression(v[x])), t[x].value) for x in range(sz)]
import unittest
import re
import sys
sys.path.insert(1, '.')
sys.path.insert(1, '..')
import cconfigspace as ccs
class TestConfigurationSpace(unittest.TestCase):
def test_create(self):
cs = ccs.ConfigurationSpace(name = "space")
self.assertEqual( ccs.CONFIGURATION_SPACE, cs.object_type )
self.assertEqual( "space", cs.name )
self.assertIsInstance( cs.rng, ccs.Rng )
self.assertEqual( 0, cs.num_hyperparameters )
self.assertEqual( [], cs.conditions )
self.assertEqual( [], cs.forbidden_clauses )
h1 = ccs.NumericalHyperparameter()
h2 = ccs.NumericalHyperparameter()
h3 = ccs.NumericalHyperparameter()
cs.add_hyperparameter(h1)
cs.add_hyperparameters([h2, h3])
self.assertEqual( 3, cs.num_hyperparameters )
self.assertEqual( h1, cs.hyperparameter(0) )
self.assertEqual( h2, cs.hyperparameter(1) )
self.assertEqual( h3, cs.hyperparameter(2) )
self.assertEqual( [h1, h2, h3], cs.hyperparameters )
self.assertEqual( h2, cs.hyperparameter_by_name(h2.name) )
cs.check(cs.default_configuration)
c = cs.sample()
cs.check(c)
self.assertEqual( cs.handle.value, c.configuration_space.handle.value )
cs.check_values(cs.sample().values)
for c in cs.samples(100):
cs.check(c)
def test_conditions(self):
h1 = ccs.NumericalHyperparameter(lower = -1.0, upper = 1.0, default = 0.0)
h2 = ccs.NumericalHyperparameter(lower = -1.0, upper = 1.0)
h3 = ccs.NumericalHyperparameter(lower = -1.0, upper = 1.0)
cs = ccs.ConfigurationSpace(name = "space")
cs.add_hyperparameters([h1, h2, h3])
e1 = ccs.Expression(t = ccs.LESS, nodes = [h2, 0.0])
cs.set_condition(h3, e1)
e2 = ccs.Expression(t = ccs.LESS, nodes = [h3, 0.0])
cs.set_condition(h1, e2)
e3 = ccs.Expression(t = ccs.LESS, nodes = [h1, 0.0])
cs.add_forbidden_clause(e3)
conditions = cs.conditions
self.assertEqual( 3, len(conditions) )
self.assertEqual( e2.handle.value, conditions[0].handle.value )
self.assertIsNone( conditions[1] )
self.assertEqual( e1.handle.value, conditions[2].handle.value )
forbidden_clauses = cs.forbidden_clauses
self.assertEqual( 1, len(forbidden_clauses))
self.assertEqual( e3.handle.value, forbidden_clauses[0].handle.value )
def extract_active_parameters(self, values):
res = ['p1']
for v in values:
if v != ccs.ccs_inactive:
res += ["p{}".format(m[1]) for m in re.finditer('#P(\d)', v)]
return res
def test_omp(self):
p1 = ccs.CategoricalHyperparameter(
name = 'p1',
values = [
' ',
'#pragma omp #P2',
'#pragma omp target teams distribute #P2',
'#pragma omp target teams distribute #P4',
'#pragma omp #P3'])
p2 = ccs.CategoricalHyperparameter(
name = 'p2',
values = [
' ',
'parallel for #P3',
'parallel for #P5',
'parallel for #P6'])
p3 = ccs.CategoricalHyperparameter(
name = 'p3',
values = [' ', 'simd'])
p4 = ccs.CategoricalHyperparameter(
name = 'p4',
values = [
' ',
'dist_schedule(static)',
'dist_schedule(static, #P8)'])
p5 = ccs.CategoricalHyperparameter(
name = 'p5',
values = [
' ',
'schedule(#P7,#P8)',
'schedule(#P7)'])
p6 = ccs.CategoricalHyperparameter(
name = 'p6',
values = [
' ',
'numthreads(#P9)'])
p7 = ccs.CategoricalHyperparameter(
name = 'p7',
values = [
'static',
'dynamic'])
p8 = ccs.OrdinalHyperparameter(
name = 'p8',
values = ['1', '8', '16'])
p9 = ccs.OrdinalHyperparameter(
name = 'p9',
values = ['1', '8', '16'])
cs = ccs.ConfigurationSpace(name = "omp")
cs.add_hyperparameters([p1, p2, p3, p4, p5, p6, p7, p8, p9])
cond0 = ccs.Expression(t = ccs.EQUAL, nodes = [p1, '#pragma omp #P2'])
cond1 = ccs.Expression(t = ccs.EQUAL, nodes = [p1, '#pragma omp target teams distribute #P2'])
cond2 = ccs.Expression(t = ccs.EQUAL, nodes = [p1, '#pragma omp target teams distribute #P4'])
cond3 = ccs.Expression(t = ccs.EQUAL, nodes = [p1, '#pragma omp #P3'])
cond4 = ccs.Expression(t = ccs.EQUAL, nodes = [p2, 'parallel for #P3'])
cond5 = ccs.Expression(t = ccs.EQUAL, nodes = [p2, 'parallel for #P5'])
cond6 = ccs.Expression(t = ccs.EQUAL, nodes = [p2, 'parallel for #P6'])
cond7 = ccs.Expression(t = ccs.EQUAL, nodes = [p4, 'dist_schedule(static, #P8)'])
cond8 = ccs.Expression(t = ccs.EQUAL, nodes = [p5, 'schedule(#P7)'])
cond9 = ccs.Expression(t = ccs.EQUAL, nodes = [p5, 'schedule(#P7,#P8)'])
cond10 = ccs.Expression(t = ccs.EQUAL, nodes = [p6, 'numthreads(#P9)'])
cs.set_condition(p2, ccs.Expression(t = ccs.OR, nodes = [cond0, cond1]))
cs.set_condition(p4, cond2)
cs.set_condition(p3, ccs.Expression(t = ccs.OR, nodes = [cond3, cond4]))
cs.set_condition(p5, cond5)
cs.set_condition(p6, cond6)
cs.set_condition(p7, ccs.Expression(t = ccs.OR, nodes = [cond8, cond9]))
cs.set_condition(p8, ccs.Expression(t = ccs.OR, nodes = [cond7, cond9]))
cs.set_condition(p9, cond10)
forbiddena = ccs.Expression(t = ccs.EQUAL, nodes = [p1, '#pragma omp #P2'])
forbiddenb = ccs.Expression(t = ccs.EQUAL, nodes = [p2, ' '])
forbidden0 = ccs.Expression(t = ccs.AND, nodes = [forbiddena, forbiddenb])
forbiddenc = ccs.Expression(t = ccs.EQUAL, nodes = [p1, '#pragma omp #P3'])
forbiddend = ccs.Expression(t = ccs.EQUAL, nodes = [p3, ' '])
forbidden1 = ccs.Expression(t = ccs.AND, nodes = [forbiddenc, forbiddend])
cs.add_forbidden_clauses([forbidden0, forbidden1])
all_params = [ "p{}".format(i) for i in range(1,10) ]
for i in range(1000):
s = cs.sample()
s.check()
active_params = self.extract_active_parameters(s.values)
for par in active_params:
self.assertNotEqual( ccs.ccs_inactive, s.value(par) )
for par in list(set(all_params) - set(active_params)):
self.assertEqual( ccs.ccs_inactive, s.value(par) )
self.assertFalse( s.value('p1') == '#pragma omp #P2' and s.value('p2') == ' ' )
self.assertFalse( s.value('p1') == '#pragma omp #P3' and s.value('p3') == ' ' )
if __name__ == '__main__':
unittest.main()
import unittest
import sys
sys.path.insert(1, '.')
sys.path.insert(1, '..')
import cconfigspace as ccs
class TestEvaluation(unittest.TestCase):
def test_create(self):
cs = ccs.ConfigurationSpace(name = "cspace")
h1 = ccs.NumericalHyperparameter()
h2 = ccs.NumericalHyperparameter()
h3 = ccs.NumericalHyperparameter()
cs.add_hyperparameters([h1, h2, h3])
os = ccs.ObjectiveSpace(name = "ospace")
v1 = ccs.NumericalHyperparameter()
v2 = ccs.NumericalHyperparameter()
os.add_hyperparameters([v1, v2])
e1 = ccs.Variable(hyperparameter = v1)
e2 = ccs.Variable(hyperparameter = v2)
os.add_objectives( { e1: ccs.MAXIMIZE, e2: ccs.MINIMIZE } )
ev1 = ccs.Evaluation(objective_space = os, configuration = cs.sample())
ev1.set_value(0, 0.5)
ev1.set_value(v2, 0.6)
self.assertEqual( [0.5, 0.6], ev1.values )
self.assertEqual( [0.5, 0.6], ev1.objective_values )
ev2 = ccs.Evaluation(objective_space = os, configuration = cs.sample(), values = [0.5, 0.6])
self.assertEqual( [0.5, 0.6], ev2.values )
self.assertEqual( [0.5, 0.6], ev2.objective_values )
self.assertEqual( ccs.EQUIVALENT, ev1.cmp(ev2) )
ev3 = ccs.Evaluation(objective_space = os, configuration = cs.sample(), values = [0.6, 0.5])
self.assertEqual( [0.6, 0.5], ev3.objective_values )
self.assertEqual( ccs.WORSE, ev1.cmp(ev3) )
self.assertEqual( ccs.BETTER, ev3.cmp(ev1) )
ev4 = ccs.Evaluation(objective_space = os, configuration = cs.sample(), values = [0.6, 0.7])
self.assertEqual( [0.6, 0.7], ev4.objective_values )
self.assertEqual( ccs.NOT_COMPARABLE, ev1.cmp(ev4) )
self.assertEqual( ccs.NOT_COMPARABLE, ev4.cmp(ev1) )
if __name__ == '__main__':
unittest.main()
import unittest
import sys
sys.path.insert(1, '.')
sys.path.insert(1, '..')
import cconfigspace as ccs
class TestExpression(unittest.TestCase):
def test_create(self):
e = ccs.Expression(t = ccs.ADD, nodes = [1.0, 2.0])
self.assertEqual( ccs.EXPRESSION, e.object_type )
self.assertEqual( ccs.ADD, e.type )
self.assertEqual( 2, e.num_nodes )
nodes = e.nodes
self.assertEqual( 2, len(nodes) )
for n in nodes:
self.assertIsInstance( n, ccs.Literal )
self.assertEqual( ccs.EXPRESSION, n.object_type )
self.assertEqual( ccs.LITERAL, n.type )
self.assertEqual( 1.0, nodes[0].value )
self.assertEqual( 2.0, nodes[1].value )
self.assertEqual( 3.0, e.eval() )
self.assertEqual( [], e.hyperparameters )
def test_to_s(self):
e = ccs.Expression(t = ccs.ADD, nodes = [1.0, 2.0])
self.assertEqual( "1.0 + 2.0", str(e) )
e2 = ccs.Expression(t = ccs.MULTIPLY, nodes = [5.0, e])
self.assertEqual( "5.0 * (1.0 + 2.0)", str(e2) )
def test_literal(self):
e = ccs.Literal(value = 15)
self.assertEqual( "15" , str(e) )
e = ccs.Literal(value = None)
self.assertEqual( "None" , str(e) )
def test_variable(self):
h = ccs.NumericalHyperparameter()
e = ccs.Variable(hyperparameter = h)
self.assertEqual( h.name , str(e) )
def test_list(self):
e = ccs.List(values = ["foo", 1, 2.0])
self.assertEqual( "[ 'foo', 1, 2.0 ]", str(e) )
self.assertEqual( "foo", e.eval(0) )
self.assertEqual( 1, e.eval(1) )
self.assertEqual( 2.0, e.eval(2) )
h = ccs.NumericalHyperparameter(name = "test")
e2 = ccs.Expression(t = ccs.IN, nodes = [h, e])
self.assertEqual( "test # [ 'foo', 1, 2.0 ]", str(e2) )
def test_unary(self):
e = ccs.Expression.unary(t = ccs.NOT, node = True)
self.assertEqual( "!True", str(e) )
self.assertFalse( e.eval() )
def test_binary(self):
e = ccs.Expression.binary(t = ccs.OR, left = True, right = False)
self.assertEqual( "True || False", str(e) )
self.assertTrue( e.eval() )
if __name__ == '__main__':
unittest.main()
import unittest
import sys
sys.path.insert(1, '.')
sys.path.insert(1, '..')
import cconfigspace as ccs
class TestObjectiveSpace(unittest.TestCase):
def test_create(self):
os = ccs.ObjectiveSpace(name = "space")
self.assertEqual( "space", os.name )
self.assertEqual( 0, os.num_hyperparameters )
self.assertEqual( [], os.objectives )
h1 = ccs.NumericalHyperparameter()
h2 = ccs.NumericalHyperparameter()
h3 = ccs.NumericalHyperparameter()
os.add_hyperparameter(h1)
os.add_hyperparameters([h2, h3])
self.assertEqual( 3, os.num_hyperparameters )
self.assertEqual( h1, os.hyperparameter(0) )
self.assertEqual( h2, os.hyperparameter(1) )
self.assertEqual( h3, os.hyperparameter(2) )
self.assertEqual( [h1, h2, h3], os.hyperparameters )
self.assertEqual( h2, os.hyperparameter_by_name(h2.name) )
e1 = ccs.Expression(t = ccs.ADD, nodes = [h1, h2])
e2 = ccs.Variable(hyperparameter = h3)
os.add_objective(e1)
self.assertEqual( 1, len(os.objectives) )
os.add_objectives([e2], types = [ccs.MAXIMIZE])
self.assertEqual( 2, len(os.objectives) )
objs = os.objectives
self.assertEqual( e1.handle.value, objs[0][0].handle.value )
self.assertEqual( ccs.MINIMIZE, objs[0][1] )
self.assertEqual( e2.handle.value, objs[1][0].handle.value )
self.assertEqual( ccs.MAXIMIZE, objs[1][1] )
if __name__ == '__main__':
unittest.main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment