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

Secrets design - optional information in bool and f64 #266

Closed
bvssvni opened this issue Jun 5, 2016 · 0 comments
Closed

Secrets design - optional information in bool and f64 #266

bvssvni opened this issue Jun 5, 2016 · 0 comments

Comments

@bvssvni
Copy link
Member

bvssvni commented Jun 5, 2016

Dyon supports putting optional secret information in bool and f64 that is unlocked with two intrinsics:

  • fn why(var: sec[bool]) -> [any] { ... }
  • fn where(var: sec[f64]) -> [any] { ... }

The /all, /any, min, max loops uses this to insert index information.

where intrinsic

A where intrinsic gives you the secret of a number. The secret is automatically derived from the composition of loops:

// Find smallest value in 2D array.
list := [[1, 0], [-1, 2]]
x := min i, j { list[i][j] }
arg := where(x)
println(arg) // prints `[1, 0]`
println(list[arg[0]][arg[1]] == x) // prints `true`

If a list is empty, the min/max loop will return NaN:

list := []
x := min i { list[i] }
println(where(x)) // ERROR: Expected `number`, found `NaN`

The secret of a number can only be unlocked if the value is not NaN.

You can use the ? operator to propagate the error message:

fn foo(list: []) -> res {
    x := min i { list[i] }
    // if list is empty, returns `err("Expected `number`, found `NaN`")`
    println(where(x?))
    return ok("success!")
}

The ? operator can also be useful in numerical calculations to check for division of zero by zero.

why intrinsic

The why intrinsic gives you a secret of a bool. The secret is derived from composition of loops:

// Find the value in 2D array that is less than zero.
list := [[1, 0], [-1, 2]]
x := ∃ i, j { list[i][j] < 0 }
arg := why(x)
println(arg) // prints `[1, 0]`
println(list[arg[0]][arg[1]] < 0) // prints `true`

If the list is empty, the /all loop will return true and /any will return false.

list := []
x := ∃ i { list[i] > 0 }
println(why(x)) // ERROR: This does not make sense, perhaps an array is empty?

You can use the ? operator to propagate the error message:

fn foo(list: []) -> res {
    x := ∃ i { list[i] > 0 }
    // If list is empty,
    // returns `err("This does not make sense, perhaps an array is empty?")`
    println(why(x?))
    return ok("success!")
}

The why intrinsics only unlocks the secret if the value is true. When using a /all loop you must ask "why not":

x := ∀ i { list[i] > 0 }
println(why(!x))

The ? operator is evaluated after !:

x := ∀ i { list[i] > 0 }
println(why(!x?)) // works because `x` is inverted before `?`

When combining /all loops with /any loops, the secret will only propagate for true values, such that the meaning is preserved:

// Find the list where all values are positive.
list := [[1, 2], [-1, 2]]
x := ∃ i { ∀ j { list[i][j] > 0 } }
println(why(x)) // prints `[0]` because that's the list.

By inverting the result of a /all loop the secret is propagated:

// Find the list where not all values are positive.
list := [[1, 2], [-1, 2]]
x := ∃ i { !∀ j { list[i][j] > 0 } }
println(why(x)) // prints `[1, 0]` because that's where we find `-1`.

Binary operators

A secret propagates from the left argument in binary operators:

// Find the list where the minimum value is less than zero.
list := [[1, 0], [-1, 2]]
x := ∃ i { min j { list[i][j] } < 0 }
println(why(x)) // prints `[1, 0]` because that's where -1 is, which is the minimum value.

If we swap sides, the secret is lost from the inner min loop:

// Find the list where zero is greater or equal to the minimum value of the list.
list := [[1, 0], [-1, 2]]
x := ∃ i { 0 >= min j { list[i][j] } }
println(why(x)) // prints `[1]` because that's where the list is

Unary operator

  • !x inverts the value of bool, but keeps the secret
  • -x changes sign of f64, but keeps the secret

explain_why intrinsic

Puts a secret with a bool:

reason := "just because"
x := explain_why((1+1)==2, reason)
println(why(x)) // prints `["just because"]`

explain_where intrinsic

Puts a secret with a f64:

reason := "the number is 2"
x := explain_where(2, reason)
println(where(x)) // prints `["the number is 2"]`

Returning values

Secrets are leaked when assigned to return. A function calling another can inspect what the other function was doing, which makes it easier to debug and write custom search/solvers.

Motivation

These rules are designed for:

  • Unifying /all, /any with min/max
  • Simplifies algorithms for problem solving
  • Improved performance for these loops
  • Easy to read
  • Reduce bugs
  • Reduce typing
  • Make debugging easier
  • Optional safety for edge cases
  • Automatically derive meaningful answers
@bvssvni bvssvni mentioned this issue Jun 5, 2016
@bvssvni bvssvni changed the title Secrets - optional information in bool and f64 unlocked with why and where Secrets design - optional information in bool and f64 Jun 5, 2016
@bvssvni bvssvni closed this as completed Jun 17, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant