-
Notifications
You must be signed in to change notification settings - Fork 52
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
Add UniformRange.isInRange function #78
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't tell if these laws are sufficient, but looks ok.
For example, I can't seem to derive this isInRange (lo, hi) hi == True
But as far as the approach to tackle the problem with ranges this seems a perfectly viable solution.
@Shimuuar I think you'd be the perfect guy to try and challenge this approach, I know how much you love the |
By symmetry and by inclusivity: |
Duhh 😄 🤦 Thanks ;) |
I really like idea! But I don't understand what does 3rd law states |
@Shimuuar I hope it is more clear now. |
Yes. Much clearer now. Thanks! Right now I'm trying to invent pathological instantiations of these laws for reals. In this case brackets are seriously overloaded. I will use
But following one satisfy all law despite being clearly pathological one:
It could be ruled out by adding another law:
On the other hand this is just a reparametrization of good instance. |
Even worse. This:
will work for any |
Please disregard all "bad" example above.. They actually fail 3-rd law. I guess it's getting late |
I think you are right in the sense that the proposed laws describe what is in range, but do not describe what is not. For example, isInRange (lo, lo) x == (x == lo) |
Now I found truly pathological case: |
Nitpick: for I made the last law about trivial ranges more strict: now it basically enforces that |
@Bodigrim what I trying to do is to understand what is meaning of these laws. Math is scary and wonderful thing. You put identity, associativity, and inverse in and you get group theory out. So question is what sort of structures these laws are generating? I got few more weird constructions and will pot them tomorrow after I flesh them out. |
TL;DR it seems that there's no shortage of weird constructions. Here I'll consider only integer numbers Z and their finite subsets [0..N-1]
ThinningOne approach for constructing more ranges is to drop some elements from standard ranges. Extreme version is to leave only endpoints since they are required by law 2). But there're more possibilities. For example it's possible to include only every other element in the range.
In similar way it's possible to leave out every third etc. FatteningOpposite approach is to include more elements into standard ranges. Extreme variant is to make PermutationsFor finite sets it's possible to simply apply permutation to set and obtain set of ranges. Take for example set [0,2]. Below are standard and permuted intervals:
I don't understand yet how this approach apply to integers and reals |
"Thinning" is almost fine, except the law for "Fattening" violates the 4th law. I'm not sure what you mean by permutations here, could you provide a snippet? But it seems equivalent to making a newtype with |
Yes, permutations are equivalent to changing order of values. It seems something unavoidable unless order is brought in. But I think it's overspecifying things. |
LawsFirst let recapitulate laws:
Finite setsFor start let work with some finite set There's useful change of perspective. Ranges form a partial order with Now we can easily see two extremes. Thin order: 4th lawNow what is effect of fourth law? It states that ranges sharing endpoint are not
or same using with different notation:
It looks that law doesn't quite protect from "range overflow" whatever it |
It seems that your analysis ignores the 5th rule, which would require |
This one?
I do. It seems very ad hoc to me. It doesn't generalize to infinite sets (integers) it does nothing if data type is not Bounded. It's also very easy to sidestep. Let add elements 0 & 5 to constrution above:
|
I like the idea of ranges being injective, but I struggle to find a way to express it in a constructive, property-testable fashion, without "there exists..." clause. |
I think it's fine to leave some laws to on paper verification. Especially since in order to get pathological constructions one have to really go out his way. It's not sort of things one can construct accidentally. P.S. I should get back to constructing possible partial orders. They grow only modestly so it's possible to explore further than 4 elements sets |
@Shimuuar Convinced, I've added the injectivity law and removed a law for |
@Bodigrim sorry for being slow. Law 3 (transitivity)I think it should be strengthened. Currently it's
Former law 4.AFAIR it said that interval endpoints are literal endpoints and any interval constructed from interior points is endpoint: There's curious consequence of these laws: if we take any 3 points a,b,c. Then we can build 3 intervals from them: If we take ordinary intervals for bounded types (say Int). Then for every 3 points first option is realized. I suspect that if for every 3 point there's interval that contains other two. System of intervals is isomorphic to standard intervals. But that something that should be checked |
@Bodigrim I spent some time thinking about the matter and come to following set of laws:
Notable difference from first version is that instead of picking single point from interval they pick two. It turns out it's not possible to go from Another point these laws do not imply injectivity. Common variant ranges (elementwise) for tuples satisfy these laws. And those not unique: <(1,10), (2,20> = <(2,10), (1,20)>. All in all I think this set of law is quite sensible. It doesn't seem to be possible to specify things more concretely without using order in some way. They do allow element tuple instances but I don;t think it's necessary to disallow them On more practical note I'm slightly worried about default implementation of inRange. It's implemented in terms of type class which is only tangentially related to the UniformRange. Maybe default implementation in terms of Generic for both methods should be added? If it will only work for single constructor, 0-1 field data types it will at least cover newtypes. |
@Shimuuar sorry for being super late.
Sure, but let's do this in a separate PR. I'll revert db65185 with appropriate changes for product types and add generic derivation for
This does not hold for tuples (with rectangular ranges). E. g., take a=(0,0), b=(1,1), c=(0,1), d=(1,0). Otherwise looks good, updated. I think four rules are good enough to go. |
You're right. Then law could be changed to weaker version (AFAIR already proposed)
Other that this I think PR is good to go |
CI failure is unrelated to this PR, but still an interesting one: it uses |
@Bodigrim smallcheck-1.2.0 is specified in stack.yaml It's an easy fix, I'll submit a PR in a sec |
@curiousleo @idontgetoutmuch unless you have any comments, I'll merge this soon. |
LGTM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very nice. Great work everyone for constructively criticising this towards an elegant and succinct definition!
Co-authored-by: Leonhard Markert <curiousleo@users.noreply.github.com>
# 1.3.0 * Improve floating point value generation and avoid degenerate cases: [#172](haskell/random#172) * Add `Uniform` instance for `Maybe` and `Either`: [#167](haskell/random#167) * Add `Seed`, `SeedGen`, `seedSize`, `seedSizeProxy`, `mkSeed` and `unSeed`: [#162](haskell/random#162) * Add `mkSeedFromByteString`, `unSeedToByteString`, `withSeed`, `withSeedM`, `withSeedFile`, `seedGenTypeName`, `nonEmptyToSeed`, `nonEmptyFromSeed`, `withSeedM`, `withSeedMutableGen` and `withSeedMutableGen_` * Add `SplitGen` and `splitGen`: [#160](haskell/random#160) * Add `unifromShuffleList` and `unifromShuffleListM`: [#140](haskell/random#140) * Add `uniformWordR`: [#140](haskell/random#140) * Add `mkStdGen64`: [#155](haskell/random#155) * Add `uniformListRM`, `uniformList`, `uniformListR`, `uniforms` and `uniformRs`: [#154](haskell/random#154) * Add compatibility with recently added `ByteArray` to `base`: [#153](haskell/random#153) * Switch to using `ByteArray` for type class implementation instead of `ShortByteString` * Add `unsafeUniformFillMutableByteArray` to `RandomGen` and a helper function `defaultUnsafeUniformFillMutableByteArray` that makes implementation for most instances easier. * Add `uniformByteArray`, `uniformByteString` and `uniformFillMutableByteArray` * Deprecate `genByteString` in favor of `uniformByteString` * Add `uniformByteArrayM` to `StatefulGen` * Add `uniformByteStringM` and `uniformShortByteStringM` * Deprecate `System.Random.Stateful.uniformShortByteString` in favor of `uniformShortByteStringM` for consistent naming and a future plan of removing it from `StatefulGen` type class * Add a pure `System.Random.uniformShortByteString` generating function. * Deprecate `genShortByteString` in favor of `System.Random.uniformShortByteString` * Expose a helper function `fillByteArrayST`, that can be used for defining implementation for `uniformByteArrayM` * Deprecate `genShortByteStringST` and `genShortByteStringIO` in favor of `fillByteArrayST` * Improve `FrozenGen` interface: [#149](haskell/random#149) * Move `thawGen` from `FreezeGen` into the new `ThawGen` type class. Fixes an issue with an unlawful instance of `StateGen` for `FreezeGen`. * Add `modifyGen` and `overwriteGen` to the `FrozenGen` type class * Switch `splitGenM` to use `SplitGen` and `FrozenGen` instead of deprecated `RandomGenM` * Add `splitMutableGenM` * Switch `randomM` and `randomRM` to use `FrozenGen` instead of `RandomGenM` * Deprecate `RandomGenM` in favor of a more powerful `FrozenGen` * Add `isInRangeOrd` and `isInRangeEnum` that can be used for implementing `isInRange`: [#148](haskell/random#148) * Add `isInRange` to `UniformRange`: [#78](haskell/random#78) * Add default implementation for `uniformRM` using `Generics`: [#92](haskell/random#92)
Following our discussions earlier, here is my proposal for a new
isInRange
function to describe rigorously what exactlyUniformRange
instance means by "range". This will allow us to define lawfulUniformRange
instances for tuples and complex numbers.