Skip to content
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

Auto dispatch create methods in python #5118

Closed
wants to merge 6 commits into from
Closed

Auto dispatch create methods in python #5118

wants to merge 6 commits into from

Conversation

ghost
Copy link

@ghost ghost commented Sep 2, 2020

This fixes #4998 using the same technique that @gf712 suggested. I created a visitor for interface classes and changed the create method in class_list to accept the visitor. Then used this visitor in swig to transform the interface object to PyObject.

MachineEvaluation, StructuredModel, FactorType, ParameterObserver,
Distribution, GaussianProcess, Alphabet>;

namespace types_detail
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome!

class ShogunInterfaceToPyObject : public InterfaceTypeVisitor
{
public:
virtual void on(std::shared_ptr<SGObject>* v)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor thing, but now we are trying to always use override instead of overwriting virtual functions

Suggested change
virtual void on(std::shared_ptr<SGObject>* v)
void on(std::shared_ptr<SGObject>* v) override

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

override FTW

// to query the swig_type in run time and be less implementation dependent maybe?
// but this is faster and should not cause problems
#define SHOGUN_GET_SWIG_TYPE(name) \
SWIGTYPE_p_std__shared_ptrT_shogun__##name##_t
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if this can be generalised to the other swig interfaces?

Copy link
Author

@ghost ghost Sep 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming you mean the whole file. I would guess so. factory_python is a horrible name for that regard. Any name suggestions?
Edit: I will call it factory_visitors.i for now

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that's fine. And yes, I meant if you could for example template ShogunInterfaceToPyObject, and the template determines the interface object type, e.g. ShogunInterfaceFactory<PyObject>.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have two reasons not to:

  1. Added complexity without any other use case at the moment.
  2. After reading "GetterVisitor" I don't see any place for this visitor in the future (and maybe not for InterfaceClassVisitor either). Once the parameter framework and AnyVisitor support base types we can get rid of both new visitors, and use GetterVisitor directly, no?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since R is working now, I should make this generic as you suggested :"D

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so, that would be great! Then it could be easier to add other languages?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. This should work with octave as well.

nullptr, nullptr, SHOGUN_GET_SWIG_TYPE(SGObject),
SWIG_POINTER_OWN);
}
return m_pyobj;
Copy link
Member

@gf712 gf712 Sep 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even if it should not be possible to reach this, could you replace this with an exception? The worst thing that can happen is segfault in Python, because then the interpreter crashes. An exception can at least be handled gracefully

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case I return a python null object. I will change the function call to SWIG_Py_Void() to be more clear and add a comment.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scratch that. Throwing is better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, agreed, throwing would provide more information. Getting None from a factory might be odd for a user

@ghost
Copy link
Author

ghost commented Sep 2, 2020

I can see this visitor being integrated into the GetterVisitor (making AnyVisitor inherit from InterfaceTypeVisitor for example, and defaulting the new methods to on(SGObject)).
Does the parameter framework currently support "getting" objects of base classes?
If no, I think this structure should be good for now.

@gf712
Copy link
Member

gf712 commented Sep 2, 2020

Does the parameter framework currently support "getting" objects of base classes?

Not yet, it's been worked on in #4793

virtual void on(std::shared_ptr<ParameterObserver>*) = 0;
virtual void on(std::shared_ptr<Distribution>*) = 0;
virtual void on(std::shared_ptr<GaussianProcess>*) = 0;
virtual void on(std::shared_ptr<Alphabet>*) = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there could be a way to automatically generate this? Then again the base types probably do not change that often

Copy link
Author

@ghost ghost Dec 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do type erasure as follows

virtual void on(std::shared_ptr<void>*) = 0;

and then try to dynamic_cast for all base types one by one (with generic for loop on types) and dispatch to a generic on.

template <typename BaseClass>
void on(std::shared_ptr<BaseClass>*);

But this is slower.

Copy link
Author

@ghost ghost Dec 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can alaso manually construct the virtual table of on methods using a polymorphic lambda. So we would have something like

// vtable is constructed from one polymorphic lambda
std::tuple<std::function<void(std::shared_ptr<BaseClasses>*)>...> vtable;

template <typename BaseClass>
void on(std::shared_ptr<BaseClass>* ptr)
{
   std::get<TypeToIndex<BaseClass>::value>(this->vtable) (ptr);
}

This should be just as efficient as multiple virtual methods, but it requires complex code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the manual vtable is similar to what we have in Any and use in SGObject

void register_parameter_visitor() const

I wonder if the same logic could be used. I guess it would only be possible if we add another base class between SGObject and the "base" classes, where it would register types to be used (somehow) in the interfaces

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type erasure solution is kind of what we have/had in SGObject but we are moving away from that and just use visitor patterns.

@stale
Copy link

stale bot commented Jun 7, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Jun 7, 2021
@stale
Copy link

stale bot commented Jun 14, 2021

This issue is now being closed due to a lack of activity. Feel free to reopen it.

@stale stale bot closed this Jun 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

auto dispatch create methods in python
3 participants