Source code for vsc.constraints

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

# Created on Jul 23, 2019
#
# @author: ballance


from vsc.impl.ctor import push_constraint_scope, push_constraint_stmt, pop_expr, \
    pop_constraint_scope, in_constraint_scope, last_constraint_stmt, push_expr, \
    push_foreach_arr, pop_foreach_arr, constraint_scope_depth, in_srcinfo_mode
from vsc.model.constraint_dist_model import ConstraintDistModel
from vsc.model.constraint_foreach_model import ConstraintForeachModel
from vsc.model.constraint_if_else_model import ConstraintIfElseModel
from vsc.model.constraint_implies_model import ConstraintImpliesModel
from vsc.model.constraint_scope_model import ConstraintScopeModel
from vsc.model.constraint_soft_model import ConstraintSoftModel
from vsc.model.constraint_solve_order_model import ConstraintSolveOrderModel
from vsc.model.constraint_unique_model import ConstraintUniqueModel
from vsc.model.constraint_unique_vec_model import ConstraintUniqueVecModel
from vsc.model.dist_weight_expr_model import DistWeightExprModel
from vsc.model.expr_array_subscript_model import ExprArraySubscriptModel
from vsc.model.expr_dynref_model import ExprDynRefModel
from vsc.model.expr_fieldref_model import ExprFieldRefModel
from vsc.model.field_array_model import FieldArrayModel
from vsc.model.expr_indexed_field_ref_model import ExprIndexedFieldRefModel
from vsc.model.field_scalar_model import FieldScalarModel
from vsc.types import to_expr, expr, type_base, rng
from vsc.visitors.expr2fieldtype_visitor import Expr2FieldTypeVisitor
from vsc.model.source_info import SourceInfo


[docs] class constraint_t(object): def __init__(self, c): self.c = c self.enabled = True self.model = None self.srcinfo = None pass
[docs] def constraint_mode(self, en): self.enabled = en if self.model is not None: self.model.set_constraint_enabled(en)
[docs] def set_model(self, m): self.model = m self.model.set_constraint_enabled(self.enabled)
[docs] def elab(self): print("elab")
[docs] class dynamic_constraint_t(object): def __init__(self, c): self.c = c self.model = None self.srcinfo = None
[docs] def set_model(self, m): self.model = m
def __call__(self): return expr(ExprDynRefModel(self.model))
[docs] class call_closure(object): def __init__(self, c, *args, **kwargs): self.c = c self.args = args self.kwargs = kwargs def __enter__(self): self.c(*self.args, **self.kwargs) def __exit__(self, t, v, tb): pass
[docs] def dynamic_constraint(c): ret = dynamic_constraint_t(c) # Capture source info, since it's only # captured once during loading ret.srcinfo = SourceInfo.mk() return ret
[docs] def constraint(c): ret = constraint_t(c) # Capture source info, since it's only # captured once during loading ret.srcinfo = SourceInfo.mk() return ret
[docs] class weight(object): def __init__(self, val, w): rng_lhs_e = None rng_rhs_e = None if isinstance(val, (list,tuple)): if len(val) != 2: raise Exception("Weight range must have two elements") to_expr(val[0]) rng_lhs_e = pop_expr() to_expr(val[1]) rng_rhs_e = pop_expr() elif isinstance(val, rng): rng_lhs_e = val.low rng_rhs_e = val.high else: to_expr(val) rng_lhs_e = pop_expr() to_expr(w) w_e = pop_expr() self.weight_e = DistWeightExprModel( rng_lhs_e, rng_rhs_e, w_e)
[docs] def dist(lhs, weights): """Applies distribution weights to the specified field""" to_expr(lhs) lhs_e = pop_expr() weight_l = [] for w in weights: if not isinstance(w, weight): raise Exception("Weight specifications must of type 'vsc.weight', not " + str(w)) weight_l.append(w.weight_e) c = ConstraintDistModel(lhs_e, weight_l) if in_srcinfo_mode(): c.srcinfo = SourceInfo.mk() push_constraint_stmt(c)
[docs] class if_then(object): def __init__(self, e): if not in_constraint_scope(): raise Exception("Attempting to use if_then constraint outside constraint scope") to_expr(e) self.stmt = ConstraintIfElseModel(pop_expr()) if in_srcinfo_mode(): self.stmt.srcinfo = SourceInfo.mk() push_constraint_stmt(self.stmt) def __enter__(self): self.stmt.true_c = ConstraintScopeModel() push_constraint_scope(self.stmt.true_c) def __exit__(self, t, v, tb): pop_constraint_scope()
[docs] class else_if(object): def __init__(self, e): self.stmt = None if not in_constraint_scope(): raise Exception("Attempting to use if_then constraint outside constraint scope") last_stmt = last_constraint_stmt() if last_stmt == None or not isinstance(last_stmt, ConstraintIfElseModel): raise Exception("Attempting to use else_if where it doesn't follow if_then") to_expr(e) # Need to find where to think this in while last_stmt.false_c != None: last_stmt = last_stmt.false_c self.stmt = ConstraintIfElseModel(pop_expr()) if in_srcinfo_mode(): self.stmt.srcinfo = SourceInfo.mk() last_stmt.false_c = self.stmt def __enter__(self): if self.stmt is not None: self.stmt.true_c = ConstraintScopeModel() push_constraint_scope(self.stmt.true_c) def __exit__(self, t, v, tb): pop_constraint_scope()
[docs] class else_then_c(object): def __init__(self): pass def __call__(self): return self def __enter__(self): if not in_constraint_scope(): raise Exception("Attempting to use if_then constraint outside constraint scope") last_stmt = last_constraint_stmt() if last_stmt == None or not isinstance(last_stmt, ConstraintIfElseModel): raise Exception("Attempting to use else_then where it doesn't follow if_then/else_if") # Need to find where to think this in while last_stmt.false_c != None: last_stmt = last_stmt.false_c stmt = ConstraintScopeModel() last_stmt.false_c = stmt push_constraint_scope(stmt) def __exit__(self, t, v, tb): pop_constraint_scope()
else_then = else_then_c()
[docs] class implies(object): def __init__(self, e): if not in_constraint_scope(): raise Exception("Attempting to use if_then constraint outside constraint scope") to_expr(e) self.stmt = ConstraintImpliesModel(pop_expr()) if in_srcinfo_mode(): self.stmt.srcinfo = SourceInfo.mk() def __enter__(self): push_constraint_stmt(self.stmt) push_constraint_scope(self.stmt) def __exit__(self, t, v, tb): pop_constraint_scope()
[docs] def soft(e): to_expr(e) em = pop_expr() c = ConstraintSoftModel(em) c.srcinfo = em.srcinfo push_constraint_stmt(c)
[docs] def unique(*args): expr_l = [] for i in range(-1, -(len(args)+1), -1): to_expr(args[i]) expr_l.insert(0, pop_expr()) c = ConstraintUniqueModel(expr_l) if in_srcinfo_mode(): c.srcinfo = SourceInfo.mk() push_constraint_stmt(c)
[docs] def unique_vec(*args): expr_l = [] for i in range(-1, -(len(args)+1), -1): to_expr(args[i]) e = pop_expr() if not isinstance(e, ExprFieldRefModel) or not isinstance(e.fm, FieldArrayModel): raise Exception("All arguments to unique_vec must be lists") expr_l.insert(0, e) if len(expr_l) < 2: raise Exception("Must specify at least two vectors to uniquify") c = ConstraintUniqueVecModel(expr_l) if in_srcinfo_mode(): c.srcinfo = SourceInfo.mk() push_constraint_stmt(c)
[docs] class forall(object): def __init__(self, target_type): self.target_type = target_type pass def __enter__(self): pass def __exit__(self, t, v, tb): pass
[docs] class foreach(object):
[docs] class idx_term_c(type_base): def __init__(self, index): super().__init__(32, False) self.index = index
[docs] def to_expr(self): return expr(ExprFieldRefModel(self.index))
[docs] class it_term_c(type_base): def __init__(self, em): super().__init__(32, False) self.em = em
[docs] def to_expr(self): return expr(self.em)
def __getattr__(self, aname): em = object.__getattribute__(self, "em") # This pops 'this expr' off the stack, so we can # replace it with an extended expression # pop_expr() ret = None if isinstance(em, ExprArraySubscriptModel): # TODO: Need to get the core type fm = None if isinstance(em.lhs, ExprIndexedFieldRefModel): fm = em.lhs.get_target() elif isinstance(em.lhs, ExprFieldRefModel): fm = em.lhs.fm else: raise Exception("Unsupported path-chaining expression " + str(em.lhs)) if aname in fm.type_t.field_id_m.keys(): idx = fm.type_t.field_id_m[aname] ret = expr(ExprIndexedFieldRefModel(em, [idx])) else: raise Exception("Type %s does not contain a field \"%s\"" % ( fm.type_t.name, aname)) else: raise Exception("Expression getattribute access on non-subscript") return ret
def __init__(self, l, it=None, idx=None): self.stmt = None if it is None and idx is None: # Default: use it it = True idx = False else: # One or more are specified if idx is None: idx = False if it is None: it = False if not idx and not it: raise Exception("Neither it nor idx specified") # Form an expression to the array to_expr(l) e = pop_expr() self.arr_ref_e = e self.elem_t = Expr2FieldTypeVisitor().fieldtype(e) self.it = it self.idx = idx if not in_constraint_scope(): raise Exception("Attempting to use foreach constraint outside constraint scope") self.stmt = ConstraintForeachModel(e) if in_srcinfo_mode(): self.stmt.srcinfo = SourceInfo.mk() def __enter__(self): push_constraint_stmt(self.stmt) push_constraint_scope(self.stmt) idx_term = foreach.idx_term_c(self.stmt.index) it_term = foreach.it_term_c(ExprArraySubscriptModel( self.arr_ref_e, ExprFieldRefModel(self.stmt.index))) if self.idx and self.it: return (idx_term, it_term) else: if self.it: return it_term else: return idx_term def __exit__(self, t, v, tb): pop_constraint_scope()
[docs] def solve_order(before, after): if constraint_scope_depth() != 1: raise Exception("solve_before can only be used at a constraint top level") before_l = [] after_l = [] if isinstance(before, list): for b in before: to_expr(b) b_e = pop_expr() if not isinstance(b_e, ExprFieldRefModel): raise Exception("Parameter " + str(b) + " is not a field reference") before_l.append(b_e.fm) else: to_expr(before) before_e = pop_expr() if not isinstance(before_e, ExprFieldRefModel): raise Exception("Parameter " + str(before) + " is not a field reference") before_l.append(before_e.fm) if isinstance(after, list): for a in after: to_expr(a) a_e = pop_expr() if not isinstance(a_e, ExprFieldRefModel): raise Exception("Parameter " + str(a) + " is not a field reference") after_l.append(a_e.fm) else: to_expr(after) after_e = pop_expr() if not isinstance(after_e, ExprFieldRefModel): raise Exception("Parameter " + str(after) + " is not a field reference") after_l.append(after_e.fm) c = ConstraintSolveOrderModel(before_l, after_l) if in_srcinfo_mode(): c.srcinfo = SourceInfo.mk() push_constraint_stmt(c)