[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner


On Wednesday, 4 February 2015 16:59:14 UTC, Avik Sengupta wrote:

 I don't understand your domain of course, but the way I'd do this would be 
 a slight variant of OPTION 1

 get_forces(a::AbstractAtom) = error(All AbstractAtom subtypes should 
 implement get_forces)
 get_forces(a::Atom) = get_forces(a.calc)


this is indeed what I've done at the moment. Good to hear that this is not 
completely idiotic. 
 

 I think the point to ponder is, what amount of commonality does all 
 possible Atoms contain? 


I thought one problem with not having proper inheritance is that this 
doesn't really help? Even small variations across AbstractAtoms types 
require a full implementation?
 


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Avik Sengupta
I don't understand your domain of course, but the way I'd do this would be 
a slight variant of OPTION 1

get_forces(a::AbstractAtom) = error(All AbstractAtom subtypes should 
implement get_forces)
get_forces(a::Atom) = get_forces(a.calc)

I think the point to ponder is, what amount of commonality does all 
possible Atoms contain? 

Regards
-
Avik

On Wednesday, 4 February 2015 15:16:02 UTC, Christoph Ortner wrote:


 I am trying to re-structure a molecular simulation code I've been working 
 on, to make it more readily extendable. I am puzzling over how to do this 
 most effectively in Julia, and would appreciate any thoughts from more 
 experienced Julia programmers. I am roughly trying to mimic the structure 
 of CAMPOS ASE ( a Python package ).

 The main type that contains the simulation state is 

abstract AbstractAtoms

 The simplest sub-type is (here a simplified version)

 type Atoms
 X::Array{Float64, 2}#  positions of atoms
 calc #  calculator for computing 
 energies, forces, etc
 neigs   # neighbourlist
 precon # preconditioner
 end

 but there could be many other sub-types that store atom positions 
 differently, or live on manifolds, or contain information for continuum 
 mechanics boundary conditions, etc.

 I now need functions that depends on the type of the atoms object and on 
 the type of calculator object.  (for example). 

 OPTION 1:At the moment, my thinking is that I can do

function get_forces(atoms::AbstractAtoms)
return get_forces(atoms, atoms.calc)
end

 and the type of `atoms` and of `atoms.calc` will then determine which 
 function is called. This feels a bit clunky to be honest, but looks like 
 the best way to go?


 OPTION 2:  Another thought that I had, was to define

type Atoms{CT, NT, PT}
 X::Array{Float64, 2}#  positions of atoms
 calc::CT #  calculator for computing 
 energies, forces, etc
 neigs::NT   # neighbourlist
 precon::PT # preconditioner
 end

function get_forces(atoms::Atoms{MyCalculator,NT,PT})
# . . .
end

 and to determine the type of the calculator this way. The problem there is 
 that I cannot give AbstractAtoms the parameters {CT, NT, PT} because other 
 sub-types might use a different, possibly longer, possibly shorter list of 
 parameters.


 I'd be very grateful for any advise what sort of constructions would be 
 the most convenient / useful to try out here.

 Many thanks,
 Christoph







[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Josh Langsfeld
For me, option 1 looks the most Julian. Maybe the clunkiness is arising 
because the calc object shouldn't be a field of Atoms? Fields are just 
suppose to store data, not logic or methods. If a certain subtype of 
AbstractAtoms always uses the same calc object, then dispatching just on 
the atoms should be sufficient. If it can vary, maybe it would be more 
elegant to associate them together in some other way than a type field and 
then directly dispatch on both values.

Also, for option 2, why couldn't you give both AbstractAtoms and its 
subtypes just a single type parameter for the calculator?

and now it looks like proper Julian code where you pass objects to methods.

On Wednesday, February 4, 2015 at 10:16:02 AM UTC-5, Christoph Ortner wrote:


 I am trying to re-structure a molecular simulation code I've been working 
 on, to make it more readily extendable. I am puzzling over how to do this 
 most effectively in Julia, and would appreciate any thoughts from more 
 experienced Julia programmers. I am roughly trying to mimic the structure 
 of CAMPOS ASE ( a Python package ).

 The main type that contains the simulation state is 

abstract AbstractAtoms

 The simplest sub-type is (here a simplified version)

 type Atoms
 X::Array{Float64, 2}#  positions of atoms
 calc #  calculator for computing 
 energies, forces, etc
 neigs   # neighbourlist
 precon # preconditioner
 end

 but there could be many other sub-types that store atom positions 
 differently, or live on manifolds, or contain information for continuum 
 mechanics boundary conditions, etc.

 I now need functions that depends on the type of the atoms object and on 
 the type of calculator object.  (for example). 

 OPTION 1:At the moment, my thinking is that I can do

function get_forces(atoms::AbstractAtoms)
return get_forces(atoms, atoms.calc)
end

 and the type of `atoms` and of `atoms.calc` will then determine which 
 function is called. This feels a bit clunky to be honest, but looks like 
 the best way to go?


 OPTION 2:  Another thought that I had, was to define

type Atoms{CT, NT, PT}
 X::Array{Float64, 2}#  positions of atoms
 calc::CT #  calculator for computing 
 energies, forces, etc
 neigs::NT   # neighbourlist
 precon::PT # preconditioner
 end

function get_forces(atoms::Atoms{MyCalculator,NT,PT})
# . . .
end

 and to determine the type of the calculator this way. The problem there is 
 that I cannot give AbstractAtoms the parameters {CT, NT, PT} because other 
 sub-types might use a different, possibly longer, possibly shorter list of 
 parameters.


 I'd be very grateful for any advise what sort of constructions would be 
 the most convenient / useful to try out here.

 Many thanks,
 Christoph







[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner

Many thanks for the discussion.

On Wednesday, 4 February 2015 16:46:09 UTC, Josh Langsfeld wrote:

 For me, option 1 looks the most Julian. Maybe the clunkiness is arising 
 because the calc object shouldn't be a field of Atoms? Fields are just 
 suppose to store data, not logic or methods. 


Indeed, that is how I use them. But the Calculator stores, e.g., model 
parameters.
 

 If a certain subtype of AbstractAtoms always uses the same calc object, 
 then dispatching just on the atoms should be sufficient. 


Unfortunately, that is not the case.
 

 If it can vary, maybe it would be more elegant to associate them together 
 in some other way than a type field and then directly dispatch on both 
 values.


This was my initial thought as well. The problem with that is that the Atom 
and Calculator, NeighbourList and Preconditioner objects are linked: when 
Atoms is updated, then a message is sent to Calculator, Preconditioner 
and NeighbourList so that they can update themselves also. The Calculator, 
NeighbourList and Preconditioner objects in fact store additional data that 
is dependent on the data stored in Atoms.
 

 Also, for option 2, why couldn't you give both AbstractAtoms and its 
 subtypes just a single type parameter for the calculator?


Because the same issues arise for NeighbourLists, for Preconditioners and 
potentially other objects that will be linked to Atoms type objects.

I wonder whether I am making things too complicated here?


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner
I don't understand your domain of course, but the way I'd do this would be 
a slight variant of OPTION 1


 get_forces(a::AbstractAtom) = error(All AbstractAtom subtypes should 
 implement get_forces)
 get_forces(a::Atom) = get_forces(a.calc)


 this is indeed what I've done at the moment. Good to hear that this is not 
 completely idiotic. 


Ok, actually this is slightly different - so I don't understand why this 
would help?

Many thanks,
Christoph 

  



[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Josh Langsfeld
Sorry, disregard that last sentence which was supposed to have been edited 
out.

On Wednesday, February 4, 2015 at 11:46:09 AM UTC-5, Josh Langsfeld wrote:

 For me, option 1 looks the most Julian. Maybe the clunkiness is arising 
 because the calc object shouldn't be a field of Atoms? Fields are just 
 suppose to store data, not logic or methods. If a certain subtype of 
 AbstractAtoms always uses the same calc object, then dispatching just on 
 the atoms should be sufficient. If it can vary, maybe it would be more 
 elegant to associate them together in some other way than a type field and 
 then directly dispatch on both values.

 Also, for option 2, why couldn't you give both AbstractAtoms and its 
 subtypes just a single type parameter for the calculator?

 and now it looks like proper Julian code where you pass objects to methods.

 On Wednesday, February 4, 2015 at 10:16:02 AM UTC-5, Christoph Ortner 
 wrote:


 I am trying to re-structure a molecular simulation code I've been working 
 on, to make it more readily extendable. I am puzzling over how to do this 
 most effectively in Julia, and would appreciate any thoughts from more 
 experienced Julia programmers. I am roughly trying to mimic the structure 
 of CAMPOS ASE ( a Python package ).

 The main type that contains the simulation state is 

abstract AbstractAtoms

 The simplest sub-type is (here a simplified version)

 type Atoms
 X::Array{Float64, 2}#  positions of atoms
 calc #  calculator for computing 
 energies, forces, etc
 neigs   # neighbourlist
 precon # preconditioner
 end

 but there could be many other sub-types that store atom positions 
 differently, or live on manifolds, or contain information for continuum 
 mechanics boundary conditions, etc.

 I now need functions that depends on the type of the atoms object and on 
 the type of calculator object.  (for example). 

 OPTION 1:At the moment, my thinking is that I can do

function get_forces(atoms::AbstractAtoms)
return get_forces(atoms, atoms.calc)
end

 and the type of `atoms` and of `atoms.calc` will then determine which 
 function is called. This feels a bit clunky to be honest, but looks like 
 the best way to go?


 OPTION 2:  Another thought that I had, was to define

type Atoms{CT, NT, PT}
 X::Array{Float64, 2}#  positions of atoms
 calc::CT #  calculator for computing 
 energies, forces, etc
 neigs::NT   # neighbourlist
 precon::PT # preconditioner
 end

function get_forces(atoms::Atoms{MyCalculator,NT,PT})
# . . .
end

 and to determine the type of the calculator this way. The problem there 
 is that I cannot give AbstractAtoms the parameters {CT, NT, PT} because 
 other sub-types might use a different, possibly longer, possibly shorter 
 list of parameters.


 I'd be very grateful for any advise what sort of constructions would be 
 the most convenient / useful to try out here.

 Many thanks,
 Christoph







[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner
On Wednesday, 4 February 2015 16:59:14 UTC, Avik Sengupta wrote:

 I don't understand your domain of course, but the way I'd do this would be 
 a slight variant of OPTION 1

 get_forces(a::AbstractAtom) = error(All AbstractAtom subtypes should 
 implement get_forces)
 get_forces(a::Atom) = get_forces(a.calc)


 this is indeed what I've done at the moment. Good to hear that this is not 
 completely idiotic. 

 
Ok, actually this is slightly different - so I don't understand why this 
would help? Is it just the fact that not all implementations of 
AbstractAtoms need to have a field `calc`?

Many thanks,
Christoph  


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner
 thought one problem with not having proper inheritance is that this 
doesn't really help?


 I meant more about commonality of behaviour. 


I think this goes exactly in the direction that I discuss in the last post? 
I just assume for the Abstract versions of the different types how they 
will behave, and if they don't behave that way, then whoever wrote the 
extension (likely me anyhow) will need to overload the relevant methods. (?)

Thanks,
   Christoph



Re: [julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Josh Langsfeld
On Wed, Feb 4, 2015 at 2:29 PM, Christoph Ortner christophortn...@gmail.com
 wrote:

If I read this correctly, then what you are saying is that I am allowed to
 assume that my concrete abstract subtypes will contain certain fields, and
 if they don't then too bad for them, they need to go and re-implement some
 of the structure that I provide for AbstractAtoms.


Basically, if you know all subtypes of AbstractAtoms have a field 'num'
then 'getnumatoms(a::AbstractAtoms) = a.num' will work fine and will only
error if any new subtype doesn't have the field. However, if the
AbstractAtoms structure relies on that field existing and it doesn't make
sense to have it for a certain subtype, then the structure has to be
refactored to rely on methods instead, which can be (NOT must be)
reimplemented by the subtypes.

How about this then; in this case a new AbstractAtoms sub-type or a new
 AbstractCalculator sub-type would not need to implement the interface
 get_forces(a), but only the get_forces(a, c).


That would certainly work, though ideally there would be no need to defined
the interface to be coupled like that. There should be an abstraction of
all calculator types that would provide whatever methods get_forces needs
to do its thing. Or maybe it's reversed with specific Calculator types able
to depend on AbstractAtoms only. Either way, you wouldn't need a
get_forces(a,c) method for every possible type a and c can take.


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Josh Langsfeld
I'm very much enjoying thinking about this and considering what might be 
the most Julian approach

 I thought one problem with not having proper inheritance is that this 
doesn't really help? Even small variations across AbstractAtoms types 
require a full implementation?

Actually, I don't think there's any substantial difference with Julia's 
inheritance model. Because if the concrete types share field names, methods 
can still access those fields even when they only know they have an 
abstract type. And if the fields are different, then any inheritance model 
would require a new implementation. The only difference is that in the case 
of same-name fields, the declarations must be repeated for each concrete 
type, which a fairly mild tax given that a macro can do it easily.

 This was my initial thought as well. The problem with that is that the 
Atom and Calculator, NeighbourList and Preconditioner objects are linked: 
when Atoms is updated, then a message is sent to Calculator, 
Preconditioner and NeighbourList so that they can update themselves also. 
The Calculator, NeighbourList and Preconditioner objects in fact store 
additional data that is dependent on the data stored in Atoms.

 Because the same issues arise for NeighbourLists, for Preconditioners and 
potentially other objects that will be linked to Atoms type objects.
 
If you don't even know which objects will be linked when get_forces is 
first called, then I don't think you have any choice but to dispatch twice. 
First on the type of atoms, and second on the type of the internal 
variables, just as you did in your Option 1 code. But I think you can avoid 
the clunkiness by being a bit more fastidious about defining an interface 
for AbstractCalculator, AbstractPreConditioner, etc... and use those 
interface methods instead of just forwarding everything to a more 
specialized version of get_forces. That is, you might have something like 
getparam1(::AbstractCalculator) and then get_forces can directly send it 
a.calc without worrying exactly what type it is. But if the other object 
implementations are so different that no interface is possible, then yeah, 
I think you just have to write a different method for each possible 
combination of types.


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Avik Sengupta


On Wednesday, 4 February 2015 17:46:58 UTC, Christoph Ortner wrote:

 On Wednesday, 4 February 2015 16:59:14 UTC, Avik Sengupta wrote:

 I don't understand your domain of course, but the way I'd do this would 
 be a slight variant of OPTION 1

 get_forces(a::AbstractAtom) = error(All AbstractAtom subtypes should 
 implement get_forces)
 get_forces(a::Atom) = get_forces(a.calc)


 this is indeed what I've done at the moment. Good to hear that this is 
 not completely idiotic. 

  
 Ok, actually this is slightly different - so I don't understand why this 
 would help? Is it just the fact that not all implementations of 
 AbstractAtoms need to have a field `calc`?


Well, yes, that is one reason, but that may or may not be true in your 
case.  Mainly, the idea is to ensure that if some subtype fails to 
implement its get_forces method, then the error message will be explicit 
about what should be fixed. 

 thought one problem with not having proper inheritance is that this 
doesn't really help?

I meant more about commonality of behaviour. 
 


[julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner


On Wednesday, 4 February 2015 18:30:06 UTC, Josh Langsfeld wrote:

 I'm very much enjoying thinking about this and considering what might be 
 the most Julian approach

  I thought one problem with not having proper inheritance is that this 
 doesn't really help? Even small variations across AbstractAtoms types 
 require a full implementation?

 Actually, I don't think there's any substantial difference with Julia's 
 inheritance model. Because if the concrete types share field names, methods 
 can still access those fields even when they only know they have an 
 abstract type. And if the fields are different, then any inheritance model 
 would require a new implementation. The only difference is that in the case 
 of same-name fields, the declarations must be repeated for each concrete 
 type, which a fairly mild tax given that a macro can do it easily.


If I read this correctly, then what you are saying is that I am allowed to 
assume that my concrete abstract subtypes will contain certain fields, and 
if they don't then too bad for them, they need to go and re-implement some 
of the structure that I provide for AbstractAtoms.


 This was my initial thought as well. The problem with that is that the 
 Atom and Calculator, NeighbourList and Preconditioner objects are linked: 
 when Atoms is updated, then a message is sent to Calculator, 
 Preconditioner and NeighbourList so that they can update themselves also. 
 The Calculator, NeighbourList and Preconditioner objects in fact store 
 additional data that is dependent on the data stored in Atoms.

  Because the same issues arise for NeighbourLists, for Preconditioners 
 and potentially other objects that will be linked to Atoms type objects.
  
 If you don't even know which objects will be linked when get_forces is 
 first called, then I don't think you have any choice but to dispatch twice. 
 First on the type of atoms, and second on the type of the internal 
 variables, just as you did in your Option 1 code. But I think you can avoid 
 the clunkiness by being a bit more fastidious about defining an interface 
 for AbstractCalculator, AbstractPreConditioner, etc... and use those 
 interface methods instead of just forwarding everything to a more 
 specialized version of get_forces. That is, you might have something like 
 getparam1(::AbstractCalculator) and then get_forces can directly send it 
 a.calc without worrying exactly what type it is. But if the other object 
 implementations are so different that no interface is possible, then yeah, 
 I think you just have to write a different method for each possible 
 combination of types.



How about this then; in this case a new AbstractAtoms sub-type or a new 
AbstractCalculator sub-type would not need to implement the interface 
get_forces(a), but only the get_forces(a, c).

type Atoms : AbstractAtoms
   X
   calc
   neigs
   precon
end

get_forces(a::AbstractAtoms) = get_forces(a, a.calc)

or even, as Avik Sengupta suggests, if an AbstractCalculator  `c` has a 
field c.atoms, with   a.calc.atoms == a, then I could even call

get_forces(a::AbstractAtoms) = get_forces(a.calc)

function get_forces(a::AbstractAtoms, c::AbstractCalculator)
   ta = typeof(a); tc = typeof(c)
   error(get_forces(::$ta, ::$tc) has not been implemented)
end


Thanks, I really appreciate this discussion.
Christoph


 


Re: [julia-users] Re: Type Annotations and Overloading Question

2015-02-04 Thread Christoph Ortner


On Wednesday, 4 February 2015 20:02:43 UTC, Josh Langsfeld wrote:

 On Wed, Feb 4, 2015 at 2:29 PM, Christoph Ortner christop...@gmail.com 
 javascript: wrote:

 If I read this correctly, then what you are saying is that I am allowed to 
 assume that my concrete abstract subtypes will contain certain fields, and 
 if they don't then too bad for them, they need to go and re-implement some 
 of the structure that I provide for AbstractAtoms.


 Basically, if you know all subtypes of AbstractAtoms have a field 'num' 
 then 'getnumatoms(a::AbstractAtoms) = a.num' will work fine and will only 
 error if any new subtype doesn't have the field. However, if the 
 AbstractAtoms structure relies on that field existing and it doesn't make 
 sense to have it for a certain subtype, then the structure has to be 
 refactored to rely on methods instead, which can be (NOT must be) 
 reimplemented by the subtypes.


Yes, I see that - I was primarily concerned whether this was good style.

 

 How about this then; in this case a new AbstractAtoms sub-type or a new 
 AbstractCalculator sub-type would not need to implement the interface 
 get_forces(a), but only the get_forces(a, c).


 That would certainly work, though ideally there would be no need to 
 defined the interface to be coupled like that. There should be an 
 abstraction of all calculator types that would provide whatever methods 
 get_forces needs to do its thing. Or maybe it's reversed with specific 
 Calculator types able to depend on AbstractAtoms only. Either way, you 
 wouldn't need a get_forces(a,c) method for every possible type a and c can 
 take.


Indeed, most Calculators need no more than AbstractAtoms type information, 
but need to know nothing about which subtype.

After this discussion, I think this is the way I will go. Thanks a lot.
 Christoph