void reduce_pivots(MutableMatrix *M) { int nr = M->n_rows()-1; int nc = M->n_cols()-1; if (nr < 0 || nc < 0) return; const Ring *K = M->get_ring(); ring_elem one = K->one(); ring_elem minus_one = K->minus_one(); // After using the pivot element, it is moved to [nrows-1,ncols-1] // and nrows and ncols are decremented. MutableMatrix::iterator *p = M->begin(); for (int i=0; i<=nc; i++) { p->set(i); for (; p->valid(); p->next()) { int pivot_type = 0; ring_elem coef; p->copy_ring_elem(coef); if (K->is_equal(one, coef)) pivot_type = 1; else if (K->is_equal(minus_one, coef)) pivot_type = -1; if (pivot_type != 0) { perform_reduction(M, p->row(), i, nr--, nc--, pivot_type); if (nr < 0 || nc < 0) return; // restart loop with the (new) column i i = -1; break; } } } // Now search for other possible pivots for (int i=0; i<=nc; i++) { p->set(i); for (; p->valid(); p->next()) { ring_elem coef; p->copy_ring_elem(coef); if (!K->is_unit(coef)) continue; int pivot_type = 0; if (K->is_equal(one, coef)) pivot_type = 1; else if (K->is_equal(minus_one, coef)) pivot_type = -1; perform_reduction(M, p->row(), i, nr--, nc--, pivot_type); if (nr < 0 || nc < 0) return; // restart loop with the (new) column i i = -1; break; } } }
/* Graph reduction function. Destructively modifies the graph passed in. */ enum graphReductionResult reduce_graph(struct node *root) { enum graphReductionResult r = UNKNOWN; struct spine_stack *stack = NULL; unsigned long reduction_counter = 0; int max_redex_count = 0; /* Used to decide what to do next: * at an application (interior node of graph) * you can take the left branch into subtree, * take the right branch, or pop the node and * go "up" the tree. */ enum Direction { DIR_LEFT, DIR_RIGHT, DIR_UP }; enum Direction dir = DIR_LEFT; stack = new_spine_stack(64); /* root constitutes the "dummy" root node */ root->updateable = root->left_addr; pushnode(stack, root, 1); D print_graph(root, 0, TOPNODE(stack)->sn); while (STACK_NOT_EMPTY(stack)) { int pop_stack_cnt = 1; int performed_reduction = 0; struct node *topnode = TOPNODE(stack); const char *atom_name = NULL; switch (topnode->typ) { case APPLICATION: switch (dir) { case DIR_LEFT: topnode->updateable = topnode->left_addr; pushnode(stack, topnode->left, 0); D printf("push left branch on stack, depth now %d\n", DEPTH(stack)); pop_stack_cnt = 0; break; case DIR_RIGHT: topnode->updateable = topnode->right_addr; pushnode(stack, topnode->right, 2); D printf("push right branch on stack, depth now %d\n", DEPTH(stack)); pop_stack_cnt = 0; break; case DIR_UP: break; } break; case ATOM: /* node->typ indicates a combinator, which can comprise a built-in, * or it can comprise a mere variable. Let node->rule decide. */ if (topnode->rule && DEPTH(stack) >= (topnode->rule->required_depth + 2)) { D { atom_name = topnode->name; printf("%s reduction (sn %d), stack depth %d, before: ", topnode->name, topnode->sn, DEPTH(stack) ); print_graph(root->left, topnode->sn, topnode->sn); } pop_stack_cnt = topnode->rule->required_depth + 1; perform_reduction(stack); performed_reduction = 1; } else D { printf("%s atom, stack depth %d, required depth %d.\n", topnode->name, DEPTH(stack), topnode->rule? topnode->rule->required_depth + 2: -1 ); } if (performed_reduction) SS; break; }