X-DataInitiative / tick

Module for statistical learning, with a particular emphasis on time-dependent modelling
https://x-datainitiative.github.io/tick/
BSD 3-Clause "New" or "Revised" License
480 stars 105 forks source link

Add methods to C++ classes and make them available from Python #494

Closed claudio-ICL closed 1 year ago

claudio-ICL commented 1 year ago

Hi @PhilipDeegan

I am trying to customize tick on my machine. I would like to add a couple of methods to compute compensators of point processes. More precisely, I have added the methods activate_ctr, evaluate_compensator, and store_compensator_values to lib/include/tick/hawkes/simulation/simu_point_process.h

class DLL_PUBLIC PP {
[...]
public:
  void activate_ctr();                                                                                   
  virtual double evaluate_compensator(int, double) { return 0; }                                         
  void store_compensator_values();    
[...]
}

I would like to make evaluate_compensator and store_compensator_values available from Python. So, I have modified lib/swig/tick/hawkes/simulation/simu_point_process.i as follows:

%{
#include "tick/hawkes/simulation/simu_point_process.h"
%}

class PP {

 public :

  PP(unsigned int n_nodes, int seed = -1);
  virtual ~PP();

  void activate_itr(double dt);

  void simulate(double run_time);
  void simulate(ulong  n_points);
  void simulate(double run_time, ulong n_points);
  virtual void reset();
  //    bool flagThresholdNegativeIntensity;
  bool itr_on();

  double get_time();
  unsigned int get_n_nodes();
  int get_seed() const;
  ulong get_n_total_jumps();
  VArrayDoublePtrList1D get_itr();
  VArrayDoublePtr get_itr_times();
  double get_itr_step();
  VArrayDoublePtrList1D get_ctr();
  void store_compensator_values();
  virtual double evaluate_compensator(int, double);

  void reseed_random_generator(int seed);

  SArrayDoublePtrList1D get_timestamps();
  void set_timestamps(VArrayDoublePtrList1D &timestamps, double end_time);

  bool get_threshold_negative_intensity() const;
  void set_threshold_negative_intensity(const bool threshold_negative_intensity);
};

From the console, I run python setup.py build_ext --inplace and the C++ code compiles successfully. Unfortunately however, my new methods do not seem to be available from the Python interface. For example, given model as an instance of tick.hawkes.simulation.simu_hawkes_exp_kernels.SimuHawkesExpKernels, I get the following error when I try to call store_compensator_values:

In [11]: model._pp.store_compensator_value()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-11-2de48a8014aa> in <module>
----> 1 model._pp.store_compensator_value()

AttributeError: 'Hawkes' object has no attribute 'store_compensator_value'

Could you please explain how to add methods to the C++ class in lib/ and make them available ifrom the Python interface? Any help greatly appreciated! :)

PhilipDeegan commented 1 year ago

If you had built Tick in this directory sometime previously, you would have generated some new files when swig was run. I think, if these generated files are found, they are not remade, so you could have a mismatch.

an example of this generated file is lib/swig/tick/array/array_module_wrap.cpp

you can delete these files manually, or run python setup.py clean to reset your entire build

claudio-ICL commented 1 year ago

Hi @PhilipDeegan

That was it. Simply running python setup.py build_ext --inplace did not seem to pick up the changes in the swig interface file. I am not sure why.

However, a simple workaround was to first clean the result of previous build by running python setup.py clean, and then re-running python setup.py build_ext --inplace. This is a bit slower, because everything needs to be re-compiled, but it was enough to make me progress.

I believe we can close this issue.