C++ recursive function with max depth - c++

State class represents a game state. My goal is to traverse through all possible game states, and build up a game tree, a vector of Node classes (not present in this example).
I want to keep the memory usage as low as possible during the building of the tree, so only the growing number of the Nodes should take up memory, not the traversing of the possible states. So any guidance is more than welcome.
#include <iostream>
#include <vector>
class State {
public:
State step(int action) {
State new_state(*this);
return new_state;
};
std::vector<int> legal_actions() {
std::vector<int> v = {7, 5, 1};
return v;
}
};
void build_tree(State &state, int depth = 0) {
if (depth == 2) {
return;
}
std::vector<int> actions = state.legal_actions();
for (auto action : actions) {
std::cout << "action: " << action << " depth: " << depth << std::endl;
State new_state = state.step(action);
build_tree(state, ++depth);
}
}
int main() {
State state;
build_tree(state);
return 0;
}
One of the problem with this code, that the traversal wont stop at depth 1.
action: 7 depth: 0
action: 7 depth: 1
action: 5 depth: 2
action: 7 depth: 3
action: 7 depth: 4
action: 7 depth: 5
action: 7 depth: 6
action: 7 depth: 7
action: 7 depth: 8
action: 7 depth: 9
... and so on
I would expect a game tree like this
And an output like this:
action: 7 depth: 0
action: 7 depth: 1
action: 5 depth: 1
action: 1 depth: 1
action: 5 depth: 0
action: 7 depth: 1
action: 5 depth: 1
action: 1 depth: 1
action: 1 depth: 0
action: 7 depth: 1
action: 5 depth: 1
action: 1 depth: 1

If you remove all the unnecessary stuff and only look at the bare-bones structure, you get this:
void build_tree(int depth = 0) {
if (depth == 2) {
return;
}
for (int i = 0; i < 3; i++) {
build_tree(++depth);
}
}
int main() {
build_tree(0);
}
Now, since you increment depth, build_tree(0) will call in turn build_tree(1), build_tree(2), and build_tree(3).
The build_tree(1) will call in turn build_tree(2), build_tree(3), and build_tree(4).
And now you should be able to see that the reason that it never ends is that you only stop when depth is exactly 2; if it's 3 or more you just keep going.
The main problem is that you wrote ++depth where you should have written depth+1, building all three children at the same depth.
(Side effects are tricky, mmkay?)
The other problem is that your condition for terminating the recursion is too specific, although changing the condition would only make sure it terminates but wouldn't give the correct result.

Related

Find all interleavings of given strings that can be formed from all the characters of first and second string where order of characters is preserved

I am trying to find all interleavings of given strings that can be formed from all the characters of first and second string where order of characters is preserved
I tried to use recursion.
// This code works[Snippet 1]
void func(string str1,string str2,string temp){
if(!str1.length() && !str2.length()){
cout << temp << endl;
return;
}
if(str1.length()){
func(str1.substr(1),str2,temp+str1[0]);
}
if(str2.length()){
func(str1,str2.substr(1),temp+str2[0]);
}
}
// This code does not work[Snippet 2]
void func(string str1,string str2,string temp){
if(!str1.length() && !str2.length()){
cout << temp << endl;
return;
}
if(str1.length()){
temp+=str1[0];
func(str1.substr(1),str2,temp);
}
if(str2.length()){
temp+=str2[0];
func(str1,str2.substr(1),temp);
}
}
The difference between snippet 1 and snippet 2 is that in snippet 2, I have appended the temp string with the character before passing it into the function. The second code gives result(string) whose size is greater than sum of length of both input strings.
Here's a version with plenty of cout and a way to track recursion depth.
#include <iostream>
#include <string>
using namespace std;
void func0(string str1, string str2, string temp, int depth) {
if (!str1.length() && !str2.length()) {
cout << temp << endl;
depth--;
return;
}
if (str1.length()) {
cout << "depth: " << depth++ << "|temp: " << temp << '\n';
func0(str1.substr(1), str2, temp + str1[0], depth);
}
if (str2.length()) {
cout << "depth: " << depth++ << "|temp: " << temp << '\n';
func0(str1, str2.substr(1), temp + str2[0], depth);
}
depth--;
}
void func1(string str1, string str2, string temp, int depth) {
if (!str1.length() && !str2.length()) {
cout << temp << endl;
depth--;
return;
}
if (str1.length()) {
temp += str1[0]; //temp has
cout << "depth: " << depth++ << "|temp: " << temp << '\n';
func1(str1.substr(1), str2, temp, depth);
}
if (str2.length()) {
temp += str2[0];
cout << "depth: " << depth++ << "|temp: " << temp << '\n';
func1(str1, str2.substr(1), temp, depth);
}
depth--;
}
int main(int argc, char* argv[]) {
string a = "asd";
string b = "qw";
string c = "";
cout << "func0\n";
func0(a, b, c, 0);
cout << "func1\n";
func1(a, b, c, 0);
return 0;
}
which yields this output for func0:
func0
depth: 0|temp:
depth: 1|temp: a
depth: 2|temp: as
depth: 3|temp: asd
depth: 4|temp: asdq
asdqw
depth: 3|temp: as
depth: 4|temp: asq
depth: 5|temp: asqd
asqdw
depth: 5|temp: asq
depth: 6|temp: asqw
asqwd
depth: 2|temp: a
depth: 3|temp: aq
depth: 4|temp: aqs
depth: 5|temp: aqsd
aqsdw
depth: 5|temp: aqs
depth: 6|temp: aqsw
aqswd
depth: 4|temp: aq
depth: 5|temp: aqw
depth: 6|temp: aqws
aqwsd
depth: 1|temp:
depth: 2|temp: q
depth: 3|temp: qa
depth: 4|temp: qas
depth: 5|temp: qasd
qasdw
depth: 5|temp: qas
depth: 6|temp: qasw
qaswd
depth: 4|temp: qa
depth: 5|temp: qaw
depth: 6|temp: qaws
qawsd
depth: 3|temp: q
depth: 4|temp: qw
depth: 5|temp: qwa
depth: 6|temp: qwas
qwasd
and this for func1:
func1
depth: 0|temp: a
depth: 1|temp: as
depth: 2|temp: asd
depth: 3|temp: asdq
depth: 4|temp: asdqw
asdqw
depth: 3|temp: asdq
depth: 4|temp: asdqd
depth: 5|temp: asdqdw
asdqdw
depth: 5|temp: asdqdw
depth: 6|temp: asdqdwd
asdqdwd
depth: 2|temp: asq
depth: 3|temp: asqs
depth: 4|temp: asqsd
depth: 5|temp: asqsdw
asqsdw
depth: 5|temp: asqsdw
depth: 6|temp: asqsdwd
asqsdwd
depth: 4|temp: asqsw
depth: 5|temp: asqsws
depth: 6|temp: asqswsd
asqswsd
depth: 1|temp: aq
depth: 2|temp: aqa
depth: 3|temp: aqas
depth: 4|temp: aqasd
depth: 5|temp: aqasdw
aqasdw
depth: 5|temp: aqasdw
depth: 6|temp: aqasdwd
aqasdwd
depth: 4|temp: aqasw
depth: 5|temp: aqasws
depth: 6|temp: aqaswsd
aqaswsd
depth: 3|temp: aqaw
depth: 4|temp: aqawa
depth: 5|temp: aqawas
depth: 6|temp: aqawasd
aqawasd
To help see the recursion look at the correct output when depth is 1 as the first level of a tree with 2 branches. They should be just the first characters of each string. Now each of those nodes get children for each remaining character. At the next lower level (depth 2), you add a character then each of those nodes gets children to create level/depth 3...etc. It builds a trie when done correctly and temp only changes length once at each depth.
In both, you bottom out and print when you reach a leaf.
In the incorrect version, you'll see that length of temp is inconsistent in a given depth of the recursion. As already said but in a different way, appending to temp and storing it locally (which can also be thought of as appending while still in a row/level/depth of the trie) causes length of temp to grow both left to right and top to bottom.
I think you should use std::next_permutation(). For the first string, add for each character a 0 to a vector. Do the same for the second string with a 1. Now you have one vector to permutate. For each permutation, simply remap the indices back to the next character in first string if it is even and second when odd.
Example permutation : "cat", "bird" to (0 0 0 1 1 1 1), one permutation becomes (0 1 1 0 1 0 1 ) which you can remap to "cbiartd"

C++ Pointer at array is printing values way past the array size [duplicate]

This question already has answers here:
Accessing an array out of bounds gives no error, why?
(18 answers)
indexing past the end of C arrays [duplicate]
(2 answers)
How dangerous is it to access an array out of bounds?
(12 answers)
How do I find the length of an array?
(30 answers)
Closed 4 years ago.
I am planning on turning this code into a quick sort application, but I am using arrays, something I have not done since discovering vectors and becoming very spoiled with them. This leads me to this code.
int main() {
int numbers[] = { 6, 5, 1, 3, 8, 4, 7, 9, 2};
int* pivot; // will be used later when I implement quicksorting
int currentElement = numbers[0]; //will be used for quicksorting
std::cout<< "\n" << currentElement << "\n" << std::endl;
int *ptr = numbers;
for(int x = 0; x < sizeof(numbers); x++)
{
std::cout << "value at index: - " << x << " is: " << *(ptr + x) << std::endl;
}
return 0;
}
I am receiving this output.
5
value at index: - 0 is: 6
value at index: - 1 is: 5
value at index: - 2 is: 1
value at index: - 3 is: 3
value at index: - 4 is: 8
value at index: - 5 is: 4
value at index: - 6 is: 7
value at index: - 7 is: 9
value at index: - 8 is: 2
value at index: - 9 is: -858993460
value at index: - 10 is: 1211635769
value at index: - 11 is: 5241484
value at index: - 12 is: 12658446
value at index: - 13 is: 1
value at index: - 14 is: 6877496
value at index: - 15 is: 6875200
value at index: - 16 is: 5241572
value at index: - 17 is: 12658033
value at index: - 18 is: 1211635877
value at index: - 19 is: 12652609
value at index: - 20 is: 12652609
value at index: - 21 is: 4116480
value at index: - 22 is: 0
value at index: - 23 is: 0
value at index: - 24 is: 0
value at index: - 25 is: 0
value at index: - 26 is: 0
value at index: - 27 is: 0
value at index: - 28 is: 0
value at index: - 29 is: 12694900
value at index: - 30 is: 12694912
value at index: - 31 is: 0
value at index: - 32 is: 5241492
value at index: - 33 is: 0
value at index: - 34 is: 5241664
value at index: - 35 is: 12665872
Process finished with exit code 0
The main question I have is why am I getting values in indexes past index 8? (value 2)
How do those even exist? Is this because the declaration I made at int numbers[] does not have a specified array size? The reason why I have that in the first place is I intend to populate the array with a random number generator with my quick sort algorithm, essentially treating the array like a vector. I know that this is illegal, but I am simply trying to relearn arrays, so I can be comfortable in other languages with them, as vectors do not exist in many others.
Am I getting these phantom indexes because the array allocation has a default block of memory that it takes if an array size is not specified, or is that already implicitly defined with the manual population of the array that I did with the values supplied in the curly braces and maybe that is causing the pointer to continue?

2 Dimensional Vector trying to copy "down" does not seem to work

I am generating hadamard matrices where for any 2d matrix "M" the next matrix is:
M, M
M,-M
e.g.
Matrix starts with a 1x1 matrix with value "1", such that:
1 (x) 1, 1 = 1, 1
1,-1 1,-1
1, 1 (x) 1, 1 = 1, 1, 1, 1
1,-1 1,-1 1,-1, 1,-1
1, 1,-1,-1
1,-1,-1, 1
And so on... see here
So I have a type:
typedef std::vector<std::vector<char>> matrix_t;
In my constructor I set the matrix to the start value:
hadamard::hadamard() :
m_matrix{{1}}
{
}
So to make the next matrix I decided I could copy the rows (a repeat copy) and then copy the complete matrix (again a repeat copy):
void hadamard::generate_next(matrix_t& matrix, size_t size)
{
if (matrix.size() < size)
{
hadamard::print_matrix(matrix, "before");
// Copy the matrix into 4: M1 | M2
// ---+---
// M3 | M4
// For each inner vector - copy it (double up)
for(auto& row : matrix)
{
// Double up the row
row.insert(row.end(), row.begin(), row.end());
}
// For the outer vector - copy it (double up)
matrix.insert(matrix.end(), matrix.begin(), matrix.end());
// Invert chars in M4 (see diagram above)
TODO
hadamard::print_matrix(matrix, "after");
// Ok, feeling brave, now call recursively...
generate_next(matrix, size);
}
}
Just for completeness here is my print function:
static void print_matrix(matrix_t& matrix, const char * title)
{
printf("%s\r\n", title);
printf("Dimensions - rows: %d, cols: %d\r\n", matrix.size(), matrix[0].size());
int row = 1;
for(auto& line : matrix)
{
printf("NEW LINE\r\n");
int col = 1;
for (auto& item : line)
{
printf("item(%d, %d): %d\r\n", row, col, item);
++col;
}
++row;
}
}
The output I get is like this:
before
Dimensions - rows: 1, cols: 1
NEW LINE
item(1, 1): 1
after
Dimensions - rows: 2, cols: 2
NEW LINE
item(1, 1): 1
item(1, 2): 1
NEW LINE
<HERE SHOULD BE A COPY OF THE PREVIOUS "LINE">
You can see from the output that the inner copy works ok - I guess this is because I am working on std::vector so the inner data is chars.
But the outer copy does not work, I think this is something this vector being a "vector of vectors" (the full type is std::vector<std::vector<char>>).
So basically the line:
// For the outer vector - copy it (double up)
matrix.insert(matrix.end(), matrix.begin(), matrix.end());
does appear to double the size of matrix but it does not copy the data.
Why does it not copy the data? - is it because a deep copy is needed?
Also, what is an efficient way to do this?
In the mean time I am going to manually copy the data across from each row... just to prove to myself that I can do it!
UPDATE
Ok, I "think" I have a really simple fix.... may not be the best way?
for(auto& row : matrix)
{
// Double up the row
row.insert(row.end(), row.begin(), row.end());
// Now copy the row down as well
matrix.insert(matrix.end(), row);
}
But my previous questions still stand!
UPDATE 2
No, the last code change "seemed" to work, at least for the first iteration... but once I start re-cursing through it breaks down...
I have updated the "recursion" so it re-curses, I had not written that code properly... now I get the output:
HADAMARD MATRIX GENERATOR
Generating HM for index 2 - dimensions: 4x4, size: 16
before
Dimensions - rows: 1, cols: 1
1
after
Dimensions - rows: 2, cols: 2
1 1
1 1
before
Dimensions - rows: 2, cols: 2
1 1
1 1
after
Dimensions - rows: 4, cols: 4
1 1 1 1
1 1
1 1 1 1
before
Dimensions - rows: 4, cols: 4
1 1 1 1
1 1
1 1 1 1
after
Dimensions - rows: 8, cols: 8
1 1 1 1 1 1 1 1
1 1
1 1 1 1
1 1 1 1 1 1 1 1
So, its not going well at all! - I am thinking the concatenation of my vectors is all wrong?...

Knapsack displaying all sub sets

I am having difficulty implementing a particular variation of the knapsack problem. the prompt wants every possible subset of items to be displayed like so.
set 1: {} => capacity: 0, value: $0
set 2: {1} => capacity: 3, value: $12
set 3: {2} => capacity: 4, value: $10
set 4: {1,2} => capacity: 7 – over capacity, value: N/A
Solution: {1} => capacity: 3, value: $12
I have implemented an algorithm to just give me the max value (which would be 12 in the example above) and that works fine. But I think I would have to change my approach completely in order to achieve the wanted output. Any Ideas would be greatly appreciated.
int knapSack(int W, int wt[], int val[], int n)
{
int i, w;
int K[n + 1][W + 1];
// Build table K[][] in bottom up manner
for (i = 0; i <= n; i++)
{
for (w = 0; w <= W; w++)
{
if (i == 0 || w == 0)
K[i][w] = 0;
else if (wt[i - 1] <= w)
K[i][w]
= max(val[i - 1] + K[i - 1][w - wt[i - 1]], K[i - 1][w]);
else
K[i][w] = K[i - 1][w];
}
}
return K[n][W];
}

Updating priorities in a boost::d_ary_heap_indirect

I am using a d_ary_heap_indirect as a priority queue (to process items with the highest priority first) using a property map to store the priorities. However, when I change the values in the priority property map and push vertices that are already in the queue into the queue again, it results in kind of an invalid state where the vertex appears in the queue twice at different positions.
Here is a demo:
#include <iostream>
#include <iomanip>
#include <boost/graph/grid_graph.hpp>
#include <boost/graph/detail/d_ary_heap.hpp>
#include <boost/property_map/property_map.hpp>
#include <cstdlib>
template <typename TQueue>
static void OutputQueue(TQueue queue);
int main(int, char*[])
{
srand((unsigned int)time(NULL));
srand48((unsigned int)time(NULL));
boost::array<std::size_t, 2> lengths = { { 2,2 } };
typedef boost::grid_graph<2> GraphType;
GraphType graph(lengths);
typedef boost::graph_traits<GraphType>::vertex_descriptor Vertex;
typedef boost::property_map<GraphType, boost::vertex_index_t>::const_type GridIndexMapType;
GridIndexMapType gridIndexMap(get(boost::vertex_index, graph));
typedef boost::vector_property_map<std::size_t, GridIndexMapType> IndexInHeapMap;
IndexInHeapMap index_in_heap(gridIndexMap);
typedef boost::graph_traits<GraphType>::vertex_iterator VertexIteratorType;
typedef boost::vector_property_map<float, GridIndexMapType> PriorityMapType;
PriorityMapType priorityMap(gridIndexMap);
VertexIteratorType vertexIterator, vertexIteratorEnd;
typedef std::greater<float> ComparisonFunctor;
typedef boost::d_ary_heap_indirect<Vertex, 4, IndexInHeapMap, PriorityMapType, ComparisonFunctor > MutableQueueType;
ComparisonFunctor comparisonFunctor;
MutableQueueType mutableQueue(priorityMap, index_in_heap, comparisonFunctor);
std::cout << "There are " << mutableQueue.size() << " items in the queue." << std::endl;
// Add random values to the vertices and add them to the queue
for( tie(vertexIterator, vertexIteratorEnd) = vertices(graph); vertexIterator != vertexIteratorEnd; ++vertexIterator)
{
put(priorityMap, *vertexIterator, rand() % 1000);
}
for( tie(vertexIterator, vertexIteratorEnd) = vertices(graph); vertexIterator != vertexIteratorEnd; ++vertexIterator)
{
mutableQueue.push(*vertexIterator);
}
std::cout << "There are " << mutableQueue.size() << " items in the queue." << std::endl;
std::cout << "The priority queue is: " << std::endl;
OutputQueue(mutableQueue);
// Insert another set of random values for each vertex
for( tie(vertexIterator, vertexIteratorEnd) = vertices(graph); vertexIterator != vertexIteratorEnd; ++vertexIterator)
{
float newPriority = rand() % 1000;
std::cout << "New priority for " << vertexIterator->operator[](0) << ", " << vertexIterator->operator[](1) << " " << newPriority << std::endl;
put(priorityMap, *vertexIterator, newPriority);
}
for( tie(vertexIterator, vertexIteratorEnd) = vertices(graph); vertexIterator != vertexIteratorEnd; ++vertexIterator)
{
//mutableQueue.push(*vertexIterator); // This makes sense that the queue would not end up sorted
mutableQueue.push_or_update(*vertexIterator); // I thought this one should work
//mutableQueue.update(*vertexIterator); // This one actually seems to UNsort the queue?
}
std::cout << "There are " << mutableQueue.size() << " items in the queue." << std::endl;
std::cout << "The priority queue is: " << std::endl;
OutputQueue(mutableQueue);
std::cout << std::endl;
return 0;
}
template <typename TQueue>
static void OutputQueue(TQueue queue)
{
while( ! queue.empty() )
{
typename TQueue::value_type u = queue.top();
// These two lines are equivalent
std::cout << "vertex: " << u[0] << " " << u[1] << " priority: " << get(queue.keys(), u) << std::endl;
queue.pop();
}
}
And a demo output:
There are 0 items in the queue.
There are 4 items in the queue.
The priority queue is:
vertex: 1 1 priority: 445
vertex: 0 0 priority: 150
vertex: 0 1 priority: 84
vertex: 1 0 priority: 0
New priority for 0, 0 769
New priority for 1, 0 870
New priority for 0, 1 99
New priority for 1, 1 211
There are 8 items in the queue.
The priority queue is:
vertex: 0 0 priority: 769
vertex: 1 0 priority: 870
vertex: 1 0 priority: 870
vertex: 0 0 priority: 769
vertex: 1 1 priority: 211
vertex: 1 1 priority: 211
vertex: 0 1 priority: 99
vertex: 0 1 priority: 99
The demo simply sets random priority values for every vertex, and pushes them all into the queue. It then does exactly the same thing again. You can see in the output that some of the items appear in the queue at different positions (not back-to-back, as I would expect, since they reference the same priority value in the PriorityMap).
The problem is that item (0,0) (with new priority 769) appears above vertex (1,0) with priority 870. This would cause the items to be processed in the wrong order.
Is there a way to replace an item in the queue when it is pushed instead of adding a second one? (like an std::set instead of the current behavior which is like std::multiset)?
--------- Edit ------------
In the "// Insert another set of random values for each vertex" loop, I replaced the 'mutableQueue.push(*vertexIterator)' with :
mutableQueue.push_or_update(*vertexIterator);
Unfortunately it doesn't do what I'd expect - the output is now:
There are 0 items in the queue.
New priority for 0, 0 150
New priority for 1, 0 522
New priority for 0, 1 27
New priority for 1, 1 883
There are 4 items in the queue.
The priority queue is:
vertex: 1 1 priority: 883
vertex: 1 0 priority: 522
vertex: 0 0 priority: 150
vertex: 0 1 priority: 27
New priority for 0, 0 658
New priority for 1, 0 591
New priority for 0, 1 836
New priority for 1, 1 341
There are 7 items in the queue.
The priority queue is:
vertex: 0 1 priority: 836
vertex: 0 1 priority: 836
vertex: 0 0 priority: 658
vertex: 0 0 priority: 658
vertex: 1 0 priority: 591
vertex: 1 0 priority: 591
vertex: 1 1 priority: 341
Further, replacing the push() with just update() produces:
There are 0 items in the queue.
New priority for 0, 0 806
New priority for 1, 0 413
New priority for 0, 1 592
New priority for 1, 1 861
There are 4 items in the queue.
The priority queue is:
vertex: 1 1 priority: 861
vertex: 0 0 priority: 806
vertex: 0 1 priority: 592
vertex: 1 0 priority: 413
New priority for 0, 0 175
New priority for 1, 0 642
New priority for 0, 1 991
New priority for 1, 1 462
There are 4 items in the queue.
The priority queue is:
vertex: 1 1 priority: 462
vertex: 0 1 priority: 991
vertex: 1 0 priority: 642
vertex: 0 0 priority: 175
There are now only 4 items (like I would expect), but they are not sorted!
----------- Edit - more information --------------
I think there is something going wrong with the index_in_heap map. I added:
std::cout << "Index added: " << get(index_in_heap, v) << std::endl;
after this line:
put(index_in_heap, v, index);
in d_ary_heap_indirect::push(Value).
I also added
std::cout << "Index added caller: " << get(index_in_heap, v) << std::endl;
after the first round of adding values to the queue (after this line:
mutableQueue.push(*vertexIterator);
The output is:
Original priority for 0, 0 641
Index added: 0
Index added caller: 0
Original priority for 1, 0 40
Index added: 1
Index added caller: 1
Original priority for 0, 1 400
Index added: 2
Index added caller: 2
Original priority for 1, 1 664
Index added: 3
Index added caller: 0
I don't understand why this last index is 3 inside the push()
function, but 0 when I query it from the caller?
When I look at the same things inside the update() function, the
index_in_heap just seems to return garbage. That is, I look at the
value of size_type index = get(index_in_heap, v); in update(), and
when it is called with vertex (0,0), the value of 'index' is
4294967295 (when I would expect it to be in the range [0,3]).
Can anyone explain this? Perhaps I am setting up the index_in_heap map incorrectly?
The priority queue won't update its structure when you just change the priorities of the nodes. Once a node is inserted you need to consider its priority constant. If you need to update the priorities you need to tell the priority queue about this. To this end you need to tell it which node gets what new priority.
Unfortunately, tracking some sort of node identification and priority makes the priority queues slow: for a d-heap it is necessay to track where the node moved, making updates relatively expensive. For node-based heaps, e.g., Fibonacci-heaps, the node stays put but the tend to be more expensive to maintain (Fibonacci-heaps have interesting theoretical complexity which, however, only matters for impractically sized problems). I haven't come up with any middle-ground although I implemented all approaches to priority queues I could find described in books.
The d_ary_heap_indirect is designed to only allow priorities to increase. If in the update() and push_or_update() functions you change:
preserve_heap_property_up(index);
to
preserve_heap_property_up(index);
preserve_heap_property_down();
it seems to allow increasing or decreasing the priorities while keeping the queue sorted.