Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Such that" is failing #14

Open
jaimerson opened this issue Nov 26, 2015 · 5 comments
Open

"Such that" is failing #14

jaimerson opened this issue Nov 26, 2015 · 5 comments

Comments

@jaimerson
Copy link

So I have the following code:

for_all {s, t, j} in such_that({s_, t_, j_} in {int, int, int} when(s_ < j_ and j_ < t_)) do
    #...
end

Because I need j to be a value between s and t. Seems correct. However, here's the output I'm getting:

image

I don't think this is the expected behaviour. (apologies in advance if this is my mistake and/or this is not the place to submit this kind of report)

@luc-tielen
Copy link
Contributor

Most likely related to how the such_that macro is implemented in ExCheck since tuples can be represented differently in AST depending on if the number of elements equals to 2:

iex(1)> quote do: {1}
{:{}, [], [1]}
iex(2)> quote do: {1,2}
{1, 2}
iex(3)> quote do: {1,2, 3}
{:{}, [], [1, 2, 3]}

Might look into this later if I have some time...

EDIT: actually I was completely wrong, problem could be in triq with the guard..
The following fails:

property "such that with 1 element" do
for_all x in such_that({x_} in {int} when x_ < 0) do
x < 0
end
end

while the following succeeds:

property "such that with 1 element" do
for_all x in such_that({x_} in {int} when x_ > 0) do
x > 0
end
end

The :suchthat_failed is triggered when suchthat can't generate a correct scenario after 100 (default) attempts.. maybe we need to open an issue on triq repo instead?

@parroty
Copy link
Owner

parroty commented Nov 29, 2015

@jaimerson thanks for the report.
@primordus thanks for the analysis.

The :suchthat_failed is triggered when suchthat can't generate a correct scenario after 100 (default) attempts.. maybe we need to open an issue on triq repo instead?

I could simulate the same behavior, but haven't been able to identify the cause enough yet.
Do you have any further insight regarding which part is causing failure? (It's using triq's internal functionality, and would like to isolate the issue if opening a issue).

As you indicated, it seems erlang:exit(suchthat_failed) is called in triq after failing to generate a correct scenario, but I'm not confident about its condition.

The following seems generating negative values, but your example (replacing 1 with 0) results in suchthat_failed. The other example x > 0 (which does not contain 0) seems working as you indicated.

property "such that with less than 1" do
  for_all {x} in such_that({x_} in {int} when x_ < 1) do
    IO.puts "x = #{x}"
    x < 1
  end
end

outputs

x = 0
.x = 0
.x = 0
.x = -3
.x = -3
.x = 0
.x = -5
.x = -5
.x = -2
.x = -2
...

and

property "such that with larger than 0" do
  for_all {x} in such_that({x_} in {int} when x_ > 0) do
    IO.puts "x = #{x}"
    x > 0
  end
end

outputs

x = 1
.x = 2
.x = 3
.x = 3
.x = 3
.x = 1
...

@luc-tielen
Copy link
Contributor

Just played around some more, the following (even simpler case) also fails:

property "such that with 1 element" do
for_all x in such_that(x_ in int when x_ < 0) do
IO.puts "x = #{x}"
x < 1
end
end

Maybe something wrong with the int generator / such that / combination of the 2?
Following variations I checked fail:
x < 0
x < -1
...
x > 1
x > 2
...
In short, x < N with N <= 0 or x > N with N >= 1..

Might be a good idea to write these same tests in Erlang and check if they fail there as well so we can pinpoint where it goes wrong or add some debug statements in triq. I suspect the int shrinking algorithm might be going in the wrong direction somehow and runs out after 100 tries?
Can't look further into this today, maybe investigate some more during the week.

devstopfix added a commit to devstopfix/excheck that referenced this issue Aug 7, 2019
@devstopfix
Copy link

devstopfix commented Aug 7, 2019

I have tested this with triq 1.2.0 and 1.3.0 and now it seems to work.

The original:

  property :stj_such_that_constraints do
    for_all {s, t, j} in such_that({s_, t_, j_} in {int(), int(), int()} when s_ < j_ and j_ < t_) do
      assert j > s, inspect([s, j, t])
      assert j < t, inspect([s, j, t])
    end
  end

An alternate formulation without using constraints:

  defp gen_sjt,
    do:
      [int(), pos_integer(), pos_integer()]
      |> bind(fn [s, dj, dt] -> {s, s + dj, s + dj + dt} end)

  property :sjt_bind do
    for_all {s, j, t} in gen_sjt() do
      assert j > s, inspect([s, j, t])
      assert j < t, inspect([s, j, t])
    end
  end

@devstopfix
Copy link

Testing from iex -S mix:

import :triq_dom

:triq_dom.suchthat([{int(), int(), int()}], fn [{a,b,c}] -> (a < b) and (b < c) end) |> sample
[
  [{6, 10, 12}],
  [{0, 3, 8}],
  [{-26, -15, -6}],
  [{-12, -11, 17}],
  [{-13, -7, 6}],
  [{-8, 0, 6}],
  [{-21, -15, 9}],
  [{7, 11, 13}],
  [{-13, 0, 13}],
  [{1, 9, 13}],
  [{-12, 9, 11}]
]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants