Commit 92a63358 authored by Brice Videau's avatar Brice Videau

Added a ruby parser for ccs expressions.

parent 5bc0089d
......@@ -6,6 +6,7 @@ require_relative 'cconfigspace/rng'
require_relative 'cconfigspace/distribution'
require_relative 'cconfigspace/hyperparameter'
require_relative 'cconfigspace/expression'
require_relative 'cconfigspace/expression_parser'
require_relative 'cconfigspace/context'
require_relative 'cconfigspace/configuration_space'
require_relative 'cconfigspace/configuration'
......
......@@ -127,6 +127,9 @@ module CCS
end
def set_condition(hyperparameter, expression)
if expression.kind_of? String
expression = ExpressionParser::new(self).parse(expression)
end
case hyperparameter
when Hyperparameter
hyperparameter = hyperparameter_index(hyperparameter);
......@@ -163,12 +166,23 @@ module CCS
end
def add_forbidden_clause(expression)
if expression.kind_of? String
expression = ExpressionParser::new(self).parse(expression)
end
res = CCS.ccs_configuration_space_add_forbidden_clause(@handle, expression)
CCS.error_check(res)
self
end
def add_forbidden_clauses(expressions)
expressions = expressions.collect { |e|
p = ExpressionParser::new(self)
if e.kind_of? String
e = p.parse(e)
else
e
end
}
count = expressions.size
return self if count == 0
ptr = MemoryPointer::new(:ccs_expression_t, count)
......
......@@ -50,8 +50,10 @@ module CCS
[k, expression_associativity[v]]
}.to_h
ExpressionSymbols = ExpressionType.symbol_map.collect { |k, v|
p = expression_symbols[v]
[k, p]
[k, expression_symbols[v]]
}.to_h
ExpressionArity = ExpressionType.symbol_map.collect { |k, v|
[k, expression_arity[v]]
}.to_h
attach_function :ccs_create_binary_expression, [:ccs_expression_type_t, :ccs_datum_t, :ccs_datum_t, :pointer], :ccs_result_t
......
def silence_warnings(&block)
warn_level = $VERBOSE
$VERBOSE = nil
result = block.call
$VERBOSE = warn_level
result
end
silence_warnings {
require 'whittle'
}
undef silence_warnings
module CCS
class ExpressionParser < Whittle::Parser
class << self
attr_accessor :context
end
def initialize(context = nil)
@context = context
end
def parse(*args)
self.class.context = @context
super
end
ExpressionSymbols.reverse_each { |k, v|
next unless v
next if k == :CCS_POSITIVE || k == :CCS_NEGATIVE
associativity = ExpressionAssociativity[k] == :CCS_LEFT_TO_RIGHT ? :left :
ExpressionAssociativity[k] == :CCS_RIGHT_TO_LEFT ? :right : nil
precedence = ExpressionPrecedence[k]
eval "rule('#{v}') % :#{associativity} ^ #{precedence}"
}
rule(:wsp => /\s+/).skip!
rule("(")
rule(")")
rule("[")
rule("]")
rule(",")
rule(:float => /-?[0-9]+([eE][+-]?[0-9]+|\.[0-9]+([eE][+-]?[0-9]+)?)/).as {|num|
Literal::new(value: Float(num)) }
rule(:integer => /-?[0-9]+/).as { |num|
Literal::new(value: Integer(num)) }
rule(:identifier => /[a-zA-Z_][a-zA-Z_0-9]*/).as { |identifier|
Variable::new(hyperparameter: context.hyperparameter_by_name(identifier)) }
rule(:string => /"([^\0\t\n\r\f"\\]|\\[0tnrf"\\])+"|'([^\0\t\n\r\f'\\]|\\[0tnrf'\\])+'/).as { |str|
Literal::new(value: eval(str)) }
rule(:value) do |r|
r[:string]
r[:identifier]
r[:float]
r[:integer]
end
rule(:list_item) do |r|
r[:list_item, ",", :value].as { |l, _, e| l.push e }
r[:value].as { |e| [e] }
end
rule(:list) do |r|
r["[", :list_item, "]"].as { |_, l, _| List::new(values: l) }
r["[", "]"].as { |_, _| List::new(values: []) }
end
rule(:in_expr) do |r|
r[:identifier, "#", :list].as { |v, _, l|
Expression.binary(type: :CCS_IN, left: v, right: l) }
end
rule(:expr) do |r|
r["(", :expr, ")"].as { |_, exp, _| exp }
ExpressionSymbols.reverse_each { |k, v|
next unless v
next if v == "#"
arity = ExpressionArity[k]
if arity == 1
eval "r['#{v}', :expr].as { |_, a| Expression.unary(type: :#{k}, node: a) }"
else
eval "r[:expr, '#{v}', :expr].as { |a, _, b| Expression.binary(type: :#{k}, left: a, right: b) }"
end
}
r[:in_expr]
r[:value]
end
start(:expr)
end
end
......@@ -116,6 +116,9 @@ module CCS
end
def add_objective(expression, type: :CCS_MINIMIZE)
if expression.kind_of? String
expression = ExpressionParser::new(self).parse(expression)
end
res = CCS.ccs_objective_space_add_objective(@handle, expression, type)
CCS.error_check(res)
self
......@@ -126,6 +129,14 @@ module CCS
types = expressions.values
expressions = expressions.keys
end
expressions = expressions.collect { |e|
p = ExpressionParser::new(self)
if e.kind_of? String
e = p.parse(e)
else
e
end
}
count = expressions.length
return self if count == 0
if types
......
......@@ -58,6 +58,21 @@ class CConfigSpaceTestConfigurationSpace < Minitest::Test
assert_equal( e3.handle, forbidden_clauses[0].handle )
end
def extract_active_parameters(values)
['p1'] + values.select { |v|
v != CCS::Inactive
}.collect { |v|
m = v.scan(/#P(\d)/)
if m
m.collect { |vi|
"p#{vi.first.to_i}"
}
else
nil
end
}.compact.flatten
end
def test_omp
p1 = CCS::CategoricalHyperparameter::new(
name: 'p1',
......@@ -149,18 +164,87 @@ class CConfigSpaceTestConfigurationSpace < Minitest::Test
1000.times {
s = cs.sample
s.check
active_params = ['p1'] + s.values.select { |v|
v != CCS::Inactive
}.collect { |v|
m = v.scan(/#P(\d)/)
if m
m.collect { |vi|
"p#{vi.first.to_i}"
}
else
nil
end
}.compact.flatten
active_params = extract_active_parameters(s.values)
active_params.each { |par|
refute_equal( CCS::Inactive, s.value(par) )
}
(all_params - active_params).each { |par|
assert_equal( CCS::Inactive, s.value(par) )
}
refute( s.value('p1') == '#pragma omp #P2' && s.value('p2') == ' ' )
refute( s.value('p1') == '#pragma omp #P3' && s.value('p3') == ' ' )
}
end
def test_omp_parse
p1 = CCS::CategoricalHyperparameter::new(
name: 'p1',
values: [
' ',
'#pragma omp #P2',
'#pragma omp target teams distribute #P2',
'#pragma omp target teams distribute #P4',
'#pragma omp #P3'])
p2 = CCS::CategoricalHyperparameter::new(
name: 'p2',
values: [
' ',
'parallel for #P3',
'parallel for #P5',
'parallel for #P6'])
p3 = CCS::CategoricalHyperparameter::new(
name: 'p3',
values: [' ', 'simd'])
p4 = CCS::CategoricalHyperparameter::new(
name: 'p4',
values: [
' ',
'dist_schedule(static)',
'dist_schedule(static, #P8)'])
p5 = CCS::CategoricalHyperparameter::new(
name: 'p5',
values: [
' ',
'schedule(#P7,#P8)',
'schedule(#P7)'])
p6 = CCS::CategoricalHyperparameter::new(
name: 'p6',
values: [
' ',
'numthreads(#P9)'])
p7 = CCS::CategoricalHyperparameter::new(
name: 'p7',
values: [
'static',
'dynamic'])
p8 = CCS::OrdinalHyperparameter::new(
name: 'p8',
values: ['1', '8', '16'])
p9 = CCS::OrdinalHyperparameter::new(
name: 'p9',
values: ['1', '8', '16'])
cs = CCS::ConfigurationSpace::new(name: "omp")
cs.add_hyperparameters([p1, p2, p3, p4, p5, p6, p7, p8, p9])
cs.set_condition(p2, "p1 # ['#pragma omp #P2', '#pragma omp target teams distribute #P2']")
cs.set_condition(p4, "p1 == '#pragma omp target teams distribute #P4'")
cs.set_condition(p3, "p1 == '#pragma omp #P3' || p2 == 'parallel for #P3'")
cs.set_condition(p5, "p2 == 'parallel for #P5'")
cs.set_condition(p6, "p2 == 'parallel for #P6'")
cs.set_condition(p7, "p5 # ['schedule(#P7)', 'schedule(#P7,#P8)']")
cs.set_condition(p8, "p4 == 'dist_schedule(static, #P8)' || p5 == 'schedule(#P7,#P8)'")
cs.set_condition(p9, "p6 == 'numthreads(#P9)'")
cs.add_forbidden_clauses(["p1 == '#pragma omp #P2' && p2 == ' '",
"p1 == '#pragma omp #P3' && p3 == ' '"])
all_params = (1..9).collect { |i| "p#{i}" }
1000.times {
s = cs.sample
s.check
active_params = extract_active_parameters(s.values)
active_params.each { |par|
refute_equal( CCS::Inactive, s.value(par) )
}
......
[ '../lib', 'lib' ].each { |d| $:.unshift(d) if File::directory?(d) }
require 'minitest/autorun'
require 'cconfigspace'
class CConfigSpaceTestExpressionParser < Minitest::Test
def setup
CCS.init
end
def test_parse
m = CCS::ExpressionParser.new.method(:parse)
exp = "1.0 + 1 == 2 || +1 == 3e0 && \"y\\nes\" == 'no' "
res = m[exp]
assert( res.kind_of? CCS::Expression )
assert_equal( "1.0 + 1 == 2 || +1 == 3.0 && \"y\\nes\" == \"no\"", res.to_s )
end
def test_parse_priority
m = CCS::ExpressionParser.new.method(:parse)
exp = "(1 + 3) * 2"
res = m[exp]
assert( res.kind_of? CCS::Expression )
assert_equal( exp, res.to_s )
end
def test_associativity
m = CCS::ExpressionParser.new.method(:parse)
exp = "5 - 2 - 1"
res = m[exp]
assert( res.kind_of? CCS::Expression )
assert_equal( 2, res.eval )
exp = "5 - +(+2 - 1)"
res = m[exp]
assert( res.kind_of? CCS::Expression )
assert_equal( 4, res.eval )
end
end
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