-
Notifications
You must be signed in to change notification settings - Fork 35
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
Principle of least astonishment violated for symbolic types whose metric space type differs in representation #716
Comments
What I suspect might be happening here is that I am asking for the sum of the string values of the character names to be minimized, given the types of the results. But in that case, how to construct the symbolic sum of the values? |
I think I can upgrade this to a bug -- the binary contents of that |
I can force out the right value with a lot of horrid hacks like so, but the sign bit appears to be incorrect in addition to the ergonomic problems
This shows
|
When you optimize a quantity, what you're actually optimizing is its value in the optimization metric space. See https://hackage.haskell.org/package/sbv-10.10/docs/Data-SBV.html#t:MetricSpace For most types the metric space is equivalent to the type itself. This is typically the case when the underlying solver (i.e., z3) supports optimization over that type. But there are certain types that the optimizer just doesn't support (Floats for instance), or you might want to have a different notion of a "metric" to optimize for given a custom data-type. This is the motivation for If you look at the The reason for this is twofold: (1) The underlying optimizer doesn't support optimizing floats. (2) You don't want So, the module Main where
import Data.SBV
constructQuery :: [Float] -> Symbolic ()
constructQuery values = do
constrainedVars <- mapM construct $ zip [0..] values
let s = sum constrainedVars
sObserve "total" s
minimize "total_metric" $ s
where.
construct (index, value) = do
introVar <- sFloat $ "variable_" ++ show index
constrain $ introVar .== literal value
return introVar
main = do
result <- optimize Lexicographic $ constructQuery [12.2, 1.44, 3.7]
print result This prints: Optimal model:
total = 17.34 :: Float
variable_0 = 12.2 :: Float
variable_1 = 1.44 :: Float
variable_2 = 3.7 :: Float
total_metric = 3247093842 :: Word32 Making it clear the *Main> fromMetricSpace (3247093842 :: SWord32) :: SFloat
17.34 :: SFloat
*Main> toMetricSpace (17.34::SFloat)
3247093842 :: SWord32 Since metric-space is typically equivalent to itself for the typical use case of *Main> optimize Lexicographic $ \(x::SInt8) -> minimize "metric_x" x
Optimal model:
s0 = -128 :: Int8
metric_x = 0 :: Word8 Note how the value of There's some documentation here: https://hackage.haskell.org/package/sbv-10.10/docs/Data-SBV.html#g:54, but it can always be improved. PR's that improve documentation are always welcome, if you would like to submit a patch. |
Ah, this makes a lot of sense! I was starting to suspect it was a solver-related implementation constraint like this. Thank you for the detailed explanation, that is really helpful. I certainly think that this could benefit from some example code (perhaps this exact example) in the "Model Extraction" part of the documentation. I'll open a PR 😄 |
I think we can do a little better here, and actually add extra "values" to the output when the metric space differs from the underlying type. I'm working on a patch as we speak. Let's see if that's more helpful. (You might want to hold off on your documentation PR till the new version is ready so it matches the latest code.) |
Addresses #716
As of 88581bd, I think the output should be less confusing. For your original program, we now print:
Is this better? We can change the |
This is super, thank you! I think the least astonishing choice for the symbolic type of a value defined by expressions in an optimization query is the symbolic correspondent of the type that would be inferred in Haskell for the concrete version of those statements. It's important to understand the practical implementation impact (ostensibly using a backend solver with native support for the types involved would result in a faster solve), and I think this change also makes that more visible; seeing extra "metric space" variables in your optimized model is a clear indicator that the optimizer you have chosen is not directly representing the types you're using. 👍 from me! I think perhaps |
Cool. I pushed in a change and the output now is: Optimal model:
total = 17.34 :: Float
variable_0 = 12.2 :: Float
variable_1 = 1.44 :: Float
variable_2 = 3.7 :: Float
toMetricSpace(total) = 3247093842 :: Word32 After all I'm closing this ticket as resolved; though feel free to open others if you see other fishy behavior. I consider "usability" bugs just as important as functional bugs. Thanks. |
Using GHC 9.6.5 and SBV 10.10
I have the following program which does not behave as I expect, and I suspect my thinking is wrong somewhere.
What I expect this program to do is to "solve" the trivial problem where the variables are all constrained to an exact value, and compute the sum of those values (this is a reduction for demonstration purposes from a larger problem where these variables are not so constrained).
What actually happens is that I see a
Word32
value coming out when the type of the symbolic values is sFloat. I cannot seem to make the problem go away by putting in explicit types, and anyway ghci tells me the inferred types are correct. Help? Is this just a completely erroneous way of constructing sums of symbolic values? It gets no better if I explicitly use+
on the list elements instead of a fold.The text was updated successfully, but these errors were encountered: