Comments (24)
Here's a speculative thought: how should an "uncountable iterator" work? Following Riemann integration, one approach would be to have a function partitions(::Domain)
that gives an iterator of partitions of the domain that become increasingly small. Then Riemann integration would look something like:
function arclength(d::Domain)
ret = Inf
for p in partitions(d)
new_ret = 0
for (x, Δx) in p
new_ret += norm(Δx)
end
new_ret ≈ ret && break
ret = new_ret
end
return ret
end
from domainsets.jl.
What about the old notions of length
or arclength
being lebesguemeasure
?
- No one would call that method out of confusion!
- It's the same for open and closed intervals.
from domainsets.jl.
Or A -> hausdorffmeasure(A,1)
? And area being A -> hausdorffmeasure(A,2)
...?
from domainsets.jl.
No, because the integral for arclength is of a positive function.
from domainsets.jl.
This might actually be a case where Domain
should be <: AbstractSet
, and Set(::Domain)
should throw an error.
from domainsets.jl.
Are there other examples of AbstractSet
's that are non-iterable? If not, let's not inherit from AbstractSet
.
How about ptype
instead of eltype
, short for pointtype
?
from domainsets.jl.
You could in theory make domains iterable using nextfloat
...
from domainsets.jl.
Also, currently nothing prevents you from making a domain of Int
s, which could be iterable efficiently, though that may be hard to implement with any kind of generality
from domainsets.jl.
Hm, I'm having second thoughts about this issue:
- The reason
Set(1)
returnsSet([1])
is because 1 is a 1-element iterator, so we have for example
julia> for x in 1 print("$x") end
1
But I do not think interval(0,1)
should act like a 1-element iterator, so Set(interval(0,1))
should not work.
2. In the example above, Set([interval(0,1)])
gives the right thing.
So I think eltype(::Domain)
should be left as is.
If we wanted to be crazy, we could add this:
Base.start(d::Interval{:closed}) = d.a
Base.start(d::Interval{:open,R,<:AbstractFloat}) where R = nextfloat(d.a)
Base.next(d::ClosedInterval{<:AbstractFloat}, st) = st, nextfloat(st)
Base.done(d::Interval{R,:open,<:AbstractFloat}, st) where R = st ≥ d.b
Base.done(d::Interval{R,:closed,<:AbstractFloat}, st) where R = st > d.b
function num_floats(d)
k = 0
for x in d
k += 1
end
k
end
num_floats(interval(0,1E-316)) # 20240226, in 0.062868s
from domainsets.jl.
Hey, that takes 0.11 seconds on my desktop! The fact that such code is even possible makes me want to add it.
Okay, let's keep using eltype
for the time being.
from domainsets.jl.
See 53c81f8.
from domainsets.jl.
Shouldn't cardinality
be called length
?
julia> Set([1,2,3]) |> length
3
from domainsets.jl.
True, that is a logical consequence. Okay, that is the reason this iteration is a bad idea. The question is whether we see an interval as the collection of all floating point numbers in between it, or as an approximation to a set of real numbers. Of course it is the latter, because we want the length
of an interval to return what you would expect (b-a
).
Yet, what is the length of the open interval (10,15) as a subset of the natural numbers? Is it 5 or 3? We may want to avoid using length
altogether.
from domainsets.jl.
length
should not return b-a
as it causes numerous other issues in Base.
from domainsets.jl.
This is why at some point I changed from length
to arclength
for domains in ApproxFun.
from domainsets.jl.
The question comes down to is 0.5 in Interval{Int}(0,1)
?
from domainsets.jl.
Okay, let's say we are not touching length
, unless it agrees with what Base expects (the number of elements in an iterable sequence).
About the question: yes, this is a key point. My first reaction was that it would be hard to argue that 0.5
is in ClosedInterval{Int}(0,1)
, since the user has explicitly created the interval as a subset of integers. Yet, it currently is, due to the promotion rules in in
. Then again, for the same promotion reason we have that nextfloat(big(0.5))
is in ClosedInterval{Float64}(0,1)
, even though this value can't be represented by the Float64
type. This case quite clearly is more desirable.
The simplest conceptual definition of a Domain{T}
would be such that in
returns false for any variable that is not of type T
. But that goes against the promotion system in Julia, since for example big(0.5) == 0.5
is true. In fact, even convert(Float64, (big(0.5)+big(nextfloat(0.5)))/2) == 0.5
is true, so convert
has a tolerance. (Following up on this logic, one could make a case for letting in
be "fuzzy" up to some eps
-related tolerance, which it currently isn't except in some cases.)
An alternative is to distinguish between "discrete" and "continuous" types (for which an eps
can be meaningfully defined, say), and to disallow mixed promotion in the in
function.
The third option is to let Julia's promotion system decide, as in the current implementation. So, 0.5
is in the interval because the interval can be promoted to Domain{Float64}
.
Regardless, any interpretation of an interval as an absurdly large but discrete set of floating point values is bound to break at some point in practice.
I wasn't before, but I am currently in favour of the fuzzy in
: that means 0.5
is in the Int
interval - because Julia says so: leftendpoint(d) <= 0.5 <= rightendpoint(d)
represents the interval. It is a matter of what you define things to be.
Perhaps slightly better is to let the domain decide when implementing in
. This way we leave the decision in the hand of the user, who could still choose to implement a sequence of integers (though said user is probably better off using a UnitRange
). That would mean the promotion logic currently in in
would have to be implemented conditionally, somehow. Perhaps in
by default can call approx_in
with promoted arguments, and domains can choose to override approx_in
or in
itself.
from domainsets.jl.
I think the domain already decides itself when you call convert(Domain{T}, d)
. That is, 0.5 in ClosedInterval{Int}(0,1)
because convert(Domain{Float64}, ClosedInterval{Int}(0,1))
returns ClosedInterval{Float64}(0,1)
.
from domainsets.jl.
Fair enough. This throws an error when the conversion fails, rather than returning false, but then again so does in
in Base
at times.
So, should in
also be "fuzzy" or approximate everywhere? It currently isn't. That would make the distinction between open and closed domains conceptual, captured in their type perhaps but not in in
, but in practice that is mostly the case anyway.
from domainsets.jl.
The current behaviour is not "fuzzy" and is precise to infinite-precision:
a in d # true
prevfloat(a) in d # false
nextfloat(a) in d # true
BigFloat(a) in d # true
prevfloat(BigFloat(a)) in d # false
nextfloat(BigFloat(a)) in d # true
b in d # false
prevfloat(b) in d # true
nextfloat(b) in d # false
BigFloat(b) in d # false
prevfloat(BigFloat(b)) in d # true
nextfloat(BigFloat(b)) in d # false
That is, It's the infinite-dimensional interval [a,b)
where the endpoints are exactly expressible as floating point numbers. No matter what x
is, a
and b
are expressible exactly as T = promote_type(typeof(x), Float64)
, and so there is no fuzzyness introduced by convert(T, a)
and convert(T,b)
.
This precision is desirable and should be maintained.
Note this interpretation makes the sets truly infinite: x in d
if x in convert(Domain{T}, d)
for any T
, which means it actually represents the mathematical interval [a,b)
. In other words, my for x in interval(0,1)
is a bad idea.
from domainsets.jl.
What does this mean for Circle <: Domain{Complex128}
? It means almost no floating Complex128
s are in the domain, but if I make my own type: RadialComplex(r, θ)
then RadialComplex(1.0, θ)
will be in Circle(0.0, 1.0)
for all θ
provided convert(Domain{RadialComplex}, ::Circle)
is overriden.
EDIT: we would actually need to support promote_type(RadialComplex, Complex128)
, which is difficult...
from domainsets.jl.
I think there is a limited and acceptable amount of fuzzyness arising from promote_type
:
promote_type(type1, type2)
Determine a type big enough to hold values of each argument type without
loss, whenever possible. In some cases, where no type exists to which both
types can be promoted losslessly, some loss is tolerated; for example,
promote_type(Int64, Float64) returns Float64 even though strictly, not all
Int64 values can be represented exactly as Float64 values.
julia> promote_type(Int64, Float64)
Float64
julia> promote_type(Int32, Int64)
Int64
julia> promote_type(Float32, BigInt)
BigFloat
I think it is OK to follow the promote_type
fuzzyness rule of almost no fuzzyness.
from domainsets.jl.
Okay, I think we agree on the notion that an interval is best defined mathematically, not in terms of possible concrete values of types. Good. Also, in general, it is a safe bet to follow Julia's standard practices in Base. I'm reverting the iterators :-)
We will still need more discussion about strictness for anything but intervals, but perhaps that is a separate issue.
from domainsets.jl.
Aren't there examples of functions which have finite arclength as defined via Riemann integration but infinite Lebesgue measure?
from domainsets.jl.
Related Issues (20)
- Support `getindex` of `TupleProductDomain` and maybe add a `NamedTupleProductDomain`? HOT 2
- Domain as an interface HOT 3
- Define intersect between a Point and a Domain HOT 2
- use atol and rtol in approx_in HOT 1
- are there conflicting versions of isapprox in IntervalSets? HOT 14
- More Spaces HOT 18
- Center for HyperRectangle? HOT 4
- Should boundary(::Rectangle) use simpler types? HOT 2
- Failure on julia master `Method overwriting is not permitted during Module precompile.` HOT 1
- Precompiling ParameterEstimation fails HOT 2
- Hashes of domains should be consistent with equality HOT 3
- Getting the domain/support of objects, and domain type hierarchy HOT 61
- Support constructors along with `convert` HOT 3
- arithmetic operations with broadcasting
- package extensions and interoperability with different domain types HOT 1
- Roadmap for future development of DomainSets HOT 3
- A confusing bug HOT 9
- VcatDomain(ℝ, ℕ) causes MethodError HOT 2
- Removing points from interval HOT 3
- Depend on EltypeExtensions.jl? HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from domainsets.jl.