2

I have an optimisation algorithm which finds the best partition of a graph.

There are many measures for the quality of a partition (the variable being optimised), so I thought it would be a good idea to use function pointers to these quality functions, and pass that into my optimisation algorithm function.

This works fine, but the problem is different quality functions take some different arguments.

For example one quality function is find_linearised_stability and it requires a markov_time parameter:

float find_linearised_stability(cliques::Graph<T> &my_graph, cliques::Partition &my_partition,
                               std::vector<float> &markov_times, std::vector<float> &stabilities)

and is used in the optimisation function :

cliques::find_optimal_partition_louvain(my_new_graph, markov_times, &cliques::find_linearised_stability);

however another quality function find_modularityrequires no markov_time parameter. Of course I could just include it as an argument and not use it in the function but that seems like bad practice, and would get unwieldy once I start adding a lot of different quality functions.

What is a better design for this kind of situation?

3 Answers 3

6

Use function objects. One of those function objects can have a markov_time member that is passed in to the constructor:

struct find_linearised_stability {
    std::vector<float> & markov_times_;

    find_linearised_stability(std::vector<float> & markov_times)
        :markov_times_(markov_times)
    {}

    float operator () (cliques::Graph<T> &my_graph, cliques::Partition &my_partition,
                 std::vector<float> &stabilities)
    {
        // use markov_times_ in here, we didn't need to pass it since it's a member
    }
};

(you may need to make adjustments to constness/referenceness to suit your needs)

Then you can call your function like this:

cliques::find_optimal_partition_louvain(my_new_graph, cliques::find_linearised_stability(markov_times));

"what type for the function object do I use when declaring the ... function?"

Make it a function template that takes the function object type as a template parameter, thusly:

template<typename PR>
whatever find_optimal_partition_louvain(my_new_graph, PR & pr)
{
    ...
    pr(my_new_graph, partition, stabilities);
    ...
}
Sign up to request clarification or add additional context in comments.

6 Comments

Ok but then what type for the function object do I use when declaring the cliques::find_optimal_partition_louvain function?
@zenna -- Make it a function template, see updated answer for example.
@zenna -- Note that this also allows you to still pass in regular functions if you have some lying around that you don't feel like converting to function object classes.
If the "extra variable" is a kind which changes every iteration doesn't the programmer need to re-create the function object again and again? Doesn't have that a performance penalty?
@ssg -- The options are wide here, depending upon the programmer's needs. If this changing extra variable is modified every iteration(rather than using a completely different object), then you can just create a named function object and modify it's member every iteration.
|
2

Your only option is boost::bind or something like it stored in a boost::function or something like it.

If profiling shows that to be too slow then you'll be stuck with the "poor practice" version because any alternative is going to run afoul of UB and/or end up being just as 'slow' as the more reasonable alternative.

Comments

0
  1. parameter is not known before: add argument to every function (reference/pointer) that contains all info, every function uses whatever it needs
  2. parameter is known before: use boost::bind, e.g.:

sample source code:

#include <iostream>
#include <cstddef>
#include <algorithm>
#include <boost/bind.hpp>
using namespace std;

void output(int a, int b)
{
    cout << a << ", " << b << '\n';
}

int main()
{
    int arr[] = { 1, 2, 3, 4, 5 };
    for_each(arr, arr + 5, bind(output, 5, _1));
    return 0;
}

Outputs:

5, 1
5, 2
5, 3
5, 4
5, 5

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.