fvutils / pyvsc

Python packages providing a library for Verification Stimulus and Coverage
https://fvutils.github.io/pyvsc
Apache License 2.0
113 stars 26 forks source link

Errors solving constraints in foreach loop #132

Closed msmftc closed 2 years ago

msmftc commented 2 years ago

@mballance,

I've encountered a couple unique errors while using constraints in a foreach loop. I've found a workaround for my immediate needs, but I think the errors are still worth investigation. In the examples below, I am trying to randomly select 5 consecutive numbers from a rangelist.

In this first example, a if_then constraint is nested inside a foreach. It seems like the target of the if_then is being evaluated even when the condition is false, causing an index out of range error.

import vsc

@vsc.randobj
class Selector:
    def __init__(self):
        self.available = vsc.rangelist((0,19), (30,49))
        self.selectedList = vsc.rand_list_t(vsc.rand_uint16_t(), 5)

    @vsc.constraint
    def select_c(self):
        with vsc.foreach(self.selectedList, idx=True) as i:
            self.selectedList[i].inside(self.available)
            with vsc.if_then(i < 4):
                self.selectedList[i] + 1 == self.selectedList[i+1]

selector = Selector()
selector.randomize()
outStr = "selector.selectedList:"
for sel in selector.selectedList:
    outStr += "\t" + str(int(sel))
print(outStr)
Traceback (most recent call last):
  File "/usr/lib64/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib64/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/users/mcgrathm/.vscode-server-insiders/extensions/ms-python.python-2021.11.1422169775/pythonFiles/lib/python/debugpy/__main__.py", line 45, in <module>
    cli.main()
  File "/users/mcgrathm/.vscode-server-insiders/extensions/ms-python.python-2021.11.1422169775/pythonFiles/lib/python/debugpy/../debugpy/server/cli.py", line 444, in main
    run()
  File "/users/mcgrathm/.vscode-server-insiders/extensions/ms-python.python-2021.11.1422169775/pythonFiles/lib/python/debugpy/../debugpy/server/cli.py", line 285, in run_file
    runpy.run_path(target_as_str, run_name=compat.force_str("__main__"))
  File "/usr/lib64/python3.6/runpy.py", line 263, in run_path
    pkg_name=pkg_name, script_name=fname)
  File "/usr/lib64/python3.6/runpy.py", line 96, in _run_module_code
    mod_name, mod_spec, pkg_name, script_name)
  File "/usr/lib64/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/experiment/pyvsc/constrDebug17.py", line 31, in <module>
    selector.randomize()
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/rand_obj.py", line 168, in randomize
    solve_fail_debug=solve_fail_debug)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/randomizer.py", line 837, in do_randomize
    fm, bounds_v.bound_m))
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/visitors/array_constraint_builder.py", line 49, in build
    m.accept(builder)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/field_composite_model.py", line 154, in accept
    v.visit_composite_field(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/model_visitor.py", line 68, in visit_composite_field
    c.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/constraint_block_model.py", line 42, in accept
    v.visit_constraint_block(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/visitors/constraint_copy_builder.py", line 85, in visit_constraint_block
    super().visit_constraint_block(c)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/model_visitor.py", line 107, in visit_constraint_block
    self.visit_constraint_scope(c)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/visitors/constraint_override_visitor.py", line 25, in visit_constraint_scope
    cc.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/constraint_foreach_model.py", line 47, in accept
    v.visit_constraint_foreach(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/visitors/array_constraint_builder.py", line 79, in visit_constraint_foreach
    c.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/constraint_if_else_model.py", line 63, in accept
    visitor.visit_constraint_if_else(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/visitors/constraint_copy_builder.py", line 137, in visit_constraint_if_else
    cs.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/constraint_expr_model.py", line 39, in accept
    visitor.visit_constraint_expr(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/visitors/constraint_copy_builder.py", line 112, in visit_constraint_expr
    ret = ConstraintExprModel(self.expr(c.e))
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/visitors/constraint_copy_builder.py", line 267, in expr
    e.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/expr_bin_model.py", line 178, in accept
    visitor.visit_expr_bin(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/visitors/constraint_copy_builder.py", line 191, in visit_expr_bin
    self.expr(e.rhs))
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/visitors/constraint_copy_builder.py", line 267, in expr
    e.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/expr_array_subscript_model.py", line 57, in accept
    v.visit_expr_array_subscript(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/visitors/array_constraint_builder.py", line 96, in visit_expr_array_subscript
    e = self.foreach_ref_expander.expand(s)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/visitors/foreach_ref_expander.py", line 35, in expand
    e.accept(self) 
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/expr_array_subscript_model.py", line 57, in accept
    v.visit_expr_array_subscript(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/visitors/foreach_ref_expander.py", line 102, in visit_expr_array_subscript
    self._field = base.field_l[int(s.rhs.val())]
IndexError: list index out of range

In this second example, I've eliminated the if_then statement, but now I get a KeyError. I don't know why.

import vsc

@vsc.randobj
class Selector:
    def __init__(self):
        self.available = vsc.rangelist((0,19), (30,49))
        self.selectedList = vsc.rand_list_t(vsc.rand_uint16_t(), 5)

    @vsc.constraint
    def select_c(self):
        with vsc.foreach(self.selectedList, idx=True) as i:
            self.selectedList[i].inside(self.available)
            self.selectedList[i] == self.selectedList[0] + i

selector = Selector()
selector.randomize()
outStr = "selector.selectedList:"
for sel in selector.selectedList:
    outStr += "\t" + str(int(sel))
print(outStr)
Traceback (most recent call last):
  File "/usr/lib64/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib64/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/users/mcgrathm/.vscode-server-insiders/extensions/ms-python.python-2021.11.1422169775/pythonFiles/lib/python/debugpy/__main__.py", line 45, in <module>
    cli.main()
  File "/users/mcgrathm/.vscode-server-insiders/extensions/ms-python.python-2021.11.1422169775/pythonFiles/lib/python/debugpy/../debugpy/server/cli.py", line 444, in main
    run()
  File "/users/mcgrathm/.vscode-server-insiders/extensions/ms-python.python-2021.11.1422169775/pythonFiles/lib/python/debugpy/../debugpy/server/cli.py", line 285, in run_file
    runpy.run_path(target_as_str, run_name=compat.force_str("__main__"))
  File "/usr/lib64/python3.6/runpy.py", line 263, in run_path
    pkg_name=pkg_name, script_name=fname)
  File "/usr/lib64/python3.6/runpy.py", line 96, in _run_module_code
    mod_name, mod_spec, pkg_name, script_name)
  File "/usr/lib64/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/experiment/pyvsc/constrDebug17.py", line 31, in <module>
    selector.randomize()
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/rand_obj.py", line 168, in randomize
    solve_fail_debug=solve_fail_debug)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/randomizer.py", line 873, in do_randomize
    ri = RandInfoBuilder.build(field_model_l, constraint_l, Randomizer._rng)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/rand_info_builder.py", line 107, in build
    fm.accept(builder)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/field_composite_model.py", line 154, in accept
    v.visit_composite_field(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/rand_info_builder.py", line 368, in visit_composite_field
    super().visit_composite_field(f)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/model_visitor.py", line 68, in visit_composite_field
    c.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/constraint_block_model.py", line 42, in accept
    v.visit_constraint_block(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/rand_info_builder.py", line 164, in visit_constraint_block
    super().visit_constraint_block(c)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/model_visitor.py", line 107, in visit_constraint_block
    self.visit_constraint_scope(c)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/model_visitor.py", line 147, in visit_constraint_scope
    cc.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/constraint_override_model.py", line 22, in accept
    v.visit_constraint_override(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/model_visitor.py", line 143, in visit_constraint_override
    c.new_constraint.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/constraint_inline_scope_model.py", line 15, in accept
    v.visit_constraint_inline_scope(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/model_visitor.py", line 140, in visit_constraint_inline_scope
    cc.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/constraint_expr_model.py", line 39, in accept
    visitor.visit_constraint_expr(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/rand_info_builder.py", line 203, in visit_constraint_expr
    super().visit_constraint_expr(c)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/model_visitor.py", line 115, in visit_constraint_expr
    c.e.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/expr_bin_model.py", line 178, in accept
    visitor.visit_expr_bin(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/model_visitor.py", line 166, in visit_expr_bin
    e.rhs.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/expr_bin_model.py", line 178, in accept
    visitor.visit_expr_bin(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/model_visitor.py", line 165, in visit_expr_bin
    e.lhs.accept(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/expr_array_subscript_model.py", line 57, in accept
    v.visit_expr_array_subscript(self)
  File "/data/cf/sshot/u/mcgrathm/silicon-validation/.venv/lib64/python3.6/site-packages/vsc/model/rand_info_builder.py", line 258, in visit_expr_array_subscript
    self._randset_m.pop(idx)
KeyError: 1

In this third example, I added an intermediate scalar value to the constraints. PyVSC solves these constraints correctly.

import vsc

@vsc.randobj
class Selector:
    def __init__(self):
        self.available = vsc.rangelist((0,19), (30,49))
        self.selectedList = vsc.rand_list_t(vsc.rand_uint16_t(), 5)
        self.startval = vsc.rand_uint16_t()

    @vsc.constraint
    def select_c(self):
        self.startval.inside(self.available)
        with vsc.foreach(self.selectedList, idx=True) as i:
            self.selectedList[i].inside(self.available)
            self.selectedList[i] == self.startval + i

selector = Selector()
selector.randomize()
outStr = "selector.selectedList:"
for sel in selector.selectedList:
    outStr += "\t" + str(int(sel))
print(outStr)
selector.selectedList:  38      39      40      41      42
mballance commented 2 years ago

I believe this issue is corrected in 0.6.9 (the testcase runs, at least). I've added an evaluator for if/else constraints inside foreach constraints that flattens out if/else that have a constant expression. For the purposes of foreach unrolling, the iteration index is considered a constant.