JuliaApproximation / FrameFun.jl

Exploring practical possibilities of approximating functions with frames rather than with a basis
Other
23 stars 7 forks source link

Removing the field `approx_op` from a FrameFun #1

Closed kuanxu closed 8 years ago

kuanxu commented 8 years ago

Currently, FrameFun has a field approx_op which is the approximation operators used to construct the FrameFun or, more precisely, the other field expansion. I totally understand that this might be of a historic issue - you folks just wanted to keep the information for a while, as they're not dirt cheap to acquire and it is pretty useful for any debugging work. However, this causes some troubles for the users.

  1. As a user whose work is built on the top of FrameFuns, if I try to construct a FrameFun not from scratch but from another FrameFun directly (e.g FrameFun x 2), I generally don't have a sensible approx_op to supply to the constructor. However, as far as I understand, I can't construct an object with some fields missing in Julia. I'm also unable to supply something like void to the constructor, since Julia does not have a “null” value. This makes personally assembled FrameFuns almost impossible without providing a place holder, i.e. a dummy approx_op.
  2. The field approx_op costs a lot in memory. So I guess it drags the speed in some degree. But I have no benchmark to justify this.

Shall we consider to get rid of approx_op at all? Comments?

kuanxu commented 8 years ago

Sorry. I just checked out the recent commits and happily found that approx_op has been removed! Thanks.

MikaelSlevinsky commented 8 years ago

Types can be constructed in Julia (at least in 0.4) with some fields undefined. These require an inner constructor. The "Self-Referential" section in the manual discusses this. Accessing an undefined field results in an error.

Cheers,

Mikael

On Jun 21, 2016, at 6:44 PM, Kuan Xu notifications@github.com wrote:

Currently, FrameFun has a field approx_op which is the approximation operators used to construct the FrameFun or, more precisely, the other field expansion. I totally understand that this might be of a historic issue - you folks just wanted to keep the information for a while, as they're not dirt cheap to acquire and it is pretty useful for any debugging work. However, this causes some troubles for the users.

As a user whose work is built on the top of FrameFuns, if I try to construct a FrameFun not from scratch but from another FrameFun directly (e.g FrameFun x 2), I generally don't have a sensible approx_op to supply to the constructor. However, as far as I understand, I can't construct an object with some fields missing in Julia. I'm also unable to supply something like void to the constructor, since Julia does not have a “null” value. This makes personally assembled FrameFuns almost impossible without providing a place holder, i.e. a dummy approx_op.

The field approx_op costs a lot in memory. So I guess it drags the speed in some degree. But I have no benchmark to justify this.

Shall we consider to get rid of approx_op at all? Comments?

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

daanhb commented 8 years ago

Thanks for reporting! Indeed, that approx_op field was annoying more often than not, and that is why we took it out. I thought it was a good idea at first, because the construction of the approximation operator can be expensive.

kuanxu commented 8 years ago

@MikaelSlevinsky Thanks for reminding the incompletely initialized objects with new(). But I didn't mean to modify FrameFun's constructor, but still be able to construct a FrameFun with field(s) undefined.

Do you know if there is a way to construct a type with undefined fields but without deliberately using new()?

@daanhb Do we really need to keep the field expansion, as it is the only field on its own level? It might be more straightforward if we strip off expansion so that a FrameFun directly own the fields set and coef. But you guys may have other thoughts on it.

MikaelSlevinsky commented 8 years ago

Not that I'm aware... maybe someone at julia-users has an answer

daanhb commented 8 years ago

@kuanxu You may want to consider just using a SetExpansion directly, if that is possible for your use case. That is exactly a combination of a set and coefficients. All arithmetic is (or should be) defined on expansions. It would also be faster in many cases since a SetExpansion has fully typed fields, intentionally. This means the compiler will optimize away all overhead of these expansions in most cases.

For background, the reason we introduced the FrameFun type was for convenience. It is a shallow, and slow (because it is untyped) layer over SetExpansion. The only thing it adds is that the type expresses that it is a frame, and that makes it a little easier to dispatch e.g. plotting routines. It also removes many layers of interactive output of nested parameters. Functionally, a FrameFun is (or should be) equivalent to a SetExpansion where the set is a DomainFrame.

Having said that, there might well be holes in our implementation! The above is the general idea. Please report whatever is missing...

kuanxu commented 8 years ago

@daanhb Sorry for not having responded sooner! I've been hectic for the deadline of exam marking.

Why do you say that FrameFun's fields (now field) are untyped? I don't see it.

immutable FrameFun{N,T} <: AbstractFun
    expansion   ::  SetExpansion
    FrameFun(e::SetExpansion) = new(e)
end

Can you elaborate a little?

daanhb commented 8 years ago

@kuanxu I was being sloppy: the expansion field of FrameFun is indeed typed, but not fully. SetExpansion is not a concrete type, because its parameters are not specified (S,ELT and ID). Hence, the compiler does not know exactly what the concrete type of the expansion of a FrameFun is, and that makes manipulations with FrameFun's slower than manipulations with SetExpansion's. Saying that expansion always is a SetExpansion does allow the compiler to narrow down the possibilities at runtime.

Not that you're suggesting this, but for completeness: we could add the extra parameters to the field expansion::SetExpansion, but then we also have to add them to the type FrameFun itself. There is a large compilation overhead in adding parameters everywhere. In the end, this approach makes everything depend on everything else. As soon as one type is changed somewhere, everything has to be recompiled. In addition, there are hard-coded limits in the depth of nested types in Julia. In fact, that kind of over-typing was a real bottleneck at some point in our code. We started removing type parameters whenever the potential runtime cost of dynamic type checking is not in a time-critical path, or when it is just O(1) in a computation that is O(N) or more expensive overall. Look at the history of CompositeOperator for an example. This exercise is not over yet, but we cut down the running time of our test suite by a factor of 2-3 with such kind of changes.

Anyway, back on topic, we will always make sure that manipulations with SetExpansion's are fast. That's why I suggested to use them instead. It is not a good name, though. Perhaps we ought to call them Fun's. Or just Expansion.

kuanxu commented 8 years ago

@daanhb Thanks for the detailed explanation!! It can't be more elaborated. 👍 From now on, I'll stick to SetExpansion for my use cases.

daanhb commented 8 years ago

It would be cool if that works for you, thanks.