//---------------------------------------------------------------------
#include <vcl.h>
#include "ChildWin.h"
#include "setepsdialog.h"
#include <math.h>

#pragma hdrstop

//---------------------------------------------------------------------
#pragma link "XPMenu"
#pragma link "AdvGrid"
#pragma link "BaseGrid"
#pragma resource "*.dfm"
//---------------------------------------------------------------------
__fastcall TMDIChild::TMDIChild(TComponent *Owner)
	: TForm(Owner)
{
        lp=NULL;
        solution=NULL;
        ls=NULL;
        selectAll=false;
        initGrids();
        memset(bases,0,sizeof(int)*MAX_VAR);
}
//---------------------------------------------------------------------
void __fastcall TMDIChild::FormClose(TObject *Sender, TCloseAction &Action)
{
	Action = caFree;
}
//---------------------------------------------------------------------

void __fastcall TMDIChild::Button3Click(TObject *Sender)
{
        Close();
}
//---------------------------------------------------------------------------


void TMDIChild::initGrids()
{
        mxGrid->RowCount=MAX_VAR+3;
        mxGrid->ColCount=MAX_VAR+3;
        mxGrid->FixedRows=2;
        mxGrid->FixedCols=1;
        mxGrid->Cells[0][0]="Matrix";
        mxGrid->Cells[1][0]="RHS";
        mxGrid->Cells[0][1]="Solution";
        for(int i=2;i<1003;++i){
                mxGrid->Cells[i][0]="Col "+IntToStr(i-1);
                mxGrid->Cells[0][i]="Row "+IntToStr(i-1);
        }

        luGrid->Cells[0][0]="L/U matrix" ;
        for(int i=1;i<1002;++i){
                luGrid->Cells[i][0]="Col "+IntToStr(i);
                luGrid->Cells[0][i]="Row "+IntToStr(i);
        }
        scaledGrid->Cells[0][0]="Factors";
        simplexGrid->Cells[0][0]="Base";
        simplexGrid->Cells[1][0]="RHS";


}
//---------------------------------------------------------------------------
void TMDIChild::LoadFromMPS(String Name)
{
        lp = lpx_read_mps(Name.c_str());
        if (lp==NULL){
                Close();
                return;
        }

        int num_variables=lpx_get_num_cols(lp);

        for (int i=1;i<=lpx_get_num_cols(lp);++i){
                mxGrid->Cells[i+1][0]=lpx_get_col_name(lp,i);
        }

        int num_eqs=0;
        for (int i=1;i<=lpx_get_num_rows(lp);++i){
                if (lpx_get_row_type(lp,i)==LPX_FX){
                        ++num_eqs;
                        mxGrid->Cells[0][num_eqs+1]=lpx_get_row_name(lp,i);
                }
        }
        ls=ls_init(num_eqs,num_variables);

        if(solution!=NULL) delete[] solution;
        solution=new double[num_eqs];

        num_eqs=0;

        for (int j=1 ;j<=lpx_get_num_rows(lp);++j){
                if (lpx_get_row_type(lp,j)==LPX_FX){
                        int ind[MAX_VAR];
                        int len;
                        double val[MAX_VAR];
                        linmx_setrhs(ls->extmx,num_eqs+1,lpx_get_row_lb(lp,j));
                        len=lpx_get_mat_row(lp,j,ind,val);
                        for(int i=1;i<=len;++i){
                                linmx_setat(ls->extmx,num_eqs+1,ind[i],val[i]);
                        }
                        ++num_eqs;
                }
        }

        nBasesSelected=0;
        mxGrid->FloatFormat="%."+IntToStr((int)ceil(fabs(log10(ls->extmx->eps))))+"f";
        UpdateView();

}
//---------------------------------------------------------------------------
__fastcall TMDIChild::~TMDIChild()
{
        if(lp!=NULL)
                lpx_delete_prob(lp);
        if(ls!=NULL)
                ls_dispose(ls);
        if(solution!=NULL) delete[] solution;
}
//---------------------------------------------------------------------------
void TMDIChild::UpdateView()
{
        if(ls==NULL) return;
        for(int i=0;i<ls->extmx->rows;++i){
                double newval;
                newval=linmx_getrhs(ls->extmx,i+1);
                newval*=linmx_getrowfactor(ls->extmx,i+1);

                mxGrid->Floats[1][i+2]=newval;
                for(int j=0;j<ls->extmx->cols;++j){
                        newval=linmx_getat(ls->extmx,i+1,j+1);
                        newval*=linmx_getrowfactor(ls->extmx,i+1);
                        newval*=linmx_getcolfactor(ls->extmx,j+1);
                        mxGrid->Floats[j+2][i+2]=newval;
                }
        }
        if(ls->lu==NULL){
                for(int i=0;i<ls->extmx->rows;++i){
                        for(int j=0;j<ls->extmx->rows;++j)
                                luGrid->Cells[j+1][i+1]="";
                }
                return;
        }
        for(int i=0;i<ls->extmx->rows;++i){
                for(int j=0;j<ls->extmx->rows;++j)
                        luGrid->Floats[j+1][i+1]=ls->lu[i*ls->extmx->rows+j];
        }
        for(int i=1;i<=ls->extmx->cols;++i){
                scaledGrid->Floats[i][0]=linmx_getcolfactor(ls->extmx,i);
                for(int j=1;j<=ls->extmx->rows;++j){
                        scaledGrid->Floats[i][j]=linmx_getat(ls->extmx,j,i);
                }
        }
        for(int j=1;j<=ls->extmx->rows;++j){
                 scaledGrid->Floats[0][j]=linmx_getrowfactor(ls->extmx,j);
        }
        outputX();
        outputSigma();
}
//---------------------------------------------------------------------------
void __fastcall TMDIChild::mxGridButtonClick(TObject *Sender, int ACol,
      int ARow)
{
        if(ls==NULL) return;
        if (ARow!=0) return;
        if(ACol<2||ACol>ls->extmx->cols+1) return;
        if(bases[ACol-2]){
                bases[ACol-2]=0;
                --nBasesSelected;
        }else{
                bases[ACol-2]=1;
                ++nBasesSelected;
        }
        bnSimplex->Enabled=false;
        TabSheet3->TabVisible=false;

        if(nBasesSelected==ls->extmx->rows){
                bnCreate->Enabled=true;
                if(ls->luvalid==_TRUE){
                    bnUpdate->Enabled=true;
                }else{
                    bnUpdate->Enabled=false;
                }
        }else{
                bnCreate->Enabled=false;
                bnUpdate->Enabled=false;
        }
        mxGrid->Repaint();
}
//---------------------------------------------------------------------------

void __fastcall TMDIChild::mxGridGetCellColor(TObject *Sender, int ARow,
      int ACol, TGridDrawState AState, TBrush *ABrush, TFont *AFont)
{
        if(ls==NULL) return;
        if (ACol<2||ARow<2) return;
        if(ACol>ls->extmx->cols+1)return;
        if(ARow>ls->extmx->rows+1)return;
        if(bases[ACol-2]) ABrush->Color=clLime;
        else ABrush->Color=clAqua;


}
//---------------------------------------------------------------------------

void __fastcall TMDIChild::bnCreateClick(TObject *Sender)
{

        UpdateMatrix();

        if (Rowscaling1->Checked||Columnscaling1->Checked)
                scaledSheet->TabVisible=true;
        else scaledSheet->TabVisible=false;

        if (Hall1->Checked)
                ls_scaleHall(ls,(int)Rowscaling1->Checked,(int)Columnscaling1->Checked);
        else if (Gondzio1->Checked)
                ls_scaleGondzio(ls,(int)Rowscaling1->Checked,(int)Columnscaling1->Checked);

        if(ls_create_lu(ls,bases)){
                for(int i=0;i<ls->extmx->rows;++i){
                        solution[i]=linmx_getrhs(ls->extmx,i+1);
                }
                ls_solve(ls,solution);
                bnUpdate->Enabled=true;
                TabSheet2->TabVisible=true;
                bnSimplex->Enabled=true;
        }
        else
                Application->MessageBoxA("Selected base is singular!","Error",0);

        UpdateView();
        outputSigma();

}
//---------------------------------------------------------------------------


void TMDIChild::UpdateMatrix()
{
        if(ls==NULL) return;
        for(int i=0;i<ls->extmx->rows;++i){
                linmx_setrhs(ls->extmx,i+1,mxGrid->Floats[1][i+2]);

                for(int j=0;j<ls->extmx->cols;++j){
                        linmx_setat(ls->extmx,i+1,j+1,mxGrid->Floats[j+2][i+2]);
                }
        }
/*      Reset scaling factors*/
        for(int i=1;i<=ls->extmx->rows;++i) linmx_setrowfactor(ls->extmx,i,1);
        for(int i=1;i<=ls->extmx->cols;++i) linmx_setcolfactor(ls->extmx,i,1);

}
//---------------------------------------------------------------------------

void TMDIChild::NewLS(int nVar,int nEq){
        if(solution!=NULL) delete[] solution;
        solution=new double[nEq];
        ls=ls_init(nEq,nVar);
        mxGrid->FloatFormat="%."+IntToStr((int)ceil(fabs(log10(ls->extmx->eps))))+"f";
        UpdateView();
}

void __fastcall TMDIChild::Rowscaling1Click(TObject *Sender)
{
 TMenuItem* rowscaling=(TMenuItem*)Sender;
 rowscaling->Checked=!rowscaling->Checked;
}
//---------------------------------------------------------------------------

void __fastcall TMDIChild::Columnscaling1Click(TObject *Sender)
{
 TMenuItem* colscaling=(TMenuItem*)Sender;
 colscaling->Checked=!colscaling->Checked;
}
//---------------------------------------------------------------------------

void __fastcall TMDIChild::Seteps1Click(TObject *Sender)
{
     SetEpsDlg=new TSetEpsDlg(this);
     SetEpsDlg->edEps->Text=FloatToStr(ls->extmx->eps);
     if(SetEpsDlg->ShowModal()==mrOk){
         try{
             double eps=StrToFloat(SetEpsDlg->edEps->Text);
             if (eps==0) eps=1e-15;
             ls->extmx->eps=eps;
         }catch(EConvertError& e){
             char msg[100];
             sprintf(msg,"Enter a floating point number!\n%s",e.Message.c_str());
             Application->MessageBoxA(msg,"",0);
         }
     }
        mxGrid->FloatFormat="%."+IntToStr((int)ceil(fabs(log10(ls->extmx->eps))))+"f";
     delete SetEpsDlg;
}
//---------------------------------------------------------------------------

void __fastcall TMDIChild::Hall1Click(TObject *Sender)
{
     TMenuItem *mi=(TMenuItem *)Sender;
     if(!mi->Checked){
             mi->Checked=true;
             Gondzio1->Checked=false;
     }
}
//---------------------------------------------------------------------------

void __fastcall TMDIChild::Gondzio1Click(TObject *Sender)
{
     TMenuItem *mi=(TMenuItem *)Sender;
     if(!mi->Checked){
             mi->Checked=true;
             Hall1->Checked=false;
     }
}
//---------------------------------------------------------------------------
void __fastcall TMDIChild::bnUpdateClick(TObject *Sender)
{
    int leaving=-1;
    int entering=-1;
    for(int i=ls->extmx->rows;i>0;--i){
            if(!bases[ls->bases[i-1]-1]){
                leaving=ls->bases[i-1];
                for(int j=ls->extmx->cols;j>0;--j){
                        if(bases[j-1]&&!ls_varinbase(ls,j)){
                             entering = j;
                             break;
                        }
                }
            }
            if((entering!=-1)&&(leaving!=-1)){
                if(ls->num_eta>=MAX_ETA-ls->extmx->cols){
                    Application->MessageBox("Maximum number of updates reached!","",0);
                    return;
                 }
               if(ls_updatelu(ls,entering,leaving)){
//                  Application->MessageBox(("Entering: "+IntToStr(entering)+"\nLeaving: "+IntToStr(leaving)).c_str(),"",0);
                    for(int i=0;i<ls->extmx->rows;++i){
                        solution[i]=linmx_getrhs(ls->extmx,i+1);
                    }
                    ls_solve(ls,solution);
                    entering=-1;
                    leaving=-1;
                    bnSimplex->Enabled=true;
               }
               else  {
                     Application->MessageBox("Selected base is singular!","Error",0);
                     bnUpdate->Enabled=false;
                     return;
               }
            }
    }

    UpdateView();


}
//---------------------------------------------------------------------------


void TMDIChild::outputX()
{
//             Clear cells
               for(int i=0;i<ls->extmx->cols;++i){
                    mxGrid->Cells[i+2][1]="";
               }
               for(int i=0;i<ls->extmx->rows;++i){
                                mxGrid->Floats[ls->bases[i]+1][1]=solution[i];
               }
}

void TMDIChild::outputSigma()
{
        double sigma=0;
        double sumsigma=0;
        for(int i=1;i<=ls->extmx->rows;++i){
              sigma=0;
              for(int j=0;j<ls->extmx->rows;++j){
                             sigma+=solution[j]*linmx_getat(ls->extmx,i,ls->bases[j])*
                             linmx_getrowfactor(ls->extmx,i)*
                             linmx_getcolfactor(ls->extmx,ls->bases[j]);
              }
              sigma=linmx_getrhs(ls->extmx,i)*linmx_getrowfactor(ls->extmx,i)-sigma;
              sumsigma+=fabs(sigma);
        }
        Label1->Caption="Sum of errors is : "+FloatToStr(sumsigma)
        +"\nCondition Number is : "+FloatToStr(linmx_getcond(ls->extmx))
        +"\nRow scaling : "+((ls->rowscaling==_TRUE)?"enabled":"disabled")
        +"\tColumn scaling : "+((ls->colscaling==_TRUE)?"enabled":"disabled")
        +"\nNumber of updates: "+IntToStr(ls->num_updates);
}

//---------------------------------------------------------------------------

void __fastcall TMDIChild::mxGridCellsChanged(TObject *Sender, TRect &R)
{
//                TAdvStringGrid* obj=static_cast<TAdvStringGrid*>(Sender);
                if(R.Top>=2&&R.Top<=ls->extmx->rows+1&&R.Left>=2&&R.Left<=ls->extmx->cols+1){
                  //     linmx_setat(ls->extmx,R.Top-1,R.Left-1,obj->Floats[R.Left][R.Top]);
                       ls->luvalid=_FALSE;
                       bnSimplex->Enabled=false;
                       bnUpdate->Enabled=false;
                       TabSheet2->TabVisible=false;
                       scaledSheet->TabVisible=false;                       
                }else if(R.Left==1&&R.Top>=2&&R.Top<=ls->extmx->rows+1){
                    //   linmx_setrhs(ls->extmx,R.Top-1,obj->Floats[R.Left][R.Top]);
                }
}
//---------------------------------------------------------------------------


void __fastcall TMDIChild::bnSimplexClick(TObject *Sender)
{
     TabSheet3->TabVisible=true;

     //Copy column headers
     for(int i=0;i<ls->extmx->cols;++i){
             simplexGrid->Cells[i+2][0]=mxGrid->Cells[i+2][0];
     }

     // set simplex system base vectors
     for(int i=0;i<ls->extmx->rows;++i){
             simplexGrid->Cells[0][i+1]=mxGrid->Cells[ls->bases[i]+1][0];

             for(int j=0;j<ls->extmx->rows;++j){
                 simplexGrid->Floats[ls->bases[i]+1][j+1]=0;
             }

             simplexGrid->Floats[ls->bases[i]+1][i+1]=1;
     }

     //Compute non-base columns
     for(int i=0;i<ls->extmx->cols;++i){
             if(!ls_varinbase(ls,i+1)){
                 double* sol=linmx_getcol(ls->extmx,i+1);

                 ls_solve(ls,sol);
                 for(int j=0;j<ls->extmx->rows;++j){
                     simplexGrid->Floats[i+2][j+1]=sol[j];
                 }
                 free(sol);
             }
     }

     double* sol=linmx_getrhsvect(ls->extmx);
     ls_solve(ls,sol);
     for(int j=0;j<ls->extmx->rows;++j){
         simplexGrid->Floats[1][j+1]=sol[j];
     }
     free(sol);

}
//---------------------------------------------------------------------------

void __fastcall TMDIChild::BitBtn1Click(TObject *Sender)
{

    bnSimplex->Enabled=false;
    TabSheet3->TabVisible=false;

    if(selectAll){
        for(int i=0;i<ls->extmx->cols;++i) bases[i]=0;
        nBasesSelected=0;
        bnUpdate->Enabled=false;
        bnCreate->Enabled=false;
        selectAll=false;
    }else{
        for(int i=0;i<ls->extmx->cols;++i) bases[i]=1;
        nBasesSelected=ls->extmx->cols;



        if(nBasesSelected==ls->extmx->rows){
                bnCreate->Enabled=true;
                if(ls->luvalid==_TRUE){
                    bnUpdate->Enabled=true;
                }else{
                    bnUpdate->Enabled=false;
                }
        }else{
                bnCreate->Enabled=false;
                bnUpdate->Enabled=false;
        }
        selectAll=true;
    }
    mxGrid->Repaint();
}
//---------------------------------------------------------------------------

