/**************************************************************
 * Structured Markov Chains Solver       [  SMCSolver  ]      *
 * Dario Bini, Beatrice Meini, Sergio Steffe'                 *
 * bini@dm.unipi.it, meini@dm.unipi.it, steffe@dm.unipi.it    *
 * Dipartimento di Matematica "Leonida Tonelli"               *
 * Largo Pontecorvo 5                                         *
 * 56127 Pisa                                                 *
 * Italy                                                      *
 * Version 1.1 - Oct 2006                                     *
 **************************************************************
 *
 *  edit-a.c - view and edit A  - both callbacks and interfaces
 *
 */

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <libgen.h>
#include <gtk/gtk.h>
#include <errno.h>
#include <ctype.h> /* character functions */
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <gdk-pixbuf/gdk-pixbuf.h>

#include "structures.h"
#include "edit_a.h"

#define  PIX 500   /* drawing area side */
#define  PIXS 50   /* drawing area space */
#define  PIXV 50   /* drawing area row sums part */

/* Edit A Window  **** Interface */
void
create_edit_a_window()
{
/* GtkWidget *window_edit_a; global */
GtkWidget *vboxm_edita;
GtkWidget *hbox1,*hbox2;
GtkWidget *vbox1,*vbox2;
GtkWidget *vbox11,*vbox14;
/* GtkWidget *edit_vbox12,*edit_vbox13; globale */
GtkWidget *hsep11,*hsep12,*hsep13; /* separators */
GtkWidget *label_v11,*label_v12,*label_v13; /* titles for button groups */
GtkWidget *button_pos_neg;
GtkWidget *button_color;
GtkWidget *button_user;
GtkWidget *hbox_contrast;
GtkWidget *label_contrast;
GtkWidget *button_contrast;
GtkWidget *button_range_normal; 
GtkWidget *button_range_adaptive;
GtkWidget *button_range_block;  
GSList *range_list = NULL;
GtkWidget *hsep1,*hsep2,*vsep0,*vsep1,*vsep2; /* separators */
GtkWidget *vbox21,*vbox22, *vbox23;
GtkWidget *label_211,*label_212; /* labels with matrix results */
GtkWidget *label_221; /* labels with matrix results */
/* GtkWidget *label_222, *label_231, *label_232; globals */
GtkWidget *button_transpose;
GtkWidget *button_normalize;
GtkWidget *button_truncate;
GtkWidget *button_qbd_exchange; /* in QBD problems only */
/* GtkWidget  *matarea; global */
GtkWidget *hbox_matlabels;
GtkWidget *label_mat,*label_vet;
GtkWidget *toolbar_ed;
GtkWidget *tmp_toolbar_icon;
GtkWidget *button_quit_ed;
GtkWidget *hbox_block;
GtkWidget *button_up,*button_down;
GtkWidget *label1_block,*label2_block;
/* GtkWidget *entry_block; global */
/* int a_selected_block; global */
GtkWidget *hbox_aij;
GtkWidget *label_aij;
/* GtkWidget *label_space; global */
/* GtkWidget   *entry_ij; global */
/* GtkWidget   *entry_aij; global */
/* GtkWidget *statusb_edita; global */
/* unsigned char *matvalue; globals */
char buf[256];
/* double *as, asmax;  globals   allocated in create_edit_a_window, sum of rows of block and maximum value of bock */


/* window_edit_a */
window_edit_a=gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window_edit_a), "View and Edit  Matrix A");
gtk_window_set_default_size (GTK_WINDOW (window_edit_a), 720, 700);
a_selected_block = pea.block; /* we need this value here */
gdk_rgb_init();

/* vboxm_edita - main vertical box*/
vboxm_edita = gtk_vbox_new (FALSE, 5);
gtk_widget_show (vboxm_edita);
gtk_container_add (GTK_CONTAINER (window_edit_a), vboxm_edita);
/* divided in four hbox */
hbox1=gtk_hbox_new(FALSE,5);
gtk_widget_show(hbox1);
gtk_box_pack_start (GTK_BOX (vboxm_edita), hbox1, FALSE, FALSE, 5);
/* first hbox divided in 2 vbox */
/* first vbox in first hbox  for buttons and hboxes */
vbox1=gtk_vbox_new(FALSE,5);
gtk_box_pack_start (GTK_BOX (hbox1), vbox1, FALSE, FALSE, 5);
gtk_widget_show(vbox1);
/* first vbox on the left contains buttons and hboxes in 3 vboxes */
vbox11 = gtk_vbox_new(FALSE,5);
gtk_box_pack_start (GTK_BOX (vbox1), vbox11, FALSE, FALSE, 0);
gtk_widget_show(vbox11);
label_v11 = gtk_label_new("DISPLAY CONTROL\n     change to: ");
gtk_widget_show(label_v11);
gtk_box_pack_start (GTK_BOX (vbox11), label_v11, TRUE, FALSE, 0);
/* button positive / negative s_positive=0 default is positive i.e. black is 1 white is 0*/
button_pos_neg = gtk_button_new();
if (pea.is_positive==1)  gtk_button_set_label (GTK_BUTTON(button_pos_neg)," Positive ");
          else           gtk_button_set_label (GTK_BUTTON(button_pos_neg)," Negative ");
gtk_widget_show (button_pos_neg);
gtk_box_pack_start (GTK_BOX (vbox11), button_pos_neg, TRUE, FALSE, 0);
/* button b/n - color default is_color=0 is black&white */ 
button_color = gtk_button_new();
if (pea.is_color==1)  gtk_button_set_label (GTK_BUTTON(button_color),"  B & W  ");
          else        gtk_button_set_label (GTK_BUTTON(button_color),"  Color  ");
gtk_widget_show (button_color);
gtk_box_pack_start (GTK_BOX (vbox11), button_color, TRUE, FALSE, 0);
/* button enhance = no enhance*/
button_user = gtk_button_new();
/* set labels depending on previous setup choices */
if (pea.is_user==1)  gtk_button_set_label (GTK_BUTTON(button_user),"  STANDARD   ");
          else       gtk_button_set_label (GTK_BUTTON(button_user),"    USER     ");
gtk_widget_show (button_user);
gtk_box_pack_start (GTK_BOX (vbox11), button_user, TRUE, FALSE, 0);

/* horizontal separator */
hsep11 = gtk_hseparator_new();
gtk_widget_show(hsep11);
gtk_box_pack_start (GTK_BOX (vbox1), hsep11, FALSE, FALSE, 0);
edit_vbox12 = gtk_vbox_new(TRUE,5);
gtk_box_pack_start (GTK_BOX (vbox1), edit_vbox12, FALSE, FALSE, 0);
gtk_widget_show(edit_vbox12);
label_v12 = gtk_label_new("USER CONTRAST");
gtk_widget_show(label_v12);
gtk_box_pack_start (GTK_BOX (edit_vbox12), label_v12, TRUE, FALSE, 0);
/* contrast spin button */
hbox_contrast = gtk_hbox_new(FALSE,0);
gtk_widget_show (hbox_contrast);
gtk_box_pack_start (GTK_BOX (edit_vbox12), hbox_contrast, TRUE, FALSE, 0);
label_contrast = gtk_label_new(" contrast");
gtk_widget_show (label_contrast);
gtk_box_pack_start (GTK_BOX (hbox_contrast),label_contrast, TRUE, FALSE, 0);
button_contrast = gtk_spin_button_new_with_range(-20,20,1);
gtk_widget_show (button_contrast);
gtk_box_pack_start (GTK_BOX (hbox_contrast), button_contrast, TRUE, FALSE, 0);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON(button_contrast),0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON(button_contrast),pea.contrast_value);
gtk_entry_set_editable(GTK_ENTRY(button_contrast),FALSE);
/* horizontal separator */
hsep12 = gtk_hseparator_new();
gtk_widget_show(hsep12);
gtk_box_pack_start (GTK_BOX (vbox1), hsep12, FALSE, FALSE, 0);
edit_vbox13 = gtk_vbox_new(TRUE,5);
gtk_box_pack_start (GTK_BOX (vbox1), edit_vbox13, FALSE, FALSE, 0);
gtk_widget_show(edit_vbox13);
label_v13 = gtk_label_new("USER    RANGE");
gtk_widget_show(label_v13);
gtk_box_pack_start (GTK_BOX (edit_vbox13), label_v13, TRUE, FALSE, 0);
/* button normal range*/
button_range_normal = gtk_radio_button_new_with_label(NULL,"  [0,1]  ");
range_list = gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_range_normal));
gtk_widget_show (button_range_normal);
gtk_box_pack_start (GTK_BOX (edit_vbox13), button_range_normal, TRUE, FALSE, 0);
/* button range block */
button_range_block = gtk_radio_button_new_with_label(range_list," [min,max] ");
range_list = gtk_radio_button_get_group (GTK_RADIO_BUTTON(button_range_normal));
gtk_widget_show (button_range_block);
gtk_box_pack_start (GTK_BOX (edit_vbox13), button_range_block, TRUE, FALSE, 0);
/* button range adaptive */
button_range_adaptive = gtk_radio_button_new_with_label(range_list," adaptive ");
gtk_widget_show (button_range_adaptive);
gtk_box_pack_start (GTK_BOX (edit_vbox13), button_range_adaptive, TRUE, FALSE, 0);
switch (pea.is_range_type) {
        case 0:
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button_range_normal),TRUE);
                break;
        case 1:
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(button_range_block),TRUE);
                break;
        case 2:
                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button_range_adaptive),TRUE);
                break;
        }

/* horizontal separator */
hsep13 = gtk_hseparator_new();
gtk_widget_show(hsep13);
gtk_box_pack_start (GTK_BOX (vbox1), hsep13, FALSE, FALSE, 0);

vbox14 = gtk_vbox_new(FALSE,5);
gtk_box_pack_start (GTK_BOX (vbox1), vbox14, FALSE, FALSE, 0);
gtk_widget_show(vbox14);
label_v13 = gtk_label_new("MATRIX MODIFY");
gtk_widget_show(label_v13);
gtk_box_pack_start (GTK_BOX (vbox14), label_v13, TRUE, FALSE, 0);

/* Transpose button */
button_transpose = gtk_button_new_with_label("  Transpose  ");
gtk_widget_show (button_transpose);
gtk_box_pack_start (GTK_BOX (vbox14), button_transpose, TRUE, FALSE, 0);
/* Normalize button */
button_normalize = gtk_button_new_with_label("  Normalize  \nRows Sums to 1");
gtk_widget_show (button_normalize);
gtk_box_pack_start (GTK_BOX (vbox14), button_normalize, TRUE, FALSE, 0);
/* truncate button */
button_truncate = gtk_button_new_with_label("Truncate\n outside [0,1] ");
gtk_widget_show (button_truncate);
gtk_box_pack_start (GTK_BOX (vbox14), button_truncate, TRUE, FALSE, 0);
/* in QBD only */
if (committed.type==1) { 
   button_qbd_exchange=gtk_button_new_with_label("Exchange Block 1-3");
   gtk_widget_show (button_qbd_exchange);	
   gtk_box_pack_start (GTK_BOX (vbox14), button_qbd_exchange, TRUE, FALSE, 0);
   }
/* vertical separator */
vsep0 = gtk_vseparator_new();
gtk_widget_show(vsep0);
gtk_box_pack_start (GTK_BOX (hbox1), vsep0, FALSE, FALSE, 0);

/* second vbox in first hbox for matrix display */
vbox2=gtk_vbox_new(FALSE,5);
gtk_widget_show(vbox2);
gtk_box_pack_end (GTK_BOX (hbox1), vbox2, FALSE, FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (vbox2), 10);
/* matrix drawable area */
gtk_widget_push_visual(gdk_rgb_get_visual());
gtk_widget_push_colormap(gdk_rgb_get_cmap());
matarea =  gtk_drawing_area_new();
gtk_widget_pop_visual();
gtk_widget_pop_colormap();
gtk_widget_show(matarea);
gtk_drawing_area_size  (GTK_DRAWING_AREA(matarea),PIX+PIXS+PIXV,PIX);
gtk_box_pack_start (GTK_BOX (vbox2), matarea, FALSE, FALSE, 0);
/* add mouse positioning events to matarea */
gtk_widget_add_events (GTK_WIDGET(matarea),GDK_POINTER_MOTION_MASK);
gtk_widget_add_events (GTK_WIDGET(matarea),GDK_BUTTON_PRESS_MASK);
hbox_matlabels = gtk_hbox_new(FALSE,0);
gtk_widget_show(hbox_matlabels);
gtk_box_pack_start (GTK_BOX (vbox2), hbox_matlabels, FALSE, FALSE, 0);
label_mat = gtk_label_new(" Block of Matrix A Graphic Display ");
gtk_widget_show(label_mat);
gtk_box_pack_start (GTK_BOX (hbox_matlabels), label_mat, FALSE, FALSE, 0);
edit_label_user = gtk_label_new("                             USER LEVELS");
if (pea.is_user==0) gtk_label_set_text(GTK_LABEL(edit_label_user),"                          STANDARD LEVELS");
else gtk_label_set_text(GTK_LABEL(edit_label_user),"                             USER LEVELS");
gtk_widget_show(edit_label_user);
gtk_box_pack_start (GTK_BOX (hbox_matlabels), edit_label_user, FALSE, FALSE, 0);

label_vet = gtk_label_new("Rows Sums");
gtk_widget_show(label_vet);
gtk_box_pack_end (GTK_BOX (hbox_matlabels), label_vet, FALSE, FALSE, 0);
/* horizontal separator */
hsep1 = gtk_hseparator_new();
gtk_widget_show(hsep1);
gtk_box_pack_start (GTK_BOX (vboxm_edita), hsep1, FALSE, FALSE, 0);

/* second hbox contains various data show boxes */
hbox2=gtk_hbox_new(FALSE,5);
gtk_widget_show(hbox2);
gtk_box_pack_start (GTK_BOX (vboxm_edita), hbox2, FALSE, FALSE, 0);
/* matrix #blocks and dimensions */
vbox21 = gtk_vbox_new(TRUE,5);
gtk_box_pack_start (GTK_BOX (hbox2), vbox21, TRUE, TRUE, 0);
gtk_widget_show(vbox21);
label_211 = gtk_label_new("   Matrix A   ");
gtk_widget_show(label_211);
gtk_box_pack_start (GTK_BOX (vbox21), label_211, TRUE, TRUE, 0);
/* A consist of committed.matrix_a_num square blocks of dimension committed.dimension_m */
sprintf(buf,"   %d Blocks   dim  %d x %d  ",committed.matrix_a_num,committed.dimension_m, committed.dimension_m);
label_212 = gtk_label_new(buf);
gtk_widget_show(label_212);
gtk_box_pack_start (GTK_BOX (vbox21), label_212, FALSE, FALSE, 0);
/* vertical separator */
vsep1 = gtk_vseparator_new();
gtk_widget_show(vsep1);
gtk_box_pack_start (GTK_BOX (hbox2), vsep1, FALSE, FALSE, 0);
vbox22 = gtk_vbox_new(TRUE,0);
gtk_box_pack_start (GTK_BOX (hbox2), vbox22, TRUE, TRUE, 0);
gtk_widget_show(vbox22);
sprintf(buf,"Stochasticity Defect");
label_221 = gtk_label_new(buf);
gtk_widget_show(label_221);
gtk_box_pack_start (GTK_BOX (vbox22), label_221, TRUE, TRUE, 0);
sprintf(buf,"  %lg  ",st_def());
label_222 = gtk_label_new(buf);
gtk_widget_show(label_222);
gtk_box_pack_start (GTK_BOX (vbox22), label_222, TRUE, TRUE, 0);
/* vertical separator */
vsep2 = gtk_vseparator_new();
gtk_widget_show(vsep2);
gtk_box_pack_start (GTK_BOX (hbox2), vsep2, FALSE, FALSE, 0);
vbox23 = gtk_vbox_new(TRUE,0);
gtk_box_pack_start (GTK_BOX (hbox2), vbox23, TRUE, TRUE, 0);
gtk_widget_show(vbox23);
sprintf(buf,"This Block  max=%g  min=%g ",abmax(a_selected_block),abmin(a_selected_block));
label_231 = gtk_label_new(buf);
gtk_widget_show(label_231);
gtk_box_pack_start (GTK_BOX (vbox23), label_231, TRUE, TRUE, 0);
sprintf(buf,"All Blocks max=%g  min=%g ",aamax(),aamin());
label_232 = gtk_label_new(buf);
gtk_widget_show(label_232);
gtk_box_pack_start (GTK_BOX (vbox23), label_232, TRUE, TRUE, 0);

/* horizontal separator */
hsep2 = gtk_hseparator_new();
gtk_widget_show(hsep2);
gtk_box_pack_start (GTK_BOX (vboxm_edita), hsep2, FALSE, FALSE, 0);

/* third hbox consists in toolbox  */
/* toolbar begins */
toolbar_ed = gtk_toolbar_new ();
gtk_widget_show (toolbar_ed);
gtk_box_pack_start (GTK_BOX (vboxm_edita), toolbar_ed, FALSE, FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (toolbar_ed), 10);
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar_ed), GTK_TOOLBAR_BOTH);
/* cancel button  first position */
tmp_toolbar_icon = gtk_image_new_from_stock ("gtk-quit", gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar_ed)));
button_quit_ed = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar_ed),
                                GTK_TOOLBAR_CHILD_BUTTON,
                                NULL,
                                "Close",
                                NULL, NULL,
                                tmp_toolbar_icon, NULL, NULL);
gtk_widget_show(button_quit_ed);
/* blocks choice hbox */
hbox_block =gtk_hbox_new(TRUE,0);
gtk_box_set_homogeneous (GTK_BOX(hbox_block),FALSE);
label1_block = gtk_label_new("               Block : ");
gtk_widget_show (label1_block);
gtk_box_pack_start (GTK_BOX (hbox_block), label1_block, FALSE, FALSE, 0);
button_down= gtk_button_new_from_stock ("gtk-go-down");
gtk_widget_show(button_down);
gtk_box_pack_start (GTK_BOX (hbox_block), button_down, FALSE, FALSE, 0);
entry_block = gtk_entry_new_with_max_length (4);
gtk_entry_set_width_chars (GTK_ENTRY(entry_block),5);
gtk_widget_show(entry_block);
gtk_box_pack_start (GTK_BOX (hbox_block), entry_block, FALSE, FALSE, 0);
sprintf(buf,"%d",a_selected_block);
gtk_entry_set_text(GTK_ENTRY(entry_block), buf);
button_up= gtk_button_new_from_stock ("gtk-go-up");
gtk_widget_show(button_up);
gtk_box_pack_start (GTK_BOX (hbox_block), button_up, FALSE, FALSE, 0);
label2_block = gtk_label_new("  ");
gtk_widget_show (label2_block);
gtk_box_pack_start (GTK_BOX (hbox_block), label2_block, FALSE, FALSE, 0);
gtk_widget_show(gtk_toolbar_append_element (GTK_TOOLBAR (toolbar_ed),
                                GTK_TOOLBAR_CHILD_WIDGET,
                                hbox_block,
                                "",
                                NULL, NULL,
                                NULL, NULL, NULL));
/* A(i,j)= x hbox */
hbox_aij = gtk_hbox_new(TRUE,0);
gtk_box_set_homogeneous (GTK_BOX(hbox_aij),FALSE);
label_aij=gtk_label_new("   Value : ");
gtk_box_pack_start (GTK_BOX (hbox_aij), label_aij, FALSE, FALSE, 0);
gtk_widget_show (label_aij);
entry_ij = gtk_entry_new_with_max_length (14);
gtk_entry_set_width_chars (GTK_ENTRY(entry_ij),15);
gtk_entry_set_editable (GTK_ENTRY(entry_ij),FALSE);
gtk_widget_show(entry_ij);
gtk_box_pack_start (GTK_BOX (hbox_aij),entry_ij,FALSE, FALSE, 0);
entry_aij = gtk_entry_new_with_max_length (16);
gtk_entry_set_width_chars (GTK_ENTRY(entry_aij),20);
gtk_entry_set_editable(GTK_ENTRY(entry_aij),FALSE);
gtk_widget_show(entry_aij);
gtk_box_pack_start (GTK_BOX (hbox_aij),entry_aij,FALSE, FALSE, 0);
gtk_widget_show(gtk_toolbar_append_element (GTK_TOOLBAR (toolbar_ed),
                                GTK_TOOLBAR_CHILD_WIDGET,
                                hbox_aij,
                                "",
                                NULL, NULL,
                                NULL, NULL, NULL));
/* label space with editing/view only message */
label_space = gtk_label_new("(view only)   ");
gtk_widget_show (label_space);
gtk_widget_show(gtk_toolbar_append_element (GTK_TOOLBAR (toolbar_ed),
                                GTK_TOOLBAR_CHILD_WIDGET,
                                label_space,
                                "",
                                NULL, NULL,
                                NULL, NULL, NULL));

/* fourth hbox consists in statusbar  */
/**************** statusbar  begins        */
statusb_edita = gtk_statusbar_new();
gtk_widget_show (statusb_edita);
gtk_box_pack_end (GTK_BOX (vboxm_edita), statusb_edita, FALSE, FALSE, 0);
/**************** statusbar ends           */

/* initialize */
if (pea.is_user==0) {
         gtk_widget_set_sensitive(edit_vbox12,FALSE);
         gtk_widget_set_sensitive(edit_vbox13,FALSE);
         }

is_freeze_aij=0;
/* allocate space for graphic buffers and block computations */
matvalue=calloc((PIX+PIXS+PIXV)*PIX,sizeof(char));
rgb_matvalue=calloc(3*(PIX+PIXS+PIXV)*PIX,sizeof(guchar));
as=malloc((committed.dimension_m+1)*sizeof(double)); /* remember that index goes from 1 to committed.dimension_m .. Fortran style */

if ((matvalue==NULL)||(rgb_matvalue==NULL)) {
        gtk_statusbar_push(GTK_STATUSBAR(statusb_edita),0,"   Sorry, there is NOT enougth memory left for graphic window");
        } else { 
	max_min_ab_compute(); /* compute min and max values for the a_selected_block block using committed.dimension_m */
	gray_levels_setup(pea.contrast_value); /* compute gray levels */
        image_compute(a_selected_block); /* compute matvalue */
        /* no need to draw the image: an expose event will be produced drawing window ! */
	if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
        }
if (committed.dimension_m > 250) 
    gtk_statusbar_push(GTK_STATUSBAR(statusb_edita),0,"  Warning: Matrix Display is not accurate for dimensions larger then 250 x 250");

/**************** connect signals  begin   */
/* g_signal_connect ((gpointer) window_edit_a, "delete_event", G_CALLBACK (on_delete_event_do),NULL);*/
g_signal_connect ((gpointer) button_quit_ed, "destroy", G_CALLBACK(on_edit_a_menu_destroy_activate),NULL);
g_signal_connect ((gpointer) button_quit_ed, "clicked", G_CALLBACK(on_edit_a_menu_quit_activate),NULL);
if (matvalue!=NULL) { /* do not activate drawings calls if no memory for buffers */
g_signal_connect (G_OBJECT (matarea), "expose_event",  G_CALLBACK (draw_matarea_callback), NULL);
g_signal_connect (G_OBJECT (matarea), "motion_notify_event",  G_CALLBACK (xy_matarea), NULL);
gtk_signal_connect (GTK_OBJECT (matarea), "button_press_event", (GtkSignalFunc) button_press_matarea, NULL);
g_signal_connect ((gpointer) button_up, "clicked", G_CALLBACK(on_edit_a_button_up_activate),NULL);
g_signal_connect ((gpointer) button_down, "clicked", G_CALLBACK(on_edit_a_button_down_activate),NULL);
g_signal_connect ((gpointer) entry_block, "changed", G_CALLBACK(on_edit_a_block_entry_changed),NULL);
g_signal_connect ((gpointer) entry_block, "activate", G_CALLBACK(on_edit_a_block_entry_activated),NULL);
g_signal_connect ((gpointer) button_pos_neg, "clicked", G_CALLBACK(on_edit_a_pos_neg_activate),NULL);
g_signal_connect ((gpointer) button_color, "clicked", G_CALLBACK(on_edit_a_color_activate),NULL);
g_signal_connect ((gpointer) button_contrast, "changed", G_CALLBACK (on_edit_a_contrast_changed), NULL);
g_signal_connect ((gpointer) button_user, "clicked", G_CALLBACK(on_edit_a_user_activate),NULL);
g_signal_connect ((gpointer) button_range_normal, "toggled", G_CALLBACK(on_edit_a_range_normal_activate),NULL);
g_signal_connect ((gpointer) button_range_block, "toggled", G_CALLBACK(on_edit_a_range_block_activate),NULL);
g_signal_connect ((gpointer) button_range_adaptive, "toggled", G_CALLBACK(on_edit_a_range_adaptive_activate),NULL);
g_signal_connect ((gpointer) entry_aij, "activate", G_CALLBACK(on_edit_a_float_entry_activate),NULL);
	        }
g_signal_connect ((gpointer) button_transpose, "clicked", G_CALLBACK(on_edit_a_transpose_activate),NULL);
g_signal_connect ((gpointer) button_normalize, "clicked", G_CALLBACK(on_edit_a_normalize_activate),NULL);
g_signal_connect ((gpointer) button_truncate, "clicked", G_CALLBACK(on_edit_a_truncate_activate),NULL);
if (committed.type==1) g_signal_connect ((gpointer) button_qbd_exchange, "clicked", G_CALLBACK(on_edit_a_exchange_activate),NULL);
/**************** connect signals  end     */

gtk_widget_show_all(window_edit_a);
}
/*********************************/

/******************* Callbacks:  Buttons and  widgets on the toolbar ***********************/

/* Edit A Window: Quit  **** Callback */
void
on_edit_a_menu_quit_activate   (GtkMenuItem  *menuitem, gpointer  user_data)
{
if(is_debug==1) printf("on_edit_a_menu_quit_activate: quit\n");
gtk_widget_destroy(GTK_WIDGET(window_edit_a));
if(is_debug==1) printf("on_edit_a_menu_quit_activate: exiting\n");   
}
/*********************************/

/* response to destroy window event */
void
on_edit_a_menu_destroy_activate   (GtkWidget  *ww, gpointer  user_data)
{
if(is_debug==1) printf("on_edit_a_menu_destroy_activate: \n");
/* save block number */
pea.block=a_displayed_block;
/* free space of the graphic buffers */
free(matvalue);
free(rgb_matvalue);
free(as);
is_edit_a_open=0;  /* 0=not open  1=open */
if(is_debug==1) printf("on_edit_a_menu_destroy_activate: exiting Edit A; preferences: %d %d %d %d %g %d\n",pea.block,pea.is_positive,pea.is_color,pea.is_user,pea.contrast_value,pea.is_range_type);
}
/*********************************/

/* increase block number and redraw *****  Callback button_up */
void 
on_edit_a_button_up_activate (GtkButton   *button, gpointer my_data )
{
/* int a_selected_block,a_displayed_block; global */
char buf[8];
if(is_debug==1) printf("on_edit_a_button_up_activate: a_selected_block(before up)=%d  block dim = %d\n",a_selected_block,committed.matrix_a_num);
if (a_selected_block <committed.matrix_a_num ) {
     a_selected_block++;
     max_min_ab_compute();
     sprintf(buf,"%d",a_selected_block);
     gtk_entry_set_text(GTK_ENTRY(entry_block), buf);
     gray_levels_setup(pea.contrast_value);
     image_compute(a_selected_block);
     if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
     draw_matarea(); 
     g_idle_add((GtkFunction) a_labels_update,NULL);
     }
}
/*********************************/

/* decrease block number and redraw *****  Callback button_down */
void 
on_edit_a_button_down_activate (GtkButton   *button, gpointer my_data )
{
/* int a_selected_block; global */
char buf[8];
if(is_debug==1) printf("on_edit_a_button_up_activate: a_selected_block(before down)=%d block dim = %d\n",a_selected_block,committed.matrix_a_num);
if (a_selected_block >1 ) {
     a_selected_block--;
     max_min_ab_compute();
     sprintf(buf,"%d",a_selected_block);
     gtk_entry_set_text(GTK_ENTRY(entry_block), buf);
     gray_levels_setup(pea.contrast_value);
     image_compute(a_selected_block); 
     if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
     draw_matarea(); 
     g_idle_add((GtkFunction) a_labels_update,NULL);
     }
}
/*********************************/

/* edit A Window: reads block number from entry *****  Callback "change" event */
/* simply throw away any non digit, throw away first 0, and and check range  */
void on_edit_a_block_entry_changed  (GtkEntry *entry, gpointer user_data )
{
/* GtkWidget *statusb_edita; global    */
gchar *blocks_in = NULL;
gchar blocks_out[256];
gchar  this_char = '\0';
int blocks_int;
int i=0;
int j=0;
int last=0;
if(is_debug==1) printf("n_edit_a_block_entry_changed: \n");
blocks_in = gtk_editable_get_chars(GTK_EDITABLE(entry_block), 0, -1);
this_char = blocks_in[0];
if (!this_char) {
    no_block_selected=1;
    g_free (blocks_in);
    return ;
    }
while (last==0) {
    if (isdigit(this_char)!=0) {
         blocks_out[i]=this_char;
         i++;
         }
         j++;
         this_char=blocks_in[j];
         if(this_char=='\0') {
               last=1;
               blocks_out[i]=this_char;
               }
   }
if(blocks_out[0]==0) {
		g_free (blocks_in);
		gtk_entry_set_text(GTK_ENTRY(entry_block), blocks_out);
	        return;
		}
blocks_int=atoi(blocks_out);
if (blocks_int <1) {
                     blocks_int=1;
		     sprintf(SBUF,"   Blocks number must be greater than 1 !");
                     g_idle_add((GtkFunction) a_edit_status_update,NULL);
                      }
if (blocks_int >committed.matrix_a_num) {
                    blocks_int=committed.matrix_a_num;
		    sprintf(SBUF,"    Blocks maximum number is %d !",committed.matrix_a_num);
                    g_idle_add((GtkFunction) a_edit_status_update,NULL);
                      }
if ((blocks_int >= 1)&&(blocks_int <= committed.matrix_a_num)) {
		a_selected_block=blocks_int;
		sprintf(blocks_out,"%d",blocks_int);}
g_free (blocks_in);
no_block_selected=0;
gtk_entry_set_text(GTK_ENTRY(entry_block), blocks_out);
}
/*********************************/

/* edit A Window: reads block number from entry , calculates image and refresh screen ***** Callback "activate" event */
/* the entry is always correct at this stage  */
void on_edit_a_block_entry_activated  (GtkEntry *entry, gpointer user_data )
{
/* GtkWidget *statusb_edita; global    */
gchar *blocks_in = NULL;

blocks_in = gtk_editable_get_chars(GTK_EDITABLE(entry_block), 0, -1);
if( is_debug==1) printf("on_edit_a_block_entry_activated: %s\n",blocks_in);
sscanf(blocks_in,"%d",&a_selected_block);
max_min_ab_compute();
gray_levels_setup(pea.contrast_value);
image_compute(a_selected_block);
if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
draw_matarea();
}
/*********************************/

/* edit A Window: reads float number from entry */
/* uses watch_for_number to read string and detect valid floats - the last one is the good  */
/* watch_for_number: initialize with watch_for_number(0, 0,num_str); and fill num_str with 0 before using; add watch_for_number('\n', 1,num_str) at last.
 * return value: 0=other ASCII <128   1=considering a number    2=comment line and new line    3=new line    4=new line following a new line
 *                5=int   6=int and new line   7=floatFP   8=floatEX   9=floatFP and new line   10 floatEX and new line  11 ASCII > 127 not in comment line 
 */
void on_edit_a_float_entry_activate  (GtkEntry *entry, gpointer user_data )
{
/* GtkWidget *statusb_edita; global    */
gchar *float_in = NULL;
gchar float_out[256];
int  this_char = '\0';
double float_num;
int i=0;
int last=0;
int v; /* retrun value */
int valid;
char num_str[1024];
if( is_debug==1) printf("on_edit_a_float_entry_activate:\n");

valid=0; /* non valid */
float_num=-1.0;
for(i=0;i<1024;i++)num_str[i]=0; /* clean input string */
watch_for_number(0, 0,num_str);  /* initialization     */

float_in = gtk_editable_get_chars(GTK_EDITABLE(entry_aij), 0, -1);
last=0;
i=0;
while (last==0) {
        this_char=float_in[i];
        if(this_char!=0) {
                        v=watch_for_number(this_char,1,num_str);
                        /*if ((v==7)||(v==8)||(v==9)||(v=10)) {if(1==sscanf(num_str,"%lg",&float_num)) valid=1;}*/
                        i++;
                        } else {
                        v=watch_for_number('\n', 1,num_str);
                        /*if ((v==7)||(v==8)||(v==9)||(v=10)) {if(1==sscanf(num_str,"%lg",&float_num)) valid=1;}*/
                        last=1;
                        };
        }
if ((v==7)||(v==8)||(v==9)||(v=10)) {if(1==sscanf(num_str,"%lg",&float_num)) valid=1;}
if (is_debug==1) printf("on_edit_a_float_entry_activate: old A(%d,%d)=%g new valid=%d  %g\n",is_frozen_i,is_frozen_j,is_frozen_a,valid,float_num);
if (valid==0) {
                sprintf(float_out,"%.8E",is_frozen_a);
                gtk_entry_set_text(GTK_ENTRY(entry_aij), float_out);
                sprintf(SBUF,"    Entry not accepted: not a floating number !");
                g_idle_add((GtkFunction) a_edit_status_update,NULL);
                return;
                }
if ((valid==1)&& (float_num < 0.0)) {
                sprintf(float_out,"%.8E",is_frozen_a);
                gtk_entry_set_text(GTK_ENTRY(entry_aij), float_out);
                sprintf(SBUF,"    Negative values not allowed !");
                g_idle_add((GtkFunction) a_edit_status_update,NULL);
                return;
                }
sprintf(float_out,"%.8E",float_num);
gtk_entry_set_text(GTK_ENTRY(entry_aij), float_out);
write_mata_(&is_frozen_i,&is_frozen_j,&a_displayed_block,&float_num);
/* recompute row sum */
max_min_ab_compute();
gray_levels_setup(pea.contrast_value);
image_compute(a_selected_block);
if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
draw_matarea();
gtk_entry_set_editable(GTK_ENTRY(entry_aij),FALSE);
is_freeze_aij=0;
g_idle_add((GtkFunction) a_labels_update,NULL);
gtk_label_set_text (GTK_LABEL(label_space),"(view only)   ");
SBUF[0]=0;
g_idle_add((GtkFunction) a_edit_status_update,NULL);
sprintf(SBUF,"    Value changed. Remember to Normalize the matrix before using it !");
g_idle_add((GtkFunction) a_edit_status_update,NULL);
return;
}
/*********************************/

/******************* Callbacks:  Buttons and  widgets on the left side  ***********************/

/* positive / negative choice button  */
void
on_edit_a_pos_neg_activate(GtkButton *button, gpointer my_data)
{
if( is_debug==1) printf("on_edit_a_pos_neg_activate:\n");
if (pea.is_positive==0) {
         pea.is_positive=1;
         gtk_button_set_label (button," Positive ");
         } else {
        pea.is_positive=0;
         gtk_button_set_label (button," Negative ");
        }
gray_levels_setup(pea.contrast_value);
image_compute(a_selected_block);
if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
draw_matarea();
}
/*********************************/

/* color / black % white */
void
on_edit_a_color_activate(GtkButton *button, gpointer my_data)
{
if( is_debug==1) printf("on_edit_a_color_activate:\n");
if (pea.is_color==0) {
         pea.is_color=1;
         gtk_button_set_label (button,"  B & W  ");
         } else {
        pea.is_color=0;
         gtk_button_set_label (button,"  Color  ");
        }
gray_levels_setup(pea.contrast_value);
image_compute(a_selected_block);
if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
draw_matarea();
}
/*********************************/

/* (toggle button) user:  activate user contrast settings  and redraw */
void
on_edit_a_user_activate(GtkButton *button, gpointer my_data)
{
if( is_debug==1) printf("on_edit_a_user_activate:\n");
if (pea.is_user==0) {
         pea.is_user=1;
	 gtk_widget_set_sensitive(edit_vbox12,TRUE);
         gtk_widget_set_sensitive(edit_vbox13,TRUE);
         gtk_label_set_text(GTK_LABEL(edit_label_user),"                             USER LEVELS");
         gtk_button_set_label (button,"  STANDARD   ");
         } else {
         pea.is_user=0;
	 gtk_widget_set_sensitive(edit_vbox12,FALSE);
         gtk_widget_set_sensitive(edit_vbox13,FALSE);
	 gtk_label_set_text(GTK_LABEL(edit_label_user),"                          STANDARD LEVELS");
         gtk_button_set_label (button,"    USER     ");
        }


if(is_debug==1) printf("on_edit_a_user_activate:  contrast_value=%g, a_selected_block=%d\n",pea.contrast_value,a_selected_block);
gray_levels_setup(pea.contrast_value);
image_compute(a_selected_block);
if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
draw_matarea();
}
/*********************************/

/* read contrast and redraw */
void 
on_edit_a_contrast_changed(GtkEntry *entry, gpointer my_data)
{
if( is_debug==1) printf("on_edit_a_contrast_changed:\n");
pea.contrast_value = gtk_spin_button_get_value (GTK_SPIN_BUTTON(entry));
if(pea.is_user==1) {/* the change is valid but to see result must be user mode */
		gray_levels_setup(pea.contrast_value);
		image_compute(a_selected_block);
                if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
		draw_matarea();
		}
}
/*********************************/

/* range normal and redraw (toggle) */
void
on_edit_a_range_normal_activate(GtkButton *button, gpointer my_data)
{
if( is_debug==1) printf("on_edit_a_range_normal_activate\n");
pea.is_range_type=0;
if(pea.is_user==1) {/* the change is valid but to see result must be user mode */
		gray_levels_setup(pea.contrast_value);
		image_compute(a_selected_block);
                if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
		draw_matarea();
		}
}
/*********************************/

/* range for the block  and redraw (toggle) */
void
on_edit_a_range_block_activate(GtkButton *button, gpointer my_data)
{
if( is_debug==1) printf("on_edit_a_range_block_activate:\n");
pea.is_range_type=1;
if(pea.is_user==1) {/* the change is valid but to see result must be user mode */
		gray_levels_setup(pea.contrast_value);
		image_compute(a_selected_block);
		draw_matarea();
		}
}
/*********************************/

/* range for the adaptive  and redraw (toggle) */
void
on_edit_a_range_adaptive_activate(GtkButton *button, gpointer my_data)
{
if( is_debug==1) printf("on_edit_a_range_adaptive_activate:\n");
pea.is_range_type=2;
if(pea.is_user==1) {/* the change is valid but to see result must be user mode */
                gray_levels_setup(pea.contrast_value);
                image_compute(a_selected_block);
                if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
                draw_matarea();
                }
}
/*********************************/


/* transpose all the blocks of A */
void
on_edit_a_transpose_activate(GtkButton *button, gpointer my_data)
{
transpose_mata_();
max_min_ab_compute();
gray_levels_setup(pea.contrast_value);
image_compute(a_selected_block);
if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
draw_matarea();
sprintf(SBUF,"    Each Block of the Matrix A has been transposed");
g_idle_add((GtkFunction) a_edit_status_update,NULL);
}
/*********************************/

/* normalize the matrix A: sum of rows =(1,1,1..) */
void on_edit_a_normalize_activate(GtkButton *button, gpointer my_data)
{
normalize_mata_();
max_min_ab_compute();
gray_levels_setup(pea.contrast_value);
image_compute(a_selected_block);
if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
draw_matarea();
g_idle_add((GtkFunction) a_labels_update,NULL);
sprintf(SBUF,"    Now the Matrix is Stochastic, i.e. the sums of the rows are all 1.0");
g_idle_add((GtkFunction) a_edit_status_update,NULL);

}
/*********************************/

/* truncate A to the range [0,1] */
void on_edit_a_truncate_activate(GtkButton *button, gpointer my_data)
{
aatrunc();
max_min_ab_compute();
gray_levels_setup(pea.contrast_value);
image_compute(a_selected_block);
if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
draw_matarea();
g_idle_add((GtkFunction) a_labels_update,NULL);
sprintf(SBUF,"    Now all the terms of all the Blocks are in the range [0,1]");
g_idle_add((GtkFunction) a_edit_status_update,NULL);
}
/*********************************/

/* exchange blocks 1-3 QBD problems only */
void 
on_edit_a_exchange_activate(GtkButton *button, gpointer my_data)
{
int i,j,p,q,m;
double r,s;
m=committed.dimension_m;
p=1;
q=3;
for(i=1;i<=m;i++) for(j=1;j<=m;j++) {
   read_mata_(&j,&i,&p,&r);
   read_mata_(&j,&i,&q,&s);   
   write_mata_(&j,&i,&q,&r);
   write_mata_(&j,&i,&p,&s);
   }
max_min_ab_compute();
gray_levels_setup(pea.contrast_value);
image_compute(a_selected_block);
if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
draw_matarea();
g_idle_add((GtkFunction) a_labels_update,NULL);
sprintf(SBUF,"    Block 1 and 3 has been exchanged");
g_idle_add((GtkFunction) a_edit_status_update,NULL);
}
/*********************************/

/******************* Callbacks:  matarea  ***********************/

/* Draw Matrix Block from buffer matvalue   ****** Callback "expose" event */
gboolean
draw_matarea_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
GdkCursor  *crosshair;
/* int a_selected_block,a_computed_block,a_displayed_block; globals */

/* gdk_draw_rectangle (widget->window,
                widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
                TRUE,
                0,0,30,30);*/
if (a_selected_block!=a_computed_block) {
		image_compute(a_selected_block);
		if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
		}
crosshair = gdk_cursor_new(GDK_TCROSS);
gdk_window_set_cursor(widget->window, crosshair);
gdk_cursor_destroy(crosshair);
draw_matarea();
a_displayed_block=a_computed_block;
if (is_debug==1) printf("draw_matarea_callback: a_displayed_block=%d\n",a_displayed_block);
return TRUE;
}
/*********************************/

/* print x y position on matarea ***** Callback  from mouse moving in matarea "motion_notify" event */
gboolean
xy_matarea (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
int x,y,i,j,m,q;
GdkModifierType state;
double r;
char buf[256];
if (no_block_selected==1) {
                if (is_debug==1) printf("xy_matarea: no block selection\n");
                a_selected_block=a_computed_block;
                sprintf(buf,"%d",a_selected_block);
                gtk_entry_set_text(GTK_ENTRY(entry_block), buf);
                        }
if (a_selected_block!=a_computed_block) {
                if (is_debug==1) printf("xy_matarea: a_selected_block=%d, a_computed_block=%d, recomputing\n",a_selected_block,a_computed_block);
                image_compute(a_selected_block);
		if((pea.is_range_type==2)&&(pea.is_user==1)) {recompute_levels(pea.contrast_value);image_compute(a_selected_block);}
                g_idle_add((GtkFunction) a_labels_update,NULL);
                }
if (a_selected_block!=a_displayed_block) {
                if (is_debug==1) printf("xy_matarea: a_selected_block=%d, a_displayed_block=%d, redrawing\n",a_selected_block,a_displayed_block);
                draw_matarea();
                }
m=committed.dimension_m;
q=a_selected_block;
gdk_window_get_pointer(widget->window,&x,&y,&state);
i=x*m/PIX+1;
j=y*m/PIX+1;
if(is_freeze_aij==0) {
   if (i <= m) {
        is_frozen_j=i;
        is_frozen_i=j;
        read_mata_(&j,&i,&q,&r);
        is_frozen_a=r;
        sprintf(buf,"A(%02d,%02d)=",j,i);
        gtk_entry_set_text(GTK_ENTRY(entry_ij), buf);
        sprintf(buf,"%.8E",r);
        gtk_entry_set_text(GTK_ENTRY(entry_aij), buf);
        } else if (x<PIX+PIXS){
                buf[0]=0;
                gtk_entry_set_text(GTK_ENTRY(entry_ij), buf);
                gtk_entry_set_text(GTK_ENTRY(entry_aij), buf);
        } else {
        sprintf(buf,"+Row %02d ",j);
        gtk_entry_set_text(GTK_ENTRY(entry_ij), buf);
        sprintf(buf,"%.8E",as[j]);
        gtk_entry_set_text(GTK_ENTRY(entry_aij), buf);
        }
   }
return TRUE;
}
/*********************************/

/* click mouse button in matarea to edit value of matrix ***** Callback  "mouse_press" event */
gboolean
button_press_matarea (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
int x,y;
GdkModifierType state;

/* if we are in the correct part of the matrix */
gdk_window_get_pointer(widget->window,&x,&y,&state);
if (x > PIX) return FALSE;
if(is_freeze_aij==0) { /* toggle to permit editing */
        gtk_entry_set_editable(GTK_ENTRY(entry_aij),TRUE);
        is_freeze_aij=1;
        gtk_label_set_text (GTK_LABEL(label_space),"(editable)    ");
        sprintf(SBUF,"   To return to viewing values, click a mouse button in the drawing area  -  to finalize change, type the ENTER key on kbd");
        g_idle_add((GtkFunction) a_edit_status_update,NULL);
        }
else {
        gtk_entry_set_editable(GTK_ENTRY(entry_aij),FALSE);
        is_freeze_aij=0;
        gtk_label_set_text (GTK_LABEL(label_space),"(view only)   ");
        SBUF[0]=0;
        g_idle_add((GtkFunction) a_edit_status_update,NULL);
        }
return TRUE;
}
/*********************************/

/******************* drawing (matarea and albels) routines  ******************/

/* update of the labels - to be called after each matrix change and after max_min_ab_compute()*/
int
a_labels_update()
{
/* double matabmax, matabqmin; globals */
char buf[256];
sprintf(buf,"  %lg  ",st_def());
gtk_label_set_text (GTK_LABEL(label_222),buf);
sprintf(buf,"This Block:  max=%g  min=%g ",matabmax,matabqmin);
gtk_label_set_text (GTK_LABEL(label_231),buf);
sprintf(buf,"All Blocks: max=%g  min=%g ",aamax(),aamin());
gtk_label_set_text (GTK_LABEL(label_232) ,buf);
return(0);
}
/*********************************/

/* update of the statusbar - to be called after each matrix change */
int
a_edit_status_update()
{
gtk_statusbar_push(GTK_STATUSBAR(statusb_edita),0,SBUF);
return(0);
}
/*********************************/

/* calculating image from A block data */
void
image_compute(int q)
{
/* int a_selected_block,a_computed_block,a_displayed_block; globals */
/* int * matvalue; global */
int i,j,h,k,m,v;
double r;
if(is_debug==1) printf("image_compute: block %d\n",q);
m=committed.dimension_m;
if (pea.is_range_type==2) for(i=0;i<256;i++) numlev[i]=0; /* adaptive range type */

if (pea.is_color==0) {
   /* compute matvalue   for gray  */
   for(i=0;i<PIX;i++) for(j=0;j<PIX+PIXS+PIXV;j++) {
        h=(i*m)/PIX+1;
        k=(j*m)/PIX+1;
	if (j<PIX) { /* block values */
                  read_mata_(&h,&k,&q,&r);
		  v=get_gray_level(r);
		  if ((pea.is_range_type==2)&&(pea.is_user==1)) numlev[v]++;
		 if (pea.is_positive==1) v=255-v;
		  matvalue[i*(PIX+PIXS+PIXV)+j]=  (char)v;
		}
	else if (j<PIX+2) { /* black line */
		 matvalue[i*(PIX+PIXS+PIXV)+j] = 255*pea.is_positive;
		}
	else if (j<PIX+PIXS-2) { /* gray space */
		matvalue[i*(PIX+PIXS+PIXV)+j] = 225;/* ligth gray */	
		}		
	else if (j<PIX+PIXS) {/* black line */
		matvalue[i*(PIX+PIXS+PIXV)+j] = 255*pea.is_positive;
		}
	else  { /* vertical column with sums of rows values */
	        v=get_gray_level(as[h]);
		if ((pea.is_range_type==2)&&(pea.is_user==1)) numlev[v]++;
		if (pea.is_positive==1) v=255-v;
		matvalue[i*(PIX+PIXS+PIXV)+j] =  (char)v;
		}
        }
   /* matvalue computed */
   } else {
   /* compute rgb_matvalue for colors */
   for(i=0;i<PIX;i++) for(j=0;j<PIX+PIXS+PIXV;j++) {
        h=(i*m)/PIX+1;
        k=(j*m)/PIX+1;
        if (j<PIX) { /* block values */
                  read_mata_(&h,&k,&q,&r);
		  v=get_gray_level(r);
  		  if ((pea.is_range_type==2)&&(pea.is_user==1)) numlev[v]++;
		  if (pea.is_positive==1) v=255-v;
                  rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)]=  (char)v;
                  rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)+1]=  (char)(35);
                  rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)+2]= (char)(255-v);
                }
        else if (j<PIX+2) { /* black line */
                 rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)] =   (char)(255*pea.is_positive);
                 rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)+1] = (char)(255*pea.is_positive); 
                 rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)+2] = (char)(255*pea.is_positive);

                }
        else if (j<PIX+PIXS-2) { /* gray space */
                rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)] = (char)225;
                rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)+1] = (char)255;
                rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)+2] = (char)225;
                } 
        else if (j<PIX+PIXS) {/* black line */
                rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)] = (char)(255*pea.is_positive);
                rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)+1] = (char)(255*pea.is_positive);
                rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)+2] = (char)(255*pea.is_positive);
                }
        else  { /* vertical column with sums of rows values */
		v = get_gray_level(as[h]);
                if ((pea.is_range_type==2)&&(pea.is_user==1)) numlev[v]++;
		if (pea.is_positive==1) v=255-v;
                rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)] =  (char)v;
                rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)+1] =  (char)(35);
                rgb_matvalue[3*(i*(PIX+PIXS+PIXV)+j)+2] =  (char)(255-v);
                }
        }
   /* rgb_matvalue computed */
   }
a_computed_block=q;
if(is_debug==1) printf("image_compute: a_computed_block=%d \n",a_computed_block);
}
/*********************************/

/* draw matarea uses matvalue or rgb_matvalue to redraw into matarea drawable and sets a_displayed_block */
void
draw_matarea()
{
if (pea.is_color==0) gdk_draw_gray_image (matarea->window,
                matarea->style->fg_gc[GTK_WIDGET_STATE (matarea)],
                0, 0, PIX+PIXS+PIXV,PIX,GDK_RGB_DITHER_NORMAL,matvalue,PIX+PIXS+PIXV);
                else
                gdk_draw_rgb_image(matarea->window,
                matarea->style->fg_gc[GTK_WIDGET_STATE (matarea)],
                0, 0, PIX+PIXS+PIXV,PIX,GDK_RGB_DITHER_NORMAL,rgb_matvalue,3*(PIX+PIXS+PIXV));
a_displayed_block=a_computed_block;
}
/*********************************/

/* the levels gray_levels[256] are number ordered increasing  */
/* we get the index i such that gray_levels[i]<=x<gray_levels[i+1] */
/* precisely:
 * 0   x (-inf,L[1])  L[1]=0 typical   L[0] not used !!!
 * 1   x [L[1], L[2])
 * .....
 * 254 x [L[254],L[255]) 
 * 255 x [L255], +inf) L[255]=1 typical
 */
int
get_gray_level(double x)
{
int i;
i=0;
if (x > gray_levels[128])  i=128;
if (x > gray_levels[i+64]) i+=64;
if (x > gray_levels[i+32]) i+=32;
if (x > gray_levels[i+16]) i+=16;
if (x > gray_levels[i+8]) i+=8;
if (x > gray_levels[i+4]) i+=4;
if (x > gray_levels[i+2]) i+=2;
if (x > gray_levels[i+1]) i+=1;
return(i);
}
/*********************************/

/* linear or nonlinear setup of gray_levels 
 * parameter a affects the shape of nonlinear curve 
 * in the case of user selected range type 0 1 2 and
 * in such cases tha max and min values computed by 
 * max_min_ab_compute() are needed !
 */
void
gray_levels_setup(double a)
{
/* double asmax, asmin, matabmax, matabmin,matabqmin;    globals */
int i;
double min,max;
if (pea.is_user==0) {
	gray_levels[0]=0; /* not used ... */
        for (i=1;i<256;i++) gray_levels[i]= ((double)1.0 *(i-1))/254.0; /* L[1]=0.0  L[255]=1.0 */
	if(is_debug==1) printf("gray_levels_setup: (user=0) a=%g, L[0]=%g,L[1]=%g,L[2]=%g,...L[254]=%g,L[255]=%g\n",a,gray_levels[0],gray_levels[1],gray_levels[2],gray_levels[254],gray_levels[255]);
        return;
	} else {      
        switch(pea.is_range_type) {
	   case 2: 
		min=matabqmin; /* first non zero minimum if possible */
                max=asmax;
		break;
	   case 1: /* [matabqmin,asmax] */
                min=matabqmin;
                max=asmax;
		break;
	   case 0: /* [0,1] full range */
		min=0;
                max=1;
		break;
	   default:
		min=0;
		max=1;
           }
       if(min==max) {min=0;max=1;} /* is needed ??? */
       gray_levels[0]=0;
       gray_levels[1]=0; /* hard minimum is fixed to 0.0 */
       if(a==0) for (i=2;i<256;i++) gray_levels[i]= (max-min)*((double)1.0 *(i-1))/254.0 + min;
       if(a>0) for (i=2;i<256;i++) gray_levels[i]= (max-min)*pow(((double)1.0 *(i-1))/254.0,a)+min;
       if(a<0) for (i=2;i<256;i++) gray_levels[i]= (max-min)*pow(((double)1.0 *(i-1))/254.0,-1/(a-1))+min;
       }
if(is_debug==1) printf("gray_levels_setup: (user=1) a=%g, max=%g min=%g L[0]=%g,L[1]=%g,L[2]=%g,...L[254]=%g,L[255]=%g\n",a,max,min,gray_levels[0],gray_levels[1],gray_levels[2],gray_levels[254],gray_levels[255]);
}
/*********************************/

/******************* utility routines  ***********************/

/* Stochasticity Defect od A */
double
st_def()
{
double sum,s,r;
int i,j,k;

sum=(double)0.0;
for(i=1;i<=committed.dimension_m;i++) {
s=(double)0.0;
for(k=1;k<=committed.matrix_a_num;k++)  for(j=1;j<=committed.dimension_m;j++) {
  read_mata_(&i,&j,&k,&r);
  s=s+r;
  }  
s=(double)1.0-s;
sum=sum+s*s;
}
sum=sqrt(sum);
return (sum);
}
/*********************************/

/* A block max */
double
abmax(int q)
{
double max,r;
int i,j;
max=-1.0E100;
for(i=1;i<=committed.dimension_m;i++)  for(j=1;j<=committed.dimension_m;j++) {
  read_mata_(&i,&j,&q,&r);
  if (max < r) max=r;
  }
return(max);
}
/*********************************/

/* A block min */
double
abmin(int q)
{
double min,r;
int i,j;
min=1.0E100;
for(i=1;i<=committed.dimension_m;i++)  for(j=1;j<=committed.dimension_m;j++) {
  read_mata_(&i,&j,&q,&r);
  if (min > r) min=r;
  }
return(min);
}
/*********************************/

/* A block quasi min returns 1.0E100 if block is all 0 !*/
double
abqmin(int q)
{
double min,r;
int i,j;
min=1.0E100;
for(i=1;i<=committed.dimension_m;i++)  for(j=1;j<=committed.dimension_m;j++) {
  read_mata_(&i,&j,&q,&r);
  if ((min > r)&&(r>0)) min=r;
  }
return(min);
}
/*********************************/

/* A block truncate in [0,1] */
void
abtrunc(int q)
{
int i,j;
double r;
for(i=1;i<=committed.dimension_m;i++)  for(j=1;j<=committed.dimension_m;j++) {
  read_mata_(&i,&j,&q,&r);
  if (r<(double)0.0) r=(double)0.0;
  if (r>(double)1.0) r=(double)1.0;
  write_mata_(&i,&j,&q,&r);
  }
}
/*********************************/

/* A  truncate in [0,1] */
void
aatrunc()
{
int k;
for (k=1;k<committed.matrix_a_num;k++) abtrunc(k);
}
/*********************************/

/* A  max */
double
aamax()
{
double max,r;
int k;
max=abmax(1);
for(k=2;k<=committed.matrix_a_num;k++)   {
  r=abmax(k);
  if (max < r) max=r;
  }
return(max);
}
/*********************************/

/* A  min */
double
aamin()
{
double min,r;
int k;
min=abmin(1);
for(k=2;k<=committed.matrix_a_num;k++)   {
  r=abmin(k);
  if (min > r) min=r;
  }

return(min);
}
/*********************************/

/* compute max min every time block is changed */
void
max_min_ab_compute()
{
int i,j,q;
double r;

q=a_selected_block;
matabmax = abmax(q);
matabmin = abmin(q);
matabqmin = abqmin(q);
if (matabqmin >matabmin) matabqmin=matabmin; /* all 0 case */
/* sums the rows of the block and compute their maximum */
i=1;
j=1;
read_mata_(&i,&j,&q,&r);
asmax=r;
asmin=r;
for(i=1;i<=committed.dimension_m;i++) { 
                as[i]=0.0;
                for(j=1;j<=committed.dimension_m;j++) {
                        read_mata_(&i,&j,&q,&r);
                        as[i]=as[i]+r;
                        }
                if(as[i]>asmax) asmax=as[i];
                if((as[i]<asmin)&&(as[i]>1.0E-30)) asmin=as[i];
                }

if(is_debug==1) printf("max_min_ab_compute: block=%d, matabmax=%g, matabmin=%g, matabqmin=%g\n",a_selected_block,matabmax,matabmin,matabqmin);
}
/*********************************/

/* adaptive case: recompute levels 
 * using old levels and numerosity of levels numlev 
 * must be called after computing once gray levels and image
 */
void
recompute_levels(double a)
{
/* double gray_levels[256]; global */
double newlev[256];
double max,min,v;
int quota[256], interval[256],interval_num[256];
int i,j,k,h;
int s,usl,unusl,spacers;
int cont;
/* memo:
 * the levels gray_levels[256] are number ordered increasing  
 * we get the index i such that gray_levels[i]<=x<gray_levels[i+1] 
 * precisely:
 * 0   x (-inf,L[1])  L[1]=0 typical   L[0] not used !!! numlevel[0] refers to <= L[1]
 * 1   x [L[1], L[2])                                    numlevel[1] refers to  <=L[2]
 * .....
 * 254 x [L[254],L[255]) 
 * 255 x [L255], +inf) L[255]=1 typical                  numlevel[255] refers to >=L[255] 
 */
/* memo:
 * in the step prior to this, we did call max_min_ab_compute and  gray_levels_setup with
 * min=matabqmin; max=asmax; and the choosen contrast, L[0]=L[1]=0,
 * and L[2]...L[255] were assigned with
 * (max-min)*pow(((double)1.0 *(i-1))/254.0,a)+min or similar, depending on 
 * the contrast a.
 */
/* memo:
 * PIX*(PIX+PIV) is the total number of pixels, the sum of numlev.
 */

/* count unused levels  */
usl=0;
unusl=0;
for(i=0;i<256;i++) if( numlev[i] ==0) unusl++; else usl++;
if(is_debug==1) {
                printf("recompute_levels:  entering we count on 256 levels %d assigned levels,   %d unassigned levels\n",usl,unusl);
                }
/* clean all */
for(i=0;i<256;i++){ 
		interval[i]=0;
		interval_num[i]=0;
		newlev[i]=-1.0;
                quota[i]=0;
		}
/* compute interval[i], reporting the number of nonvoid levels starting on i-th level */
for(i=0;i<256;i++){
    if(numlev[i]!=0) {
	j=i; 
	cont=0;
	while (cont==0){
		j++;
		if((numlev[j]==0)||(j==256)) cont=1;
		}
	interval[i]=j-i; /* if j==i 1 */
        i=j;
       }/* else increment i */
    }
/* compute numerosity of intervals */
for (i=0;i<256;i++) if (interval[i]!=0) {
	s=0;
	for (j=i;j<i+interval[i];j++) s=s+numlev[j];
	interval_num[i]=s;
	}
if(is_debug==1) for(i=0;i<256;i++) if(interval_num[i]!=0) printf("recompute_levels:  pre reassign interval[%d]=%d, interval_num=%d bounds [%g,%g]\n",i,interval[i],interval_num[i],gray_levels[i],gray_levels[i+interval[i]]);
/* reassign levels */
k=0;
for(i=0;i<256;i++) if (interval[i]!=0) k=k+interval_num[i]; /* well k should be PIX*(PIX+PIXV), but we check for debugging errors ... */
if(is_debug==1) printf("recompute_levels:  pre reassign interval numerosity %d - PIX=%d\n",k,PIX*(PIX+PIXV));
/* we now reassign the free levels giving a quota[i] to each non void interval i */
/* k is the total number of pixels involved in reassign , interval_num[i] in every interval */
for(i=0;i<256;i++) if (interval[i]!=0) { /* these are the intervals to reassign */
        v=interval_num[i] *unusl;
	quota[i]= interval[i]+floor(v/k) ;
    }
/* better count totals ... */
j=0;
for(i=0;i<256;i++) if (interval[i]!=0) j=j+quota[i];
spacers=256-j; /* these levels can be used to separate leves with void levels */
if (is_debug==1)    printf("recompute_levels:  now we count on 256 levels %d assigned levels,   %d unassigned levels, reassigning total %d, spacers=%d\n",usl,unusl,j,spacers);
/* now reassign spacers to biggest  quota  */
k=0;
for(i=0;i<256;i++) if(interval[i]!=0) if(quota[i]>k) {h=i; k=quota[i];}
quota[h]=quota[h]+spacers;
/* better recount totals ... */
j=0;
for(i=0;i<256;i++) if (interval[i]!=0) j=j+quota[i];
spacers=256-j; /* these levels can be used to separate leves with void levels */
if (is_debug==1)    printf("recompute_levels:  now we recount on 256 levels %d assigned levels,   %d unassigned levels, reassigning total %d, spacers=%d\n",usl,unusl,j,spacers);

newlev[0]=0.0;
j=1;  /*first level to reassign */
for(i=0;i<256;i++) if (interval[i]!=0) {
	min=gray_levels[i];
	if(i+1+interval[i] <256) max=gray_levels[i+1+interval[i]]; else max=1.1;
	if (is_debug==1) printf("recompute_levels: interval %d [%g,%g] : reassigning %d levels (old %d) \n",i, min,max,quota[i],interval[i]);
          if(a==0) for (k=j;k<j+quota[i];k++) newlev[k]= (max-min)*((double)1.0 *(k-j))/quota[i] + min;
          if(a>0)  for (k=j;k<j+quota[i];k++) newlev[k]= (max-min)*pow(((double)1.0 *(k-j))/quota[i],a)+min;
          if(a<0)  for (k=j;k<j+quota[i];k++) newlev[k]= (max-min)*pow(((double)1.0 *(k-j))/quota[i],-1/(a-1))+min;
	  j=j+quota[i];
          }

/* at this point there should be no newlev with value -1 ! */
for(i=0;i<256;i++) if (newlev[i]==-1.0) printf("nelwv = -1 !!! %d\n",i);

/* now copy and sort the levels */
gray_levels[0]=newlev[0];
for(i=0;i<256;i++) { /* get the minimum for the first gray level */
        if (newlev[i]<gray_levels[0]) gray_levels[0]=newlev[i];
        }
gray_levels[255]=gray_levels[0];
for(i=0;i<256;i++) { /* get the maximum for the last gray level */
        if (newlev[i]>gray_levels[255]) gray_levels[255]=newlev[i];
        }
for(i=1;i<255;i++) { /* for others levels go growing */
     gray_levels[i]=gray_levels[255];
     for (j=0;j<256;j++) if ((newlev[j]<gray_levels[i])&&(newlev[j]>gray_levels[i-1])) gray_levels[i]=newlev[j];
   }

/* now insert spacers if any */
}
/*********************************/

/* Stochasticity Defect of B */
/* type =1 QBD, =2 M/G/1, =3 GI/M/1 */
/* this should go in edit_b.c ! */
double
st_def_b(int type)
{
double sum,s,x;
int i,j,h,k,kmax;

sum=(double)0.0;
switch(type) {
	case 1: /* QBD */
        /* sum of rows of B0 B if optional B is present, else B0 A(3) */
	 for (i=1;i<=committed.dimension_n;i++) {
	 s=0;
	 for(j=1;j<=committed.dimension_n;j++) {
	    read_matb0_(&i,&j,&x);
	    s=s+x;
	    }
	 for(j=1;j<=committed.dimension_m;j++) {
            if (committed.is_b==1) {
		k=1;
		read_matb_(&i,&j,&k,&x);
                s=s+x;
		} else { /* in this case committed.dimension_n = committed.dimension_m */
		k=3;
		read_mata_(&i,&j,&k,&x);
		s=s+x;
		}
	    }
	 s=(double)1.0-s;
         sum=sum+s*s;
	}
	/* sums of rows BN1, A(1) A(2) */
	for (i=1;i<=committed.dimension_m;i++) {
	s=0;
	for(j=1;j<=committed.dimension_n;j++) {
            read_matbn1_(&i,&j,&x);
            s=s+x;
	    }
	k=2;
	for(j=1;j<=committed.dimension_m;j++) {
            read_mata_(&i,&j,&k,&x);
            s=s+x;
	    }
	k=3;
	for(j=1;j<=committed.dimension_m;j++) {
            read_mata_(&i,&j,&k,&x);
            s=s+x;
	    }
	s=(double)1.0-s;
        sum=sum+s*s;
	}
	break;
	case 2: /* M/G/1 */
        /* printf(" m=%d n=%d\n",committed.dimension_m,committed.dimension_n);*/
	/* sum of rows of B0, B */
	for (i=1;i<=committed.dimension_n;i++) {
	     s=0;
	     for (j=1;j<=committed.dimension_n;j++) {
		   read_matb0_(&i,&j,&x);
		   s=s+x;
		   /* printf(" B0  row %d column %d x=%g s=%g\n",i,j,x,s);*/
		   }
	     for (k=1;k<=committed.matrix_b_num;k++) for (j=1;j<=committed.dimension_m;j++) {
                   read_matb_(&i,&j,&k,&x);
                   s=s+x;
		   /* printf("B: block %d row %d column %d x=%g s=%g\n",k,i,j,x,s);*/
                   } 
	     s=(double)1.0-s;
	     sum=sum+s*s;
                /* printf("SUM=%g\n",sum);*/
	     }
	/* if optional BN1 is present sum of rows of BN1 A0, A1, ...*/
	if( committed.is_bn1==1) for (i=1;i<=committed.dimension_m;i++) {
            s=0;
            for (j=1;j<=committed.dimension_n;j++) {
                   read_matbn1_(&i,&j,&x);
                   s=s+x;
		    /* printf(" BN1  row %d column %d x=%g s=%g\n",i,j,x,s);*/
                   }
        /* we suppose committed.matrix_a_num >2 .... */
            for (k=2;k<=committed.matrix_a_num;k++) for (j=1;j<=committed.dimension_m;j++) {
                   read_mata_(&i,&j,&k,&x);
                   s=s+x;
                   /* printf("A: block %d row %d column %d x=%g s=%g\n",k,i,j,x,s);*/
                   }
	   s=(double)1.0-s;
           sum=sum+s*s;
	      /* printf("SUM=%g\n",sum); */
           }
	break;

	case 3: /* GI/M/1 */
        /* sum of rows of B0 BN1 if present else B0 and A(1) */
	for (i=1;i<=committed.dimension_n;i++) {
             s=0;
	     for (j=1;j<=committed.dimension_n;j++) {
                   read_matb0_(&i,&j,&x);
                   s=s+x;
                   /* printf(" B0  row %d column %d x=%g s=%g\n",i,j,x,s);*/
                   }
	     if( committed.is_bn1==1) for (j=1;j<=committed.dimension_m;j++) {
                   read_matbn1_(&i,&j,&x);
                   s=s+x;
                   /* printf(" BN1  row %d column %d x=%g s=%g\n",i,j,x,s);*/
                   } else { /* read AN1= A(1) and note that committed.dimension_m =  committed.dimension_n */
                   k=1;
		   for (j=1;j<=committed.dimension_m;j++) {
                       read_mata_(&i,&j,&k,&x);
                       s=s+x;
		       }
		   }
	      s=(double)1.0-s;
              sum=sum+s*s;
                /* printf("SUM=%g\n",sum);*/
	     }
	/* compute kmax */
	if(committed.matrix_a_num -1 > committed.matrix_b_num) kmax = committed.matrix_b_num; else kmax = committed.matrix_a_num -1 ;
	for (k=1;k<=kmax;k++) for (i=1;i<=committed.dimension_m;i++) {
		s=0;
             for (j=1;j<=committed.dimension_n;j++) {
                   read_matb_(&i,&j,&k,&x);
                   s=s+x;
                   /* printf(" B0  row %d column %d x=%g s=%g\n",i,j,x,s);*/
                   }
             for (h=1;h<=k+1;h++) for(j=1;j<=committed.dimension_m;j++){
                   read_mata_(&i,&j,&h,&x);
                   s=s+x;
                   /* printf(" BN1  row %d column %d x=%g s=%g\n",i,j,x,s);*/
                   }
              s=(double)1.0-s;
              sum=sum+s*s;
                /* printf("SUM=%g\n",sum);*/
	  }	
	break;
	default:
	sum=(double)1.0;
}
sum=sqrt(sum);
/* printf("FINAL SUM = %g\n",sum); */
return (sum);
}
/*********************************/

/* B0,BN1, B  min for the committed problem */
double
bbbmin()
{
double min,r;
int i,j,k,bn,bm;
i=1;
j=1;
read_matb0_(&i,&j,&r);
min=r;
for(i=1;i<=committed.dimension_n;i++) for(j=1;j<=committed.dimension_n;j++) {
		read_matb0_(&i,&j,&r);
		if (r<min) min=r;
		}
if(committed.type==3) { /* GIM1 has BN1 and B blocks  with inverted dimensions */
bm=committed.dimension_n;
bn=committed.dimension_m;
} else {  /* QBD and M/G/1  */
bm=committed.dimension_m;
bn=committed.dimension_n;
}
if (committed.is_bn1==1) for(i=1;i<=bm;i++) for(j=1;j<=bn;j++) {
	read_matbn1_(&i,&j,&r);
        if (r<min) min=r;
        }
if (committed.is_b==1) for(k=1;k<=committed.matrix_b_num;k++) for(i=1;i<=bn;i++) for(j=1;j<=bm;j++) {
	read_matb_(&i,&j,&k,&r);
        if (r<min) min=r;
        }
return(min);
}
/*********************************/


