https://hal.archives-ouvertes.fr/hal-03445821
exact.c
/*
Copyright Universite de Versailles Saint-Quentin en Yvelines 2009
AUTHORS: Sebastien Briais, Sid Touati
This file is part of RS.
RS is free software: you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
RS is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with RS. If not, see
<http://www.gnu.org/licenses/>.
*/
#include <SCEDA/list.h>
#include <SCEDA/graph.h>
#include <SCEDA/graph_dag.h>
#include <SCEDA/common.h>
#include <SCEDA/graph_antichain.h>
#include "util.h"
#include "exact.h"
#include "pkill.h"
#include "dvk.h"
#include "extk.h"
#include <sys/time.h>
static double ellapsed_time(struct timeval *t0, struct timeval *t1) {
return ((double)(t1->tv_sec - t0->tv_sec)) + ((double)(t1->tv_usec - t0->tv_usec))/((double)1000000);
}
// reflect the choice "u killed by ku" in G_k
// nodes are given in PK(G), so this is rather "u in PK(G) killed by ku in PK(G)"
static SCEDA_List *update_choice(SCEDA_Graph *gk, SCEDA_HashMap *g_to_gk, SCEDA_Vertex *u_pk, SCEDA_Vertex *ku_pk) {
SCEDA_List *new_edges = SCEDA_list_create(NULL);
// translate PK(G) vertices into G vertices
SCEDA_Vertex *ku = SCEDA_vertex_get_data(SCEDA_Vertex *, ku_pk);
// get Gk translation
SCEDA_Vertex *ku_k = SCEDA_hashmap_get(g_to_gk, ku);
// add edges from potential killers of u to chosen killer of u
SCEDA_VertexSuccIterator succ;
SCEDA_vertex_succ_iterator_init(u_pk, &succ);
while(SCEDA_vertex_succ_iterator_has_next(&succ)) {
SCEDA_Vertex *v_pk = SCEDA_vertex_succ_iterator_next(&succ);
if(v_pk != ku_pk) {
SCEDA_Vertex *v = SCEDA_vertex_get_data(SCEDA_Vertex *, v_pk);
SCEDA_Vertex *v_k = SCEDA_hashmap_get(g_to_gk, v);
SCEDA_Edge *e = SCEDA_graph_add_edge(gk, v_k, ku_k, NULL);
safe_call(SCEDA_list_add(new_edges, e));
}
}
SCEDA_vertex_succ_iterator_cleanup(&succ);
return new_edges;
}
static void undo_choice(SCEDA_Graph *gk, SCEDA_List *new_edges) {
SCEDA_ListIterator edges;
SCEDA_list_iterator_init(new_edges, &edges);
while(SCEDA_list_iterator_has_next(&edges)) {
SCEDA_Edge *e = SCEDA_list_iterator_next(&edges);
void *data = NULL;
SCEDA_graph_remove_edge(gk, e, &data);
}
SCEDA_list_iterator_cleanup(&edges);
SCEDA_list_clear(new_edges);
}
static SCEDA_Graph *RS_ddag_dvk_opt(GDD_DAG *ddg, const char *type, SCEDA_Graph *pkg, SCEDA_HashMap *killing_map, SCEDA_Graph *g_extk) {
SCEDA_Graph *dvk_g = SCEDA_graph_create(NULL, NULL);
SCEDA_Graph *g = GDD_dag_get_ddg(ddg);
SCEDA_HashMap *g_to_dvkg = SCEDA_vertex_map_create(NULL);
{
SCEDA_VerticesIterator g_vertice;
SCEDA_vertices_iterator_init(g, &g_vertice);
while(SCEDA_vertices_iterator_has_next(&g_vertice)) {
SCEDA_Vertex *v = SCEDA_vertices_iterator_next(&g_vertice);
if(GDD_vertex_is_value_of_type(v, type)) {
SCEDA_Vertex *dvv = SCEDA_graph_add_vertex(dvk_g, v);
SCEDA_hashmap_put(g_to_dvkg, v, dvv, NULL);
}
}
SCEDA_vertices_iterator_cleanup(&g_vertice);
}
SCEDA_Graph *g_extk_closure = SCEDA_graph_transitive_closure(g_extk);
SCEDA_HashMap *g_to_g_extk_closure = SCEDA_vertex_map_create(NULL);
{
SCEDA_VerticesIterator vertices;
SCEDA_vertices_iterator_init(g_extk_closure, &vertices);
while(SCEDA_vertices_iterator_has_next(&vertices)) {
SCEDA_Vertex *v_extk_closure = SCEDA_vertices_iterator_next(&vertices);
SCEDA_Vertex *v_extk = SCEDA_vertex_get_data(SCEDA_Vertex *, v_extk_closure);
SCEDA_Vertex *v = SCEDA_vertex_get_data(SCEDA_Vertex *, v_extk);
SCEDA_hashmap_put(g_to_g_extk_closure, v, v_extk_closure, NULL);
}
SCEDA_vertices_iterator_cleanup(&vertices);
}
{
SCEDA_HashMapIterator killers;
SCEDA_hashmap_iterator_init(killing_map, &killers);
while(SCEDA_hashmap_iterator_has_next(&killers)) {
SCEDA_Vertex *u;
SCEDA_Vertex *ku = SCEDA_hashmap_iterator_next(&killers, &u);
SCEDA_Vertex *dvu = SCEDA_hashmap_get(g_to_dvkg, u);
SCEDA_Vertex *ku_extk_closure = SCEDA_hashmap_get(g_to_g_extk_closure, ku);
SCEDA_VertexSuccIterator desc;
SCEDA_vertex_succ_iterator_init(ku_extk_closure, &desc);
while(SCEDA_vertex_succ_iterator_has_next(&desc)) {
SCEDA_Vertex *v_extk_closure = SCEDA_vertex_succ_iterator_next(&desc);
SCEDA_Vertex *v_extk = SCEDA_vertex_get_data(SCEDA_Vertex *, v_extk_closure);
SCEDA_Vertex *v = SCEDA_vertex_get_data(SCEDA_Vertex *, v_extk);
if(GDD_vertex_is_value_of_type(v, type)) {
SCEDA_Vertex *dvv = SCEDA_hashmap_get(g_to_dvkg, v);
SCEDA_graph_add_edge(dvk_g, dvu, dvv, NULL);
}
}
SCEDA_vertex_succ_iterator_cleanup(&desc);
if(GDD_vertex_is_value_of_type(ku, type)) {
SCEDA_Vertex *dvku = SCEDA_hashmap_get(g_to_dvkg, ku);
SCEDA_graph_add_edge(dvk_g, dvu, dvku, NULL);
}
}
SCEDA_hashmap_iterator_cleanup(&killers);
}
SCEDA_hashmap_delete(g_to_g_extk_closure);
SCEDA_graph_delete(g_extk_closure);
SCEDA_hashmap_delete(g_to_dvkg);
return dvk_g;
}
static SCEDA_List *RS_ddag_saturating_values_opt(GDD_DAG *ddg, const char *type, SCEDA_Graph *pkg, SCEDA_HashMap *killing_map, SCEDA_Graph *g_extk) {
SCEDA_Graph *dvk = RS_ddag_dvk_opt(ddg, type, pkg, killing_map, g_extk);
SCEDA_List *amk = RS_ddag_amk(ddg, dvk);
SCEDA_graph_delete(dvk);
return amk;
}
static int RS_ddag_register_need_opt(GDD_DAG *ddg, const char *type, SCEDA_Graph *pkg, SCEDA_HashMap *killing_map, SCEDA_Graph *g_extk) {
SCEDA_Graph *dvk = RS_ddag_dvk_opt(ddg, type, pkg, killing_map, g_extk);
int n = SCEDA_graph_width(dvk);
SCEDA_graph_delete(dvk);
return n;
}
/** Compute the (exact) register saturation for considered type.
@param[in] ddg = GDD_DAG
@param[in] type = considered type
@param[in] timeout = time out in seconds (ignored when < 0)
@param[out] rs = register saturation
@param[out] k = killing function (not NULL in case of success
except when there are no values of given type and thus rs = 0)
@return TRUE if computed saturation is optimal, FALSE otherwise.
*/
int RS_ddag_compute_saturation(GDD_DAG *ddg, const char *type, double timeout, int *rs_value, SCEDA_HashMap **rs_killing) {
int abort_timeout = FALSE;
*rs_value = 0;
*rs_killing = NULL;
SCEDA_Graph *pkg = RS_ddag_pkill(ddg, type);
SCEDA_Vertex *pk_values[SCEDA_graph_vcount(pkg)];
int n = 0;
{
SCEDA_VerticesIterator vertice;
SCEDA_vertices_iterator_init(pkg, &vertice);
while(SCEDA_vertices_iterator_has_next(&vertice)) {
SCEDA_Vertex *pk_v = SCEDA_vertices_iterator_next(&vertice);
SCEDA_Vertex *v = SCEDA_vertex_get_data(SCEDA_Vertex *, pk_v);
if(GDD_vertex_is_value_of_type(v, type)) {
pk_values[n++] = pk_v;
}
}
SCEDA_vertices_iterator_cleanup(&vertice);
}
if(n == 0) {
SCEDA_graph_delete(pkg);
return TRUE;
}
#if(1)
{
int i, j, min;
for(i = 0; i < n; i++) {
min = i;
SCEDA_Vertex *vmin = pk_values[i];
for(j = i+1; j < n; j++) {
SCEDA_Vertex *v = pk_values[j];
if(SCEDA_vertex_out_deg(v) >= SCEDA_vertex_out_deg(vmin)) {
min = j;
vmin = v;
}
}
if(min != i) {
pk_values[min] = pk_values[i];
pk_values[i] = vmin;
}
}
}
#endif
SCEDA_Graph *gk = SCEDA_graph_create(NULL, NULL);
SCEDA_HashMap *g_to_gk = SCEDA_vertex_map_create(NULL);
{
SCEDA_Graph *g = GDD_dag_get_ddg(ddg);
// first copy G
{
// copy vertices
SCEDA_VerticesIterator vertices;
SCEDA_vertices_iterator_init(g, &vertices);
while(SCEDA_vertices_iterator_has_next(&vertices)) {
SCEDA_Vertex *v = SCEDA_vertices_iterator_next(&vertices);
SCEDA_Vertex *vk = SCEDA_graph_add_vertex(gk, v);
SCEDA_hashmap_put(g_to_gk, v, vk, NULL);
}
SCEDA_vertices_iterator_cleanup(&vertices);
}
{
// copy succ relation
SCEDA_VerticesIterator vertices;
SCEDA_vertices_iterator_init(g, &vertices);
while(SCEDA_vertices_iterator_has_next(&vertices)) {
SCEDA_Vertex *v = SCEDA_vertices_iterator_next(&vertices);
SCEDA_Vertex *vk = SCEDA_hashmap_get(g_to_gk, v);
SCEDA_VertexSuccIterator succ;
SCEDA_vertex_succ_iterator_init(v, &succ);
while(SCEDA_vertex_succ_iterator_has_next(&succ)) {
SCEDA_Vertex *w = SCEDA_vertex_succ_iterator_next(&succ);
SCEDA_Vertex *wk = SCEDA_hashmap_get(g_to_gk, w);
SCEDA_graph_add_edge(gk, vk, wk, NULL);
}
SCEDA_vertex_succ_iterator_cleanup(&succ);
}
SCEDA_vertices_iterator_cleanup(&vertices);
}
}
// exhaustive search
SCEDA_HashMap *current_killing = SCEDA_vertex_map_create(NULL);
{
SCEDA_VertexSuccIterator succ[n];
SCEDA_List *edges[n];
int i;
for(i = 0; i < n; i++) {
edges[i] = NULL;
}
struct timeval chrono_start;
gettimeofday(&chrono_start, NULL);
int backtrack = FALSE;
for(i = 0; i >= 0;) {
struct timeval chrono_current;
gettimeofday(&chrono_current, NULL);
if((timeout > 0) && (ellapsed_time(&chrono_start, &chrono_current) >= timeout)) {
abort_timeout = TRUE;
break;
}
SCEDA_Vertex *u_pk = pk_values[i];
SCEDA_Vertex *u = SCEDA_vertex_get_data(SCEDA_Vertex *, u_pk);
//
if(SCEDA_vertex_out_deg(u_pk) == 0) {
if(backtrack) {
i--;
} else {
i++;
}
} else {
if(edges[i] != NULL) {
SCEDA_Vertex *ku;
safe_call(SCEDA_hashmap_remove(current_killing, (void **)&u, (void **)&ku));
SCEDA_List *ku_edges = edges[i];
undo_choice(gk, ku_edges);
SCEDA_list_delete(ku_edges);
edges[i] = NULL;
} else {
SCEDA_vertex_succ_iterator_init(u_pk, &(succ[i]));
}
int found = FALSE;
while(SCEDA_vertex_succ_iterator_has_next(&(succ[i]))) {
SCEDA_Vertex *ku_pk = SCEDA_vertex_succ_iterator_next(&(succ[i]));
SCEDA_List *ku_edges = update_choice(gk, g_to_gk, u_pk, ku_pk);
if(SCEDA_graph_is_acyclic(gk)) {
edges[i] = ku_edges;
found = TRUE;
SCEDA_Vertex *ku = SCEDA_vertex_get_data(SCEDA_Vertex *, ku_pk);
SCEDA_hashmap_put(current_killing, u, ku, NULL);
break;
} else {
undo_choice(gk, ku_edges);
SCEDA_list_delete(ku_edges);
}
}
if(found) {
backtrack = FALSE;
i++;
} else {
SCEDA_vertex_succ_iterator_cleanup(&(succ[i]));
backtrack = TRUE;
i--;
}
}
if(i == n) {
int rn = RS_ddag_register_need_opt(ddg, type, pkg, current_killing, gk);
if(rn > *rs_value) {
*rs_value = rn;
if(*rs_killing != NULL) {
SCEDA_hashmap_clear(*rs_killing);
} else {
*rs_killing = SCEDA_vertex_map_create(NULL);
}
{
SCEDA_HashMapIterator kmap;
SCEDA_hashmap_iterator_init(current_killing, &kmap);
while(SCEDA_hashmap_iterator_has_next(&kmap)) {
SCEDA_Vertex *v;
SCEDA_Vertex *kv = SCEDA_hashmap_iterator_next(&kmap, &v);
SCEDA_hashmap_put(*rs_killing, v, kv, NULL);
}
SCEDA_hashmap_iterator_cleanup(&kmap);
}
}
backtrack = TRUE;
i--;
}
}
for(i = 0; i < n; i++) {
if(edges[i] != NULL) {
SCEDA_List *ku_edges = edges[i];
undo_choice(gk, ku_edges);
SCEDA_list_delete(ku_edges);
edges[i] = NULL;
SCEDA_vertex_succ_iterator_cleanup(&(succ[i]));
}
}
}
SCEDA_hashmap_delete(current_killing);
// finished
SCEDA_hashmap_delete(g_to_gk);
SCEDA_graph_delete(gk);
SCEDA_graph_delete(pkg);
return !abort_timeout;
}