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

Ported DQM code to C++ #781

Open
wants to merge 36 commits into
base: main
Choose a base branch
from

Conversation

amahmudwave
Copy link

Ported all the dqm code to C++. Not making any attempt to rebase with upstream/main since there is a lot of divergence now.


self.bqm_.set_quadratic(cu, cv, bias)
self.dqm_.connect_variables(u,v)
Copy link
Author

Choose a reason for hiding this comment

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

@arcondello I put this line of code only for a test case to pass, I think I should remove it and modify the test case, instead

350 dqm.set_quadratic('a', 'b', {})
351
352 self.assertEqual(dqm.get_quadratic('a', 'b'), {})

since if we serialize this dqm, and de-serialize differences will arise, as connections among variables are recreated based on actual connections among cases. I can fix it in this PR or in a different PR (since this changes the original behaviour of the code, so far it just imitates)

Copy link
Member

Choose a reason for hiding this comment

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

Right, I know I told you the old behavior was a bug, but I think it is in fact meaningful for dqm.set_quadratic(u, v, {}) to set the interaction, but not biases. I know it's weird, but I suppose I can imagine a case where I populate the structure of the DQM before setting the biases where I would want to do that.

Copy link
Author

Choose a reason for hiding this comment

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

Okay I will keep it as it is, but we could always end up making at test case that fails due to this issue. We serialize with redundant connection, and the connection is not present in the deserialized one.

@amahmudwave
Copy link
Author

@arcondello This is ready for review, I guess we need some co-ordination to get it merged. I think merging will be better than rebasing in this case.


AdjVectorDQM() { case_starts_.push_back(0); }

explicit AdjVectorDQM(const AdjVectorDQM &dqm) {
Copy link
Member

Choose a reason for hiding this comment

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

This is probably a basic C++ question, but will this handle DQMs that are not of the same template type?

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 to dig deeper into it. I followed the AdjVectorBQM, which does use a template over here, but in the cppbqm.pxd file it has only the declaration for something like AdjVectorBQM(cons AdjVectorBQM & bqm), we are not passing a template parameter for specifying the type of the other BQM.

Copy link
Author

Choose a reason for hiding this comment

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

Templated it the way adjvectorbqm copy constructor is templated.

}

template <class io_variable_type, class io_bias_type>
void extract_data(io_variable_type *case_starts,
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 to_coo or something like that would be a better name.

Copy link
Member

Choose a reason for hiding this comment

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

Alternatively, since this is just reading the DQM, I think it makes sense to leave this code in cython.

return connected;
}

void connect_variables(variable_type u, variable_type v) {
Copy link
Member

Choose a reason for hiding this comment

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

should this be private and/or protected?

Copy link
Author

Choose a reason for hiding this comment

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

I made it private initially but the problem is for the bug I mentioned above this is needed, to create the connection in cython.

return false;
}

bool connection_present(variable_type u, variable_type v) {
Copy link
Member

Choose a reason for hiding this comment

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

should this be private and/or protected?

Copy link
Author

Choose a reason for hiding this comment

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

This needs to be used inside cython, to raise value error, when no connection is present.

return v;
}

bias_type get_linear_case(variable_type v, variable_type case_v) {
Copy link
Member

Choose a reason for hiding this comment

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

In the bqm I am switching to bias_type& linear(v) and I think bias_type& linear_case(u, v) would also be preferable to get/set.

Note that for setting to work with cython, you need some trickery. E.g.

        cdef bias_type *b = &(self.cppbqm.linear(v))
        b[0] = bias

In python there isn't really a notion of a reference/proxy object in the same way. So we'll want to keep get/set.

}

template <class io_variable_type, class io_bias_type>
void get_energies(io_variable_type *samples, int num_samples,
Copy link
Member

Choose a reason for hiding this comment

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

IMO it makes sense to just have a single method, bias_type energy(Iter sample_start). The user can then parallelize it themselves if they like.

}

template <class io_bias_type>
bool set_quadratic(variable_type u, variable_type v, io_bias_type *biases) {
Copy link
Member

Choose a reason for hiding this comment

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

I'd rather accept an iterator than a pointer (applies other places). Let me know if you disagree.

Copy link
Author

Choose a reason for hiding this comment

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

If we pass in an iterator while passing a pointer we are sort of hiding the real information, we can always use the pointer as an iterator. The thing is we might end up doing pointer arithmetic which does not look too good on an iterator.

Copy link
Member

Choose a reason for hiding this comment

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

I guess it seems to me that the iterator is the more general object. Specifically here we mean a random access iterator, since as you say we might end up doing arithmetic. But using an iterator instead would allow us to use strided arrays for instance.

Copy link
Member

Choose a reason for hiding this comment

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

Let me think about it a bit, this is also coming up in the BQM case.


self.bqm_.set_quadratic(cu, cv, bias)
self.dqm_.connect_variables(u,v)
Copy link
Member

Choose a reason for hiding this comment

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

Right, I know I told you the old behavior was a bug, but I think it is in fact meaningful for dqm.set_quadratic(u, v, {}) to set the interaction, but not biases. I know it's weird, but I suppose I can imagine a case where I populate the structure of the DQM before setting the biases where I would want to do that.

#ifndef DIMOD_ADJVECTORDQM_H_
#define DIMOD_ADJVECTORDQM_H_

#include <stdio.h>
Copy link
Member

Choose a reason for hiding this comment

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

Is this used?

Copy link
Author

Choose a reason for hiding this comment

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

Removed

@codecov-io
Copy link

codecov-io commented Jan 25, 2021

Codecov Report

Merging #781 (2e5e4c8) into main (f4d2744) will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #781   +/-   ##
=======================================
  Coverage   91.81%   91.81%           
=======================================
  Files          63       63           
  Lines        4667     4667           
=======================================
  Hits         4285     4285           
  Misses        382      382           

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f4d2744...2e5e4c8. Read the comment docs.

Copy link
Author

@amahmudwave amahmudwave left a comment

Choose a reason for hiding this comment

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

Addressed the review comments, regarding taking to_coo (previously extract_data) , if we want to parallelize it, it will be a lot of code, so I think its better to keep inside c++ instead of cython.


self.bqm_.set_quadratic(cu, cv, bias)
self.dqm_.connect_variables(u,v)
Copy link
Author

Choose a reason for hiding this comment

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

Okay I will keep it as it is, but we could always end up making at test case that fails due to this issue. We serialize with redundant connection, and the connection is not present in the deserialized one.


AdjVectorDQM() { case_starts_.push_back(0); }

explicit AdjVectorDQM(const AdjVectorDQM &dqm) {
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 to dig deeper into it. I followed the AdjVectorBQM, which does use a template over here, but in the cppbqm.pxd file it has only the declaration for something like AdjVectorBQM(cons AdjVectorBQM & bqm), we are not passing a template parameter for specifying the type of the other BQM.

return false;
}

bool connection_present(variable_type u, variable_type v) {
Copy link
Author

Choose a reason for hiding this comment

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

This needs to be used inside cython, to raise value error, when no connection is present.

return connected;
}

void connect_variables(variable_type u, variable_type v) {
Copy link
Author

Choose a reason for hiding this comment

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

I made it private initially but the problem is for the bug I mentioned above this is needed, to create the connection in cython.

}

template <class io_bias_type>
bool set_quadratic(variable_type u, variable_type v, io_bias_type *biases) {
Copy link
Author

Choose a reason for hiding this comment

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

If we pass in an iterator while passing a pointer we are sort of hiding the real information, we can always use the pointer as an iterator. The thing is we might end up doing pointer arithmetic which does not look too good on an iterator.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants