<commit_before>// @(#)root/ged:$Name:  TPadEditor.cxx
// Author: Ilka Antcheva   24/06/04

/*************************************************************************
 * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
//  TPadEditor                                                          //
//                                                                      //
//  Editor of pad/canvas objects.                                       //
//       color and fill style,                                          //
//      'Edit' check box sets pad/canvad editable,                      //
//      'Crosshair' sets a cross hair on the pad,                       //
//      'Fixed aspect ratio' can be set when resizing the pad           //
//      'TickX' and 'TickY' set ticks along the X and Y axis            //
//      'GridX' and 'GridY' set a grid along the X and Y axis           //
//       pad/canvas border size can be set if a sinken or a raised      //
//       border mode is selected; no border mode can be set to          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////
//Begin_Html
/*

*/
//End_Html

#include "TPadEditor.h"
#include "TGClient.h"
#include "TGButton.h"
#include "TGComboBox.h"
#include "TGButtonGroup.h"
#include "TGLabel.h"
#include "TColor.h"
#include "TCanvas.h"

ClassImp(TGedFrame)
ClassImp(TPadEditor)

enum {
   kCOLOR,
   kPAD_FAR,
   kPAD_EDIT,
   kPAD_CROSS,
   kPAD_GRIDX,
   kPAD_GRIDY,
   kPAD_LOGX,
   kPAD_LOGY,
   kPAD_LOGZ,
   kPAD_TICKX,
   kPAD_TICKY,
   kPAD_BSIZE,
   kPAD_BMODE
};

//______________________________________________________________________________
TPadEditor::TPadEditor(const TGWindow *p, Int_t id, Int_t width,
                       Int_t height, UInt_t options, Pixel_t back)
   : TGedFrame(p, id, width, height, options | kVerticalFrame, back)
{
   // Constructor of TPad editor GUI.

   fPadPointer = 0;

   MakeTitle("Pad/Canvas");

   fFixedAR = new TGCheckButton(this, "Fixed aspect ratio", kPAD_FAR);
   fFixedAR->SetToolTipText("Set fixed aspect ratio");
   AddFrame(fFixedAR, new TGLayoutHints(kLHintsTop, 4, 1, 2, 1));

   TGCompositeFrame *f2 = new TGCompositeFrame(this, 80, 20, kHorizontalFrame);
   fCrosshair = new TGCheckButton(f2, "Crosshair", kPAD_CROSS);
   fCrosshair->SetToolTipText("Set crosshair");
   f2->AddFrame(fCrosshair, new TGLayoutHints(kLHintsTop, 3, 1, 1, 1));
   fEditable = new TGCheckButton(f2, "Edit", kPAD_EDIT);
   fEditable->SetToolTipText("Set editable mode");
   f2->AddFrame(fEditable, new TGLayoutHints(kLHintsTop, 3, 1, 1, 1));
   AddFrame(f2, new TGLayoutHints(kLHintsTop, 1, 1, 0, 0));

   TGCompositeFrame *f3 = new TGCompositeFrame(this, 80, 20, kHorizontalFrame);
   fGridX = new TGCheckButton(f3, "GridX", kPAD_GRIDX);
   fGridX->SetToolTipText("Set grid along X");
   f3->AddFrame(fGridX, new TGLayoutHints(kLHintsTop, 3, 1, 1, 1));
   fGridY = new TGCheckButton(f3, "GridY", kPAD_GRIDY);
   fGridY->SetToolTipText("Set grid along Y");
   f3->AddFrame(fGridY, new TGLayoutHints(kLHintsTop, 24, 1, 1, 1));
   AddFrame(f3, new TGLayoutHints(kLHintsTop, 1, 1, 0, 0));

   TGCompositeFrame *f4 = new TGCompositeFrame(this, 80, 20, kHorizontalFrame);
   fTickX = new TGCheckButton(f4, "TickX", kPAD_TICKX);
   fTickX->SetToolTipText("Set tick marks along X");
   f4->AddFrame(fTickX, new TGLayoutHints(kLHintsTop, 3, 1, 1, 1));
   fTickY = new TGCheckButton(f4, "TickY", kPAD_TICKY);
   fTickY->SetToolTipText("Set tick marks along Y");
   f4->AddFrame(fTickY, new TGLayoutHints(kLHintsTop, 24, 1, 1, 1));
   AddFrame(f4, new TGLayoutHints(kLHintsTop, 1, 1, 0, 2));

   MakeTitle("Log Scale");

   TGCompositeFrame *f5 = new TGCompositeFrame(this, 80, 20, kHorizontalFrame);
   fLogX = new TGCheckButton(f5, ":X", kPAD_LOGX);
   fLogX->SetToolTipText("Set logarithmic scale along X");
   f5->AddFrame(fLogX, new TGLayoutHints(kLHintsTop, 4, 1, 1, 1));
   fLogY = new TGCheckButton(f5, ":Y", kPAD_LOGY);
   fLogY->SetToolTipText("Set logarithmic scale along Y");
   f5->AddFrame(fLogY, new TGLayoutHints(kLHintsTop, 15, 1, 1, 1));
   fLogZ = new TGCheckButton(f5, ":Z", kPAD_LOGZ);
   fLogZ->SetToolTipText("Set logarithmic scale along Z");
   f5->AddFrame(fLogZ, new TGLayoutHints(kLHintsTop, 15, 1, 1, 1));
   AddFrame(f5, new TGLayoutHints(kLHintsTop, 1, 1, 0, 0));

   TGCompositeFrame *f6 = new TGCompositeFrame(this, 80, 20, kHorizontalFrame);
   TGButtonGroup *bgr = new TGButtonGroup(f6,3,1,3,0, "Border Mode");
   bgr->SetRadioButtonExclusive(kTRUE);
   fBmode = new TGRadioButton(bgr, " Sinken border", 77);
   fBmode->SetToolTipText("Set a sinken border of the pad/canvas");
   fBmode0 = new TGRadioButton(bgr, " No border", 78);
   fBmode0->SetToolTipText("Set no border of the pad/canvas");
   fBmode1 = new TGRadioButton(bgr, " Raised border", 79);
   fBmode1->SetToolTipText("Set a raised border of the pad/canvas");
   bgr->SetButton(79, kTRUE);
   bgr->SetLayoutHints(new TGLayoutHints(kLHintsLeft, 0,0,3,0), fBmode);
   bgr->Show();
   bgr->ChangeOptions(kFitWidth|kChildFrame|kVerticalFrame);
   f6->AddFrame(bgr, new TGLayoutHints(kLHintsCenterY | kLHintsLeft, 4, 1, 0, 0));
   AddFrame(f6, new TGLayoutHints(kLHintsTop, 1, 1, 0, 0));

   f7 = new TGCompositeFrame(this, 80, 20, kHorizontalFrame);
   TGLabel *fSizeLbl = new TGLabel(f7, "Size:");
   f7->AddFrame(fSizeLbl, new TGLayoutHints(kLHintsCenterY | kLHintsLeft, 6, 1, 0, 0));
   fBsize = new TGLineWidthComboBox(f7, kPAD_BSIZE);
   fBsize->Connect("Selected(Int_t)", "TPadEditor", this, "DoBorderSize(Int_t)");
   fBsize->Resize(92, 20);
   f7->AddFrame(fBsize, new TGLayoutHints(kLHintsLeft, 13, 1, 0, 0));
   fBsize->Associate(this);
   AddFrame(f7, new TGLayoutHints(kLHintsTop, 1, 1, 0, 0));

   MapSubwindows();
   Layout();
   MapWindow();

   TClass *cl = TPad::Class();
   TGedElement *ge = new TGedElement;
   ge->fGedFrame = this;
   ge->fCanvas = 0;
   cl->GetEditorList()->Add(ge);

   fInit = kTRUE;
}

//______________________________________________________________________________
TPadEditor::~TPadEditor()
{
   // Destructor of fill editor.

   TGFrameElement *el;
   TIter next(GetList());

   while ((el = (TGFrameElement *)next())) {
      if (!strcmp(el->fFrame->ClassName(), "TGCompositeFrame"))
         ((TGCompositeFrame *)el->fFrame)->Cleanup();
   }
   Cleanup();
}

//______________________________________________________________________________
void TPadEditor::ConnectSignals2Slots()
{
   // Connect signals to slots.

   fFixedAR->Connect("Toggled(Bool_t)","TPadEditor",this,"DoFixedAspectRatio(Bool_t)");
   fCrosshair->Connect("Toggled(Bool_t)","TPadEditor",this,"DoCrosshair(Bool_t)");
   fEditable->Connect("Toggled(Bool_t)","TPadEditor",this,"DoEditable(Bool_t)");
   fGridX->Connect("Toggled(Bool_t)","TPadEditor",this,"DoGridX(Bool_t)");
   fGridY->Connect("Toggled(Bool_t)","TPadEditor",this,"DoGridY(Bool_t)");
   fTickX->Connect("Toggled(Bool_t)","TPadEditor",this,"DoTickX(Bool_t)");
   fTickY->Connect("Toggled(Bool_t)","TPadEditor",this,"DoTickY(Bool_t)");
   fLogX->Connect("Toggled(Bool_t)","TPadEditor",this,"DoLogX(Bool_t)");
   fLogY->Connect("Toggled(Bool_t)","TPadEditor",this,"DoLogY(Bool_t)");
   fLogZ->Connect("Toggled(Bool_t)","TPadEditor",this,"DoLogZ(Bool_t)");
   fBmode->Connect("Toggled(Bool_t)","TPadEditor",this,"DoBorderMode()");
   fBmode0->Connect("Toggled(Bool_t)","TPadEditor",this,"DoBorderMode()");
   fBmode1->Connect("Toggled(Bool_t)","TPadEditor",this,"DoBorderMode()");

   fInit = kFALSE;
}

//______________________________________________________________________________
void TPadEditor::SetModel(TVirtualPad* pad, TObject* obj, Int_t)
{
   // Pick up the used fill attributes.

   fModel = 0;
   fPad = 0;

   if (obj == 0 || !obj->InheritsFrom("TPad")) {
      SetActive(kFALSE);
      return;
   }

   fModel = obj;
   fPad = pad;

   fPadPointer = (TPad *)fModel;

   Bool_t on;

   on = fPadPointer->HasFixedAspectRatio();
   if (on) fFixedAR->SetState(kButtonDown);
   else fFixedAR->SetState(kButtonUp);

   on = fPadPointer->HasCrosshair();
   if (on) fCrosshair->SetState(kButtonDown);
   else fCrosshair->SetState(kButtonUp);

   on = fPadPointer->IsEditable();
   if (on) fEditable->SetState(kButtonDown);
   else fEditable->SetState(kButtonUp);

   on = fPadPointer->GetGridx();
   if (on) fGridX->SetState(kButtonDown);
   else fGridX->SetState(kButtonUp);

   on = fPadPointer->GetGridy();
   if (on) fGridY->SetState(kButtonDown);
   else fGridY->SetState(kButtonUp);

   Int_t par;
   par = fPadPointer->GetLogx();
   if (par) fLogX->SetState(kButtonDown);
   else fLogX->SetState(kButtonUp);

   par = fPadPointer->GetLogy();
   if (par) fLogY->SetState(kButtonDown);
   else fLogY->SetState(kButtonUp);

   par = fPadPointer->GetLogz();
   if (par) fLogZ->SetState(kButtonDown);
   else fLogZ->SetState(kButtonUp);

   par = fPadPointer->GetTickx();
   if (par) fTickX->SetState(kButtonDown);
   else fTickX->SetState(kButtonUp);

   par = fPadPointer->GetTicky();
   if (par) fTickY->SetState(kButtonDown);
   else fTickY->SetState(kButtonUp);

   par = fPadPointer->GetBorderMode();
   if (par == -1) fBmode->SetState(kButtonDown);
   else if (par == 1) fBmode1->SetState(kButtonDown);
   else fBmode0->SetState(kButtonDown);

   par = fPadPointer->GetBorderSize();
   if (par < 1) par = 1;
   if (par > 16) par = 16;
   fBsize->Select(par);

   if (fInit) ConnectSignals2Slots();
   SetActive();
}

//______________________________________________________________________________
void TPadEditor::DoEditable(Bool_t on)
{
   // Slot connected to the check box 'Editable'.

   fPadPointer->SetEditable(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoCrosshair(Bool_t on)
{
   // Slot connected to the check box 'Crosshair'.

   fPadPointer->SetCrosshair(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoFixedAspectRatio(Bool_t on)
{
   // Slot connected to the check box 'Fixed aspect ratio'.

   fPadPointer->SetFixedAspectRatio(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoGridX(Bool_t on)
{
   // Slot connected to the check box 'GridX'.

   fPadPointer->SetGridx(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoGridY(Bool_t on)
{
   // Slot connected to the check box 'GridY'.

   fPadPointer->SetGridy(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoLogX(Bool_t on)
{
   // Slot connected to the check box 'LogX'.

   fPadPointer->SetLogx(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoLogY(Bool_t on)
{
   // Slot connected to the check box 'LogY'.

   fPadPointer->SetLogy(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoLogZ(Bool_t on)
{
   // Slot connected to the check box 'LogZ'.

   fPadPointer->SetLogz(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoTickX(Bool_t on)
{
   // Slot connected to the check box 'TickX'.

   fPadPointer->SetTickx(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoTickY(Bool_t on)
{
   // Slot connected to the check box 'TickY'.

   fPadPointer->SetTicky(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoBorderMode()
{
   // Slot connected to the border mode settings.

   Int_t mode = 0;
   if (fBmode->GetState() == kButtonDown) mode = -1;
   else if (fBmode0->GetState() == kButtonDown) mode = 0;
   else mode = 1;

   if (!mode) HideFrame(f7);
   else ShowFrame(f7);
   Layout();

   fPadPointer->SetBorderMode(mode);
   Update();
   gPad->Modified();
   gPad->Update();
}

//______________________________________________________________________________
void TPadEditor::DoBorderSize(Int_t size)
{
   // Slot connected to the border size settings.

   fPadPointer->SetBorderSize(size);
   Update();
}
<commit_msg>From Ilka: fixes a typo in a label of the pad editor (thanks to Olivier).<commit_after>// @(#)root/ged:$Name:  TPadEditor.cxx
// Author: Ilka Antcheva   24/06/04

/*************************************************************************
 * Copyright (C) 1995-2002, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
//  TPadEditor                                                          //
//                                                                      //
//  Editor of pad/canvas objects.                                       //
//       color and fill style,                                          //
//      'Edit' check box sets pad/canvad editable,                      //
//      'Crosshair' sets a cross hair on the pad,                       //
//      'Fixed aspect ratio' can be set when resizing the pad           //
//      'TickX' and 'TickY' set ticks along the X and Y axis            //
//      'GridX' and 'GridY' set a grid along the X and Y axis           //
//       pad/canvas border size can be set if a sinken or a raised      //
//       border mode is selected; no border mode can be set to          //
//                                                                      //
//////////////////////////////////////////////////////////////////////////
//Begin_Html
/*

*/
//End_Html

#include "TPadEditor.h"
#include "TGClient.h"
#include "TGButton.h"
#include "TGComboBox.h"
#include "TGButtonGroup.h"
#include "TGLabel.h"
#include "TColor.h"
#include "TCanvas.h"

ClassImp(TGedFrame)
ClassImp(TPadEditor)

enum {
   kCOLOR,
   kPAD_FAR,
   kPAD_EDIT,
   kPAD_CROSS,
   kPAD_GRIDX,
   kPAD_GRIDY,
   kPAD_LOGX,
   kPAD_LOGY,
   kPAD_LOGZ,
   kPAD_TICKX,
   kPAD_TICKY,
   kPAD_BSIZE,
   kPAD_BMODE
};

//______________________________________________________________________________
TPadEditor::TPadEditor(const TGWindow *p, Int_t id, Int_t width,
                       Int_t height, UInt_t options, Pixel_t back)
   : TGedFrame(p, id, width, height, options | kVerticalFrame, back)
{
   // Constructor of TPad editor GUI.

   fPadPointer = 0;

   MakeTitle("Pad/Canvas");

   fFixedAR = new TGCheckButton(this, "Fixed aspect ratio", kPAD_FAR);
   fFixedAR->SetToolTipText("Set fixed aspect ratio");
   AddFrame(fFixedAR, new TGLayoutHints(kLHintsTop, 4, 1, 2, 1));

   TGCompositeFrame *f2 = new TGCompositeFrame(this, 80, 20, kHorizontalFrame);
   fCrosshair = new TGCheckButton(f2, "Crosshair", kPAD_CROSS);
   fCrosshair->SetToolTipText("Set crosshair");
   f2->AddFrame(fCrosshair, new TGLayoutHints(kLHintsTop, 3, 1, 1, 1));
   fEditable = new TGCheckButton(f2, "Edit", kPAD_EDIT);
   fEditable->SetToolTipText("Set editable mode");
   f2->AddFrame(fEditable, new TGLayoutHints(kLHintsTop, 3, 1, 1, 1));
   AddFrame(f2, new TGLayoutHints(kLHintsTop, 1, 1, 0, 0));

   TGCompositeFrame *f3 = new TGCompositeFrame(this, 80, 20, kHorizontalFrame);
   fGridX = new TGCheckButton(f3, "GridX", kPAD_GRIDX);
   fGridX->SetToolTipText("Set grid along X");
   f3->AddFrame(fGridX, new TGLayoutHints(kLHintsTop, 3, 1, 1, 1));
   fGridY = new TGCheckButton(f3, "GridY", kPAD_GRIDY);
   fGridY->SetToolTipText("Set grid along Y");
   f3->AddFrame(fGridY, new TGLayoutHints(kLHintsTop, 24, 1, 1, 1));
   AddFrame(f3, new TGLayoutHints(kLHintsTop, 1, 1, 0, 0));

   TGCompositeFrame *f4 = new TGCompositeFrame(this, 80, 20, kHorizontalFrame);
   fTickX = new TGCheckButton(f4, "TickX", kPAD_TICKX);
   fTickX->SetToolTipText("Set tick marks along X");
   f4->AddFrame(fTickX, new TGLayoutHints(kLHintsTop, 3, 1, 1, 1));
   fTickY = new TGCheckButton(f4, "TickY", kPAD_TICKY);
   fTickY->SetToolTipText("Set tick marks along Y");
   f4->AddFrame(fTickY, new TGLayoutHints(kLHintsTop, 24, 1, 1, 1));
   AddFrame(f4, new TGLayoutHints(kLHintsTop, 1, 1, 0, 2));

   MakeTitle("Log Scale");

   TGCompositeFrame *f5 = new TGCompositeFrame(this, 80, 20, kHorizontalFrame);
   fLogX = new TGCheckButton(f5, ":X", kPAD_LOGX);
   fLogX->SetToolTipText("Set logarithmic scale along X");
   f5->AddFrame(fLogX, new TGLayoutHints(kLHintsTop, 4, 1, 1, 1));
   fLogY = new TGCheckButton(f5, ":Y", kPAD_LOGY);
   fLogY->SetToolTipText("Set logarithmic scale along Y");
   f5->AddFrame(fLogY, new TGLayoutHints(kLHintsTop, 15, 1, 1, 1));
   fLogZ = new TGCheckButton(f5, ":Z", kPAD_LOGZ);
   fLogZ->SetToolTipText("Set logarithmic scale along Z");
   f5->AddFrame(fLogZ, new TGLayoutHints(kLHintsTop, 15, 1, 1, 1));
   AddFrame(f5, new TGLayoutHints(kLHintsTop, 1, 1, 0, 0));

   TGCompositeFrame *f6 = new TGCompositeFrame(this, 80, 20, kHorizontalFrame);
   TGButtonGroup *bgr = new TGButtonGroup(f6,3,1,3,0, "Border Mode");
   bgr->SetRadioButtonExclusive(kTRUE);
   fBmode = new TGRadioButton(bgr, " Sunken border", 77);
   fBmode->SetToolTipText("Set a sinken border of the pad/canvas");
   fBmode0 = new TGRadioButton(bgr, " No border", 78);
   fBmode0->SetToolTipText("Set no border of the pad/canvas");
   fBmode1 = new TGRadioButton(bgr, " Raised border", 79);
   fBmode1->SetToolTipText("Set a raised border of the pad/canvas");
   bgr->SetButton(79, kTRUE);
   bgr->SetLayoutHints(new TGLayoutHints(kLHintsLeft, 0,0,3,0), fBmode);
   bgr->Show();
   bgr->ChangeOptions(kFitWidth|kChildFrame|kVerticalFrame);
   f6->AddFrame(bgr, new TGLayoutHints(kLHintsCenterY | kLHintsLeft, 4, 1, 0, 0));
   AddFrame(f6, new TGLayoutHints(kLHintsTop, 1, 1, 0, 0));

   f7 = new TGCompositeFrame(this, 80, 20, kHorizontalFrame);
   TGLabel *fSizeLbl = new TGLabel(f7, "Size:");
   f7->AddFrame(fSizeLbl, new TGLayoutHints(kLHintsCenterY | kLHintsLeft, 6, 1, 0, 0));
   fBsize = new TGLineWidthComboBox(f7, kPAD_BSIZE);
   fBsize->Connect("Selected(Int_t)", "TPadEditor", this, "DoBorderSize(Int_t)");
   fBsize->Resize(92, 20);
   f7->AddFrame(fBsize, new TGLayoutHints(kLHintsLeft, 13, 1, 0, 0));
   fBsize->Associate(this);
   AddFrame(f7, new TGLayoutHints(kLHintsTop, 1, 1, 0, 0));

   MapSubwindows();
   Layout();
   MapWindow();

   TClass *cl = TPad::Class();
   TGedElement *ge = new TGedElement;
   ge->fGedFrame = this;
   ge->fCanvas = 0;
   cl->GetEditorList()->Add(ge);

   fInit = kTRUE;
}

//______________________________________________________________________________
TPadEditor::~TPadEditor()
{
   // Destructor of fill editor.

   TGFrameElement *el;
   TIter next(GetList());

   while ((el = (TGFrameElement *)next())) {
      if (!strcmp(el->fFrame->ClassName(), "TGCompositeFrame"))
         ((TGCompositeFrame *)el->fFrame)->Cleanup();
   }
   Cleanup();
}

//______________________________________________________________________________
void TPadEditor::ConnectSignals2Slots()
{
   // Connect signals to slots.

   fFixedAR->Connect("Toggled(Bool_t)","TPadEditor",this,"DoFixedAspectRatio(Bool_t)");
   fCrosshair->Connect("Toggled(Bool_t)","TPadEditor",this,"DoCrosshair(Bool_t)");
   fEditable->Connect("Toggled(Bool_t)","TPadEditor",this,"DoEditable(Bool_t)");
   fGridX->Connect("Toggled(Bool_t)","TPadEditor",this,"DoGridX(Bool_t)");
   fGridY->Connect("Toggled(Bool_t)","TPadEditor",this,"DoGridY(Bool_t)");
   fTickX->Connect("Toggled(Bool_t)","TPadEditor",this,"DoTickX(Bool_t)");
   fTickY->Connect("Toggled(Bool_t)","TPadEditor",this,"DoTickY(Bool_t)");
   fLogX->Connect("Toggled(Bool_t)","TPadEditor",this,"DoLogX(Bool_t)");
   fLogY->Connect("Toggled(Bool_t)","TPadEditor",this,"DoLogY(Bool_t)");
   fLogZ->Connect("Toggled(Bool_t)","TPadEditor",this,"DoLogZ(Bool_t)");
   fBmode->Connect("Toggled(Bool_t)","TPadEditor",this,"DoBorderMode()");
   fBmode0->Connect("Toggled(Bool_t)","TPadEditor",this,"DoBorderMode()");
   fBmode1->Connect("Toggled(Bool_t)","TPadEditor",this,"DoBorderMode()");

   fInit = kFALSE;
}

//______________________________________________________________________________
void TPadEditor::SetModel(TVirtualPad* pad, TObject* obj, Int_t)
{
   // Pick up the used fill attributes.

   fModel = 0;
   fPad = 0;

   if (obj == 0 || !obj->InheritsFrom("TPad")) {
      SetActive(kFALSE);
      return;
   }

   fModel = obj;
   fPad = pad;

   fPadPointer = (TPad *)fModel;

   Bool_t on;

   on = fPadPointer->HasFixedAspectRatio();
   if (on) fFixedAR->SetState(kButtonDown);
   else fFixedAR->SetState(kButtonUp);

   on = fPadPointer->HasCrosshair();
   if (on) fCrosshair->SetState(kButtonDown);
   else fCrosshair->SetState(kButtonUp);

   on = fPadPointer->IsEditable();
   if (on) fEditable->SetState(kButtonDown);
   else fEditable->SetState(kButtonUp);

   on = fPadPointer->GetGridx();
   if (on) fGridX->SetState(kButtonDown);
   else fGridX->SetState(kButtonUp);

   on = fPadPointer->GetGridy();
   if (on) fGridY->SetState(kButtonDown);
   else fGridY->SetState(kButtonUp);

   Int_t par;
   par = fPadPointer->GetLogx();
   if (par) fLogX->SetState(kButtonDown);
   else fLogX->SetState(kButtonUp);

   par = fPadPointer->GetLogy();
   if (par) fLogY->SetState(kButtonDown);
   else fLogY->SetState(kButtonUp);

   par = fPadPointer->GetLogz();
   if (par) fLogZ->SetState(kButtonDown);
   else fLogZ->SetState(kButtonUp);

   par = fPadPointer->GetTickx();
   if (par) fTickX->SetState(kButtonDown);
   else fTickX->SetState(kButtonUp);

   par = fPadPointer->GetTicky();
   if (par) fTickY->SetState(kButtonDown);
   else fTickY->SetState(kButtonUp);

   par = fPadPointer->GetBorderMode();
   if (par == -1) fBmode->SetState(kButtonDown);
   else if (par == 1) fBmode1->SetState(kButtonDown);
   else fBmode0->SetState(kButtonDown);

   par = fPadPointer->GetBorderSize();
   if (par < 1) par = 1;
   if (par > 16) par = 16;
   fBsize->Select(par);

   if (fInit) ConnectSignals2Slots();
   SetActive();
}

//______________________________________________________________________________
void TPadEditor::DoEditable(Bool_t on)
{
   // Slot connected to the check box 'Editable'.

   fPadPointer->SetEditable(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoCrosshair(Bool_t on)
{
   // Slot connected to the check box 'Crosshair'.

   fPadPointer->SetCrosshair(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoFixedAspectRatio(Bool_t on)
{
   // Slot connected to the check box 'Fixed aspect ratio'.

   fPadPointer->SetFixedAspectRatio(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoGridX(Bool_t on)
{
   // Slot connected to the check box 'GridX'.

   fPadPointer->SetGridx(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoGridY(Bool_t on)
{
   // Slot connected to the check box 'GridY'.

   fPadPointer->SetGridy(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoLogX(Bool_t on)
{
   // Slot connected to the check box 'LogX'.

   fPadPointer->SetLogx(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoLogY(Bool_t on)
{
   // Slot connected to the check box 'LogY'.

   fPadPointer->SetLogy(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoLogZ(Bool_t on)
{
   // Slot connected to the check box 'LogZ'.

   fPadPointer->SetLogz(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoTickX(Bool_t on)
{
   // Slot connected to the check box 'TickX'.

   fPadPointer->SetTickx(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoTickY(Bool_t on)
{
   // Slot connected to the check box 'TickY'.

   fPadPointer->SetTicky(on);
   Update();
}

//______________________________________________________________________________
void TPadEditor::DoBorderMode()
{
   // Slot connected to the border mode settings.

   Int_t mode = 0;
   if (fBmode->GetState() == kButtonDown) mode = -1;
   else if (fBmode0->GetState() == kButtonDown) mode = 0;
   else mode = 1;

   if (!mode) HideFrame(f7);
   else ShowFrame(f7);
   Layout();

   fPadPointer->SetBorderMode(mode);
   Update();
   gPad->Modified();
   gPad->Update();
}

//______________________________________________________________________________
void TPadEditor::DoBorderSize(Int_t size)
{
   // Slot connected to the border size settings.

   fPadPointer->SetBorderSize(size);
   Update();
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief infrastructure for query optimizer
///
/// @file arangod/Aql/Optimizer.cpp
///
/// DISCLAIMER
///
/// Copyright 2010-2014 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014, triagens GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "Aql/Optimizer.h"
#include "Aql/OptimizerRules.h"

using namespace triagens::aql;

// -----------------------------------------------------------------------------
// --SECTION--                                               the optimizer class
// -----------------------------------------------------------------------------

std::vector<Optimizer::Rule> Optimizer::_rules;

////////////////////////////////////////////////////////////////////////////////
// @brief constructor, this will initialize the rules database
////////////////////////////////////////////////////////////////////////////////

Optimizer::Optimizer () {
  if (_rules.empty()) {
    setupRules();
  }
}

////////////////////////////////////////////////////////////////////////////////
// @brief the actual optimization
////////////////////////////////////////////////////////////////////////////////

int Optimizer::createPlans (ExecutionPlan* plan) {
  int res;
  int leastDoneLevel = 0;
  int maxRuleLevel = _rules.back().level;

  // _plans contains the previous optimisation result
  _plans.clear();
  _plans.push_back(plan, 0);

  int pass = 1;
  while (leastDoneLevel < maxRuleLevel) {
    std::cout << "Entering pass " << pass << " of query optimization..."
              << std::endl;

    // This vector holds the plans we have created in this pass:
    PlanList newPlans;

    // Find variable usage for all old plans now:
    for (auto p : _plans.list) {
      if (! p->varUsageComputed()) {
        p->findVarUsage();
      }
    }

    std::cout << "Have " << _plans.size() << " plans:" << std::endl;

    for (auto p : _plans.list) {
      p->show();
      std::cout << std::endl;
    }

    int count = 0;

    // For all current plans:
    while (_plans.size() > 0) {
      int level;
      auto p = _plans.pop_front(level);
      if (level == maxRuleLevel) {
        newPlans.push_back(p, level);  // nothing to do, just keep it
      }
      else {   // some rule needs applying
        Rule r("dummy", dummyRule, level);
        auto it = std::upper_bound(_rules.begin(), _rules.end(), r);
        TRI_ASSERT(it != _rules.end());
        std::cout << "Trying rule " << it->name << " (" << &(it->func) << ") with level "
                  << it->level << " on plan " << count++
                  << std::endl;
        try {
          res = it->func(this, p, it->level, newPlans);
        }
        catch (...) {
          delete p;
          throw;
        }
        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }
      }

      // TODO: abort early here if we found a good-enough plan
      // a good-enough plan is probably every plan with costs below some
      // defined threshold. this requires plan costs to be calculated here
    }
    _plans.steal(newPlans);
    leastDoneLevel = maxRuleLevel;
    for (auto l : _plans.levelDone) {
      if (l < leastDoneLevel) {
        leastDoneLevel = l;
      }
    }
    std::cout << "Least done level is " << leastDoneLevel << std::endl;

    // Stop if the result gets out of hand:
    if (_plans.size() >= maxNumberOfPlans) {
      break;
    }
  }

  estimatePlans();
  sortPlans();
  std::cout << "Optimisation ends with " << _plans.size() << " plans."
            << std::endl;
  for (auto p : _plans.list) {
    p->show();
    std::cout << "costing: " << p->getCost() << std::endl;
    std::cout << std::endl;
  }

  return TRI_ERROR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief estimatePlans
////////////////////////////////////////////////////////////////////////////////

void Optimizer::estimatePlans () {
  for (auto p : _plans.list) {
    p->getCost();
    // this value is cached in the plan, so formally this step is
    // unnecessary, but for the sake of cleanliness...
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief sortPlans
////////////////////////////////////////////////////////////////////////////////

void Optimizer::sortPlans () {
  std::sort(_plans.list.begin(), _plans.list.end(), [](ExecutionPlan* const& a, ExecutionPlan* const& b) -> bool {
    return a->getCost() < b->getCost();
  });
}

////////////////////////////////////////////////////////////////////////////////
/// @brief set up the optimizer rules once and forever
////////////////////////////////////////////////////////////////////////////////

void Optimizer::setupRules () {
  TRI_ASSERT(_rules.empty());

  // List all the rules in the system here:
  // lower level values mean earlier rule execution
  // if two rules have the same level value, they will be executed in declaration order

  //////////////////////////////////////////////////////////////////////////////
  // "Pass 1": moving nodes "up" (potentially outside loops):
  //           please use levels between 1 and 99 here
  //////////////////////////////////////////////////////////////////////////////

  // move calculations up the dependency chain (to pull them out of
  // inner loops etc.)
  registerRule("move-calculations-up", moveCalculationsUpRule, 10);

  // move filters up the dependency chain (to make result sets as small
  // as possible as early as possible)
  registerRule("move-filters-up", moveFiltersUpRule, 20);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 2": try to remove redundant or unnecessary nodes
  ///           use levels between 101 and 199 for this
  //////////////////////////////////////////////////////////////////////////////

  // remove filters from the query that are not necessary at all
  // filters that are always true will be removed entirely
  // filters that are always false will be replaced with a NoResults node
  registerRule("remove-unnecessary-filters", removeUnnecessaryFiltersRule, 110);

  // remove calculations that are never necessary
  registerRule("remove-unnecessary-calculations",
               removeUnnecessaryCalculationsRule, 120);

  // remove redundant sort blocks
  registerRule("remove-redundant-sorts", removeRedundantSorts, 130);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 3": interchange EnumerateCollection nodes in all possible ways
  ///           this is level 500, please never let new plans from higher
  ///           levels go back to this or lower levels!
  //////////////////////////////////////////////////////////////////////////////

  registerRule("interchangeAdjacentEnumerations",
               interchangeAdjacentEnumerations, 500);

  //////////////////////////////////////////////////////////////////////////////
  // "Pass 4": moving nodes "up" (potentially outside loops) (second try):
  //           please use levels between 501 and 599 here
  //////////////////////////////////////////////////////////////////////////////

  // move calculations up the dependency chain (to pull them out of
  // inner loops etc.)
  registerRule("move-calculations-up", moveCalculationsUpRule, 510);

  // move filters up the dependency chain (to make result sets as small
  // as possible as early as possible)
  registerRule("move-filters-up", moveFiltersUpRule, 520);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 5": try to remove redundant or unnecessary nodes (second try)
  ///           use levels between 601 and 699 for this
  //////////////////////////////////////////////////////////////////////////////

  // remove filters from the query that are not necessary at all
  // filters that are always true will be removed entirely
  // filters that are always false will be replaced with a NoResults node
  registerRule("remove-unnecessary-filters", removeUnnecessaryFiltersRule, 610);

  // remove calculations that are never necessary
  registerRule("remove-unnecessary-calculations",
               removeUnnecessaryCalculationsRule, 620);

  // remove redundant sort blocks
  registerRule("remove-redundant-sorts", removeRedundantSorts, 630);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 6": use indexes if possible for FILTER and/or SORT nodes
  ///           use levels between 701 and 799 for this
  //////////////////////////////////////////////////////////////////////////////

  // try to find a filter after an enumerate collection and find an index . . .
  registerRule("use-index-range", useIndexRange, 710);

  // try to find sort blocks which are superseeded by indexes
  registerRule("use-index-for-sort", useIndexForSort, 720);

  //////////////////////////////////////////////////////////////////////////////
  /// END OF OPTIMISATIONS
  //////////////////////////////////////////////////////////////////////////////

  // Now sort them by level:
  std::stable_sort(_rules.begin(), _rules.end());
}

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:

<commit_msg>disabled broken rules<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief infrastructure for query optimizer
///
/// @file arangod/Aql/Optimizer.cpp
///
/// DISCLAIMER
///
/// Copyright 2010-2014 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014, triagens GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "Aql/Optimizer.h"
#include "Aql/OptimizerRules.h"

using namespace triagens::aql;

// -----------------------------------------------------------------------------
// --SECTION--                                               the optimizer class
// -----------------------------------------------------------------------------

std::vector<Optimizer::Rule> Optimizer::_rules;

////////////////////////////////////////////////////////////////////////////////
// @brief constructor, this will initialize the rules database
////////////////////////////////////////////////////////////////////////////////

Optimizer::Optimizer () {
  if (_rules.empty()) {
    setupRules();
  }
}

////////////////////////////////////////////////////////////////////////////////
// @brief the actual optimization
////////////////////////////////////////////////////////////////////////////////

int Optimizer::createPlans (ExecutionPlan* plan) {
  int res;
  int leastDoneLevel = 0;
  int maxRuleLevel = _rules.back().level;

  // _plans contains the previous optimisation result
  _plans.clear();
  _plans.push_back(plan, 0);

  int pass = 1;
  while (leastDoneLevel < maxRuleLevel) {
    std::cout << "Entering pass " << pass << " of query optimization..."
              << std::endl;

    // This vector holds the plans we have created in this pass:
    PlanList newPlans;

    // Find variable usage for all old plans now:
    for (auto p : _plans.list) {
      if (! p->varUsageComputed()) {
        p->findVarUsage();
      }
    }

    std::cout << "Have " << _plans.size() << " plans:" << std::endl;

    for (auto p : _plans.list) {
      p->show();
      std::cout << std::endl;
    }

    int count = 0;

    // For all current plans:
    while (_plans.size() > 0) {
      int level;
      auto p = _plans.pop_front(level);
      if (level == maxRuleLevel) {
        newPlans.push_back(p, level);  // nothing to do, just keep it
      }
      else {   // some rule needs applying
        Rule r("dummy", dummyRule, level);
        auto it = std::upper_bound(_rules.begin(), _rules.end(), r);
        TRI_ASSERT(it != _rules.end());
        std::cout << "Trying rule " << it->name << " (" << &(it->func) << ") with level "
                  << it->level << " on plan " << count++
                  << std::endl;
        try {
          res = it->func(this, p, it->level, newPlans);
        }
        catch (...) {
          delete p;
          throw;
        }
        if (res != TRI_ERROR_NO_ERROR) {
          return res;
        }
      }

      // TODO: abort early here if we found a good-enough plan
      // a good-enough plan is probably every plan with costs below some
      // defined threshold. this requires plan costs to be calculated here
    }
    _plans.steal(newPlans);
    leastDoneLevel = maxRuleLevel;
    for (auto l : _plans.levelDone) {
      if (l < leastDoneLevel) {
        leastDoneLevel = l;
      }
    }
    std::cout << "Least done level is " << leastDoneLevel << std::endl;

    // Stop if the result gets out of hand:
    if (_plans.size() >= maxNumberOfPlans) {
      break;
    }
  }

  estimatePlans();
  sortPlans();
  std::cout << "Optimisation ends with " << _plans.size() << " plans."
            << std::endl;
  for (auto p : _plans.list) {
    p->show();
    std::cout << "costing: " << p->getCost() << std::endl;
    std::cout << std::endl;
  }

  return TRI_ERROR_NO_ERROR;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief estimatePlans
////////////////////////////////////////////////////////////////////////////////

void Optimizer::estimatePlans () {
  for (auto p : _plans.list) {
    p->getCost();
    // this value is cached in the plan, so formally this step is
    // unnecessary, but for the sake of cleanliness...
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief sortPlans
////////////////////////////////////////////////////////////////////////////////

void Optimizer::sortPlans () {
  std::sort(_plans.list.begin(), _plans.list.end(), [](ExecutionPlan* const& a, ExecutionPlan* const& b) -> bool {
    return a->getCost() < b->getCost();
  });
}

////////////////////////////////////////////////////////////////////////////////
/// @brief set up the optimizer rules once and forever
////////////////////////////////////////////////////////////////////////////////

void Optimizer::setupRules () {
  TRI_ASSERT(_rules.empty());

  // List all the rules in the system here:
  // lower level values mean earlier rule execution
  // if two rules have the same level value, they will be executed in declaration order

  //////////////////////////////////////////////////////////////////////////////
  // "Pass 1": moving nodes "up" (potentially outside loops):
  //           please use levels between 1 and 99 here
  //////////////////////////////////////////////////////////////////////////////

  // move calculations up the dependency chain (to pull them out of
  // inner loops etc.)
  registerRule("move-calculations-up", moveCalculationsUpRule, 10);

  // move filters up the dependency chain (to make result sets as small
  // as possible as early as possible)
  registerRule("move-filters-up", moveFiltersUpRule, 20);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 2": try to remove redundant or unnecessary nodes
  ///           use levels between 101 and 199 for this
  //////////////////////////////////////////////////////////////////////////////

  // remove filters from the query that are not necessary at all
  // filters that are always true will be removed entirely
  // filters that are always false will be replaced with a NoResults node
  registerRule("remove-unnecessary-filters", removeUnnecessaryFiltersRule, 110);

  // remove calculations that are never necessary
  registerRule("remove-unnecessary-calculations",
               removeUnnecessaryCalculationsRule, 120);

  // remove redundant sort blocks
  registerRule("remove-redundant-sorts", removeRedundantSorts, 130);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 3": interchange EnumerateCollection nodes in all possible ways
  ///           this is level 500, please never let new plans from higher
  ///           levels go back to this or lower levels!
  //////////////////////////////////////////////////////////////////////////////

  registerRule("interchangeAdjacentEnumerations",
               interchangeAdjacentEnumerations, 500);

  //////////////////////////////////////////////////////////////////////////////
  // "Pass 4": moving nodes "up" (potentially outside loops) (second try):
  //           please use levels between 501 and 599 here
  //////////////////////////////////////////////////////////////////////////////

  // move calculations up the dependency chain (to pull them out of
  // inner loops etc.)
  registerRule("move-calculations-up", moveCalculationsUpRule, 510);

  // move filters up the dependency chain (to make result sets as small
  // as possible as early as possible)
  registerRule("move-filters-up", moveFiltersUpRule, 520);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 5": try to remove redundant or unnecessary nodes (second try)
  ///           use levels between 601 and 699 for this
  //////////////////////////////////////////////////////////////////////////////

  // remove filters from the query that are not necessary at all
  // filters that are always true will be removed entirely
  // filters that are always false will be replaced with a NoResults node
  registerRule("remove-unnecessary-filters", removeUnnecessaryFiltersRule, 610);

  // remove calculations that are never necessary
  registerRule("remove-unnecessary-calculations",
               removeUnnecessaryCalculationsRule, 620);

  // remove redundant sort blocks
  registerRule("remove-redundant-sorts", removeRedundantSorts, 630);

  //////////////////////////////////////////////////////////////////////////////
  /// "Pass 6": use indexes if possible for FILTER and/or SORT nodes
  ///           use levels between 701 and 799 for this
  //////////////////////////////////////////////////////////////////////////////

  // try to find a filter after an enumerate collection and find an index . . .
  //registerRule("use-index-range", useIndexRange, 710);

  // try to find sort blocks which are superseeded by indexes
  //registerRule("use-index-for-sort", useIndexForSort, 720);

  //////////////////////////////////////////////////////////////////////////////
  /// END OF OPTIMISATIONS
  //////////////////////////////////////////////////////////////////////////////

  // Now sort them by level:
  std::stable_sort(_rules.begin(), _rules.end());
}

// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:

<|endoftext|>


<commit_before>
#include <iostream>

#include <chrono>
#include <random>

#include "matrix_connected_components/Algorithm.hpp"
#include "utils/containers/Matrix.hpp"

template <typename T>
struct StringRep {};

template <>
struct StringRep<uint64_t> {
  static constexpr std::string_view value{"uint64_t"};
};

template <>
struct StringRep<int64_t> {
  static constexpr std::string_view value{"int64_t"};
};

int main() {
  // using ValueType = uint64_t;
  // static constexpr int64_t width{6};
  // static constexpr int64_t height{5};
  // utils::containers::Matrix<ValueType> m{height, width, matrix_connected_components::kUnmarkedField<ValueType>};

  // std::vector<std::pair<int64_t, int64_t>> markedFields = {
  //     {0, 0}, {1, 0}, {1, 2}, {1, 3}, {2, 1}, {2, 3}, {3, 1}, {3, 2}, {3, 3}, {4, 4},
  // };

  // for (const auto &[row, column]: markedFields) {
  //   m.get(row, column) = matrix_connected_components::kMarkedField<ValueType>;
  // }
  // for (auto row = 0U; row < height; ++row) {
  //   for (auto column = 0U; column < width; ++column) {
  //     std::cout << static_cast<ValueType>(m.get(row, column)) << ' ';
  //   }
  //   std::cout << std::endl;
  // }
  // std::cout << std::endl;
  // matrix_connected_components::labelConnectedCompnents(m);
  // for (auto row = 0U; row < height; ++row) {
  //   for (auto column = 0U; column < width; ++column) {
  //     std::cout << static_cast<ValueType>(m.get(row, column)) << ' ';
  //   }
  //   std::cout << std::endl;
  // }

  static constexpr int64_t kDimension{20000};
  static constexpr int64_t kNumberOfFields{kDimension * kDimension};

  using ValueType = uint64_t;
  std::mt19937 mt(1); // NOLINTNEXTLINE(cert-msc32-c)
  std::uniform_int_distribution<int64_t> r1(0, kDimension - 1);
  utils::containers::Matrix<ValueType> matrix(kDimension, kDimension,
                                              matrix_connected_components::kUnmarkedField<ValueType>);

  static constexpr int64_t kIterations = kNumberOfFields / 5 * 2;
  for (auto i = 0; i < kIterations; ++i) {
    matrix.get(r1(mt), r1(mt)) = matrix_connected_components::kMarkedField<ValueType>;
  }

  std::cout << "Start " << StringRep<ValueType>::value << '\n';
  std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
  const auto components = matrix_connected_components::countConnectedComponents(std::move(matrix));
  std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
  std::cout << "Done, there are " << components << " components.\n";

  std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count()
            << "[ms]" << std::endl;

  return 0;
}
<commit_msg>Finalize demo<commit_after>#include <iostream>

#include "matrix_connected_components/Algorithm.hpp"
#include "utils/containers/Matrix.hpp"

int main() {
  using ValueType = uint8_t;
  static constexpr int64_t width{5};
  static constexpr int64_t height{5};
  utils::containers::Matrix<ValueType> m{height, width, matrix_connected_components::kUnmarkedField<ValueType>};

  std::vector<std::pair<int64_t, int64_t>> markedFields = {
      {0, 0}, {1, 0}, {1, 2}, {1, 3}, {2, 1}, {2, 3}, {3, 1}, {3, 2}, {3, 3}, {4, 4},
  };

  for (const auto &[row, column]: markedFields) {
    m.get(row, column) = matrix_connected_components::kMarkedField<ValueType>;
  }

  std::cout << "Matrix before running the algorithm: \n";

  for (auto row = 0U; row < height; ++row) {
    for (auto column = 0U; column < width; ++column) {
      std::cout << static_cast<int>(m.get(row, column)) << ' ';
    }
    std::cout << std::endl;
  }
  const auto numberOfConnectedComponents = matrix_connected_components::countConnectedComponents(m);
  std::cout << "Number of connected components: " << numberOfConnectedComponents << '\n';

  m = matrix_connected_components::labelConnectedComponents(std::move(m));

  std::cout << "Matrix after running the algorithm: \n";
  for (auto row = 0U; row < height; ++row) {
    for (auto column = 0U; column < width; ++column) {
      std::cout << static_cast<int>(m.get(row, column)) << ' ';
    }
    std::cout << std::endl;
  }

  return 0;
}
<|endoftext|>


<commit_before>#include "crv.h"

// Include <gtest/gtest.h> _after_ "crv.h"
#include "gtest/gtest.h"
#include <array>

TEST(CrvFunctionalTest, SafeIf)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  bool error = false;
  do
  {
    crv::External<char> x('A');
    if (crv::tracer().append_guard(x == '?'))
      x = 'B';
    crv::Internal<char> a(x);

    crv::tracer().add_error(!(a == 'B' || a == 'A'));

    if (!crv::tracer().errors().empty() &&
        smt::sat == encoder.check(crv::tracer()))
      error = true;
  }
  while (crv::tracer().flip());
  EXPECT_FALSE(error);
}

void fib_t0(
  const unsigned N,
  crv::External<int>& i,
  crv::External<int>& j)
{
  int k;
  for (k = 0; k < N; k++)
  {
    i = i + j;
  }
}

void fib_t1(
  const unsigned N,
  crv::External<int>& i,
  crv::External<int>& j)
{
  int k;
  for (k = 0; k < N; k++)
  {
    j = j + i;
  }
}

// Adapted from SV-COMP'13 benchmark:
//   https://svn.sosy-lab.org/software/sv-benchmarks/trunk/c/pthread/fib_bench_longer_true.c
TEST(CrvFunctionalTest, UnsatFib6)
{
  constexpr unsigned N = 6;

  crv::tracer().reset();
  crv::Encoder encoder;

  crv::External<int> i = 1, j = 1;
  crv::Thread t0(fib_t0, N, i, j);
  crv::Thread t1(fib_t1, N, i, j);

  crv::tracer().add_error(377 < i || 377 < j);

  t0.join();
  t1.join();

  EXPECT_TRUE(crv::tracer().assertions().empty());
  EXPECT_FALSE(crv::tracer().errors().empty());
  EXPECT_TRUE(smt::unsat == encoder.check(crv::tracer()));
  EXPECT_FALSE(crv::tracer().flip());
}

// Adapted from SV-COMP'13 benchmark:
//  https://svn.sosy-lab.org/software/sv-benchmarks/trunk/c/pthread/fib_bench_longer_false-unreach-label.c
TEST(CrvFunctionalTest, SatFib6)
{
  constexpr unsigned N = 6;

  crv::tracer().reset();
  crv::Encoder encoder;

  crv::External<int> i = 1, j = 1;
  crv::Thread t0(fib_t0, N, i, j);
  crv::Thread t1(fib_t1, N, i, j);

  crv::tracer().add_error(377 <= i || 377 <= j);

  t0.join();
  t1.join();

  EXPECT_TRUE(crv::tracer().assertions().empty());
  EXPECT_FALSE(crv::tracer().errors().empty());
  EXPECT_TRUE(smt::sat == encoder.check(crv::tracer()));
  EXPECT_FALSE(crv::tracer().flip());
}

void stateful_t0(
  crv::Mutex& mutex,
  crv::External<int>& i,
  crv::External<int>& j)
{
  mutex.lock();
  i = i + 1;
  mutex.unlock();

  mutex.lock();
  j = j + 1;
  mutex.unlock();
}

void stateful_t1(
  crv::Mutex& mutex,
  crv::External<int>& i,
  crv::External<int>& j)
{
  mutex.lock();
  i = i + 5;
  mutex.unlock();

  mutex.lock();
  j = j - 6;
  mutex.unlock();
}

// Adapted from SV-COMP'13 benchmark:
//  https://svn.sosy-lab.org/software/sv-benchmarks/trunk/c/pthread/stateful01_true.c
TEST(CrvFunctionalTest, UnsatStateful)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Mutex mutex;
  crv::External<int> i(10), j(10);

  bool error = false;
  do
  {
    crv::Thread t0(stateful_t0, mutex, i, j);
    crv::Thread t1(stateful_t1, mutex, i, j);

    t0.join();
    t1.join();

    crv::tracer().add_error(i != 16 || j != 5);

    if (!crv::tracer().errors().empty() &&
        smt::sat == encoder.check(crv::tracer()))
      error = true;
  }
  while (crv::tracer().flip());
  EXPECT_FALSE(error);
}

// Adapted from SV-COMP'13 benchmark:
//  https://svn.sosy-lab.org/software/sv-benchmarks/trunk/c/pthread/stateful01_false-unreach-label.c
TEST(CrvFunctionalTest, SatStateful)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Mutex mutex;
  crv::External<int> i(10), j(10);

  bool error = false;
  do
  {
    crv::Thread t0(stateful_t0, mutex, i, j);
    crv::Thread t1(stateful_t1, mutex, i, j);

    t0.join();
    t1.join();

    crv::tracer().add_error(i == 16 && j == 5);

    if (!crv::tracer().errors().empty() &&
        smt::sat == encoder.check(crv::tracer()))
      error = true;
  }
  while (crv::tracer().flip());
  EXPECT_TRUE(error);
}

void sat_stack_t0(
  const unsigned N,
  crv::Mutex& mutex,
  crv::External<unsigned int>& top,
  crv::External<int>& flag)
{
  int i;
  for (i = 0; i < N; i++)
  {
    mutex.lock();
    top = top + 1U;
    flag = 1;
    mutex.unlock();
  }
}

void sat_stack_t1(
const unsigned N,
  crv::Mutex& mutex,
  crv::External<unsigned int>& top,
  crv::External<int>& flag)
{
  int i;
  for (i = 0; i < N; i++)
  {
    mutex.lock();
    if (crv::tracer().append_guard(flag == 1))
    {
      crv::tracer().add_error(top == 0U);
      top = top - 1U;
    }
    mutex.unlock();
  }
}

TEST(CrvFunctionalTest, SatStack)
{
  constexpr unsigned N = 5;

  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Mutex mutex;
  crv::External<unsigned int> top(0U);
  crv::External<int> flag(0);

  bool error = false;
  do
  {
    crv::Thread t0(sat_stack_t0, N, mutex, top, flag);
    crv::Thread t1(sat_stack_t1, N, mutex, top, flag);

    if (!crv::tracer().errors().empty() &&
        smt::sat == encoder.check(crv::tracer()))
      error = true;
  }
  while (crv::tracer().flip());
  EXPECT_TRUE(error);
}

void unsat_stack_t0(
  const unsigned N,
  crv::Mutex& mutex,
  crv::External<unsigned int>& top)
{
  int i;
  for (i = 0; i < N; i++)
  {
    mutex.lock();
    top = top + 1U;
    mutex.unlock();
  }
}

void unsat_stack_t1(
  const unsigned N,
  crv::Mutex& mutex,
  crv::External<unsigned int>& top)
{
  int i;
  for (i = 0; i < N; i++)
  {
    mutex.lock();
    if (crv::tracer().append_guard(0U < top))
    {
      crv::tracer().add_error(top == 0U);
      top = top - 1U;
    }
    mutex.unlock();
  }
}

TEST(CrvFunctionalTest, UnsatStack)
{
  constexpr unsigned N = 5;

  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Mutex mutex;
  crv::External<unsigned int> top(0U);

  bool error = false;
  do
  {
    crv::Thread t0(unsat_stack_t0, N, mutex, top);
    crv::Thread t1(unsat_stack_t1, N, mutex, top);

    if (!crv::tracer().errors().empty() &&
        smt::sat == encoder.check(crv::tracer()))
      error = true;
  }
  while (crv::tracer().flip());
  EXPECT_FALSE(error);
}

void sat_communication_f(crv::Channel<int>& s, crv::Channel<int>& t)
{
  t.send(1);
  crv::Internal<int> r(s.recv());
  s.send(r);
}

void sat_communication_g(crv::Channel<int>& s, crv::Channel<int>& t)
{
  crv::Internal<int> r(t.recv());
  s.send(r);
}

void sat_communication_h(crv::Channel<int>& s)
{
  s.recv();
}

TEST(CrvFunctionalTest, SatCommunication)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Channel<int> s, t;
  crv::Thread f(sat_communication_f, s, t);
  crv::Thread g(sat_communication_g, s, t);
  crv::Thread h(sat_communication_h, s);

  EXPECT_TRUE(crv::tracer().errors().empty());
  EXPECT_EQ(smt::sat, encoder.check_deadlock(crv::tracer()));
}

void sat_communication_g_prime(crv::Channel<int>& s, crv::Channel<int>& t)
{
  crv::Internal<int> r(t.recv());
  s.send(r);
  s.recv();
}

TEST(CrvFunctionalTest, UnsatCommunication)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Channel<int> s, t;
  crv::Thread f(sat_communication_f, s, t);
  crv::Thread g_prime(sat_communication_g_prime, s, t);

  EXPECT_TRUE(crv::tracer().errors().empty());
  EXPECT_EQ(smt::unsat, encoder.check_deadlock(crv::tracer()));
}

void unsat_communication_deadlock_with_guard_f(crv::Channel<int>& c)
{
  EXPECT_TRUE(crv::tracer().append_guard(6 == c.recv()));
  c.send(7);
}

void unsat_communication_deadlock_with_guard_g(crv::Channel<int>& c)
{
  c.send(6);
  c.recv();
}

TEST(CrvFunctionalTest, UnsatCommunicationDeadlockWithGuard)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Channel<int> c;
  crv::Thread f(unsat_communication_deadlock_with_guard_f, c);
  crv::Thread g(unsat_communication_deadlock_with_guard_g, c);

  EXPECT_EQ(smt::unsat, encoder.check_deadlock(crv::tracer()));
}

void sat_communication_deadlock_with_guard_f(crv::Channel<int>& c)
{
  EXPECT_TRUE(crv::tracer().append_guard(6 != c.recv()));
  c.send(7);
}

void sat_communication_deadlock_with_guard_g(crv::Channel<int>& c)
{
  c.send(6);
  c.recv();
}

TEST(CrvFunctionalTest, SatCommunicationDeadlockWithGuard)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Channel<int> c;
  crv::Thread f(sat_communication_deadlock_with_guard_f, c);
  crv::Thread g(sat_communication_deadlock_with_guard_g, c);

  EXPECT_EQ(smt::sat, encoder.check_deadlock(crv::tracer()));
}

// N is the number of philosophers
template<size_t N>
struct DiningTable
{
  std::array<crv::Channel<int>, N> picksup;
  std::array<crv::Channel<int>, N> putsdown;
};

// Allow fork to be used twice
template<size_t N>
void phil_fork(size_t i, DiningTable<N>& t)
{
  t.picksup.at(i).recv();
  t.putsdown.at(i).recv();
  t.picksup.at(i).recv();
  t.putsdown.at(i).recv();
}

// Picks up left and then right fork;
// finally, puts down both forks
template<size_t N>
void phil_person(size_t i, DiningTable<N>& t)
{
  t.picksup.at(i).send(i);
  t.picksup.at((i + 1) % N).send(i);
  t.putsdown.at(i).send(i);
  t.putsdown.at((i + 1) % N).send(i);
}

// Picks up right fork then left fork;
// finally, puts down both forks
template<size_t N>
void phil_different_person(size_t i, DiningTable<N>& t)
{
  t.picksup.at((i + 1) % N).send(i);
  t.picksup.at(i).send(i);
  t.putsdown.at(i).send(i);
  t.putsdown.at((i + 1) % N).send(i);
}

TEST(CrvFunctionalTest, UnsatDiningPhilosophersDeadlock)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  constexpr size_t N = 5;
  DiningTable<N> t;

  for (int i = 0; i < N; i++)
  {
    crv::Thread fork(phil_fork<N>, i, t);

    if (i == 0)
      crv::Thread person(phil_different_person<N>, i, t);
    else
      crv::Thread person(phil_person<N>, i, t);
  }

  EXPECT_EQ(smt::unsat, encoder.check_deadlock(crv::tracer()));
}

TEST(CrvFunctionalTest, SatDiningPhilosophersDeadlock)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  constexpr size_t N = 2;
  DiningTable<N> t;

  for (int i = 0; i < N; i++)
  {
    crv::Thread fork(phil_fork<N>, i, t);
    crv::Thread person(phil_person<N>, i, t);
  }

  EXPECT_EQ(smt::sat, encoder.check_deadlock(crv::tracer()));
}

<commit_msg>Add CSP code of the dining philosophers problem<commit_after>#include "crv.h"

// Include <gtest/gtest.h> _after_ "crv.h"
#include "gtest/gtest.h"
#include <array>

TEST(CrvFunctionalTest, SafeIf)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  bool error = false;
  do
  {
    crv::External<char> x('A');
    if (crv::tracer().append_guard(x == '?'))
      x = 'B';
    crv::Internal<char> a(x);

    crv::tracer().add_error(!(a == 'B' || a == 'A'));

    if (!crv::tracer().errors().empty() &&
        smt::sat == encoder.check(crv::tracer()))
      error = true;
  }
  while (crv::tracer().flip());
  EXPECT_FALSE(error);
}

void fib_t0(
  const unsigned N,
  crv::External<int>& i,
  crv::External<int>& j)
{
  int k;
  for (k = 0; k < N; k++)
  {
    i = i + j;
  }
}

void fib_t1(
  const unsigned N,
  crv::External<int>& i,
  crv::External<int>& j)
{
  int k;
  for (k = 0; k < N; k++)
  {
    j = j + i;
  }
}

// Adapted from SV-COMP'13 benchmark:
//   https://svn.sosy-lab.org/software/sv-benchmarks/trunk/c/pthread/fib_bench_longer_true.c
TEST(CrvFunctionalTest, UnsatFib6)
{
  constexpr unsigned N = 6;

  crv::tracer().reset();
  crv::Encoder encoder;

  crv::External<int> i = 1, j = 1;
  crv::Thread t0(fib_t0, N, i, j);
  crv::Thread t1(fib_t1, N, i, j);

  crv::tracer().add_error(377 < i || 377 < j);

  t0.join();
  t1.join();

  EXPECT_TRUE(crv::tracer().assertions().empty());
  EXPECT_FALSE(crv::tracer().errors().empty());
  EXPECT_TRUE(smt::unsat == encoder.check(crv::tracer()));
  EXPECT_FALSE(crv::tracer().flip());
}

// Adapted from SV-COMP'13 benchmark:
//  https://svn.sosy-lab.org/software/sv-benchmarks/trunk/c/pthread/fib_bench_longer_false-unreach-label.c
TEST(CrvFunctionalTest, SatFib6)
{
  constexpr unsigned N = 6;

  crv::tracer().reset();
  crv::Encoder encoder;

  crv::External<int> i = 1, j = 1;
  crv::Thread t0(fib_t0, N, i, j);
  crv::Thread t1(fib_t1, N, i, j);

  crv::tracer().add_error(377 <= i || 377 <= j);

  t0.join();
  t1.join();

  EXPECT_TRUE(crv::tracer().assertions().empty());
  EXPECT_FALSE(crv::tracer().errors().empty());
  EXPECT_TRUE(smt::sat == encoder.check(crv::tracer()));
  EXPECT_FALSE(crv::tracer().flip());
}

void stateful_t0(
  crv::Mutex& mutex,
  crv::External<int>& i,
  crv::External<int>& j)
{
  mutex.lock();
  i = i + 1;
  mutex.unlock();

  mutex.lock();
  j = j + 1;
  mutex.unlock();
}

void stateful_t1(
  crv::Mutex& mutex,
  crv::External<int>& i,
  crv::External<int>& j)
{
  mutex.lock();
  i = i + 5;
  mutex.unlock();

  mutex.lock();
  j = j - 6;
  mutex.unlock();
}

// Adapted from SV-COMP'13 benchmark:
//  https://svn.sosy-lab.org/software/sv-benchmarks/trunk/c/pthread/stateful01_true.c
TEST(CrvFunctionalTest, UnsatStateful)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Mutex mutex;
  crv::External<int> i(10), j(10);

  bool error = false;
  do
  {
    crv::Thread t0(stateful_t0, mutex, i, j);
    crv::Thread t1(stateful_t1, mutex, i, j);

    t0.join();
    t1.join();

    crv::tracer().add_error(i != 16 || j != 5);

    if (!crv::tracer().errors().empty() &&
        smt::sat == encoder.check(crv::tracer()))
      error = true;
  }
  while (crv::tracer().flip());
  EXPECT_FALSE(error);
}

// Adapted from SV-COMP'13 benchmark:
//  https://svn.sosy-lab.org/software/sv-benchmarks/trunk/c/pthread/stateful01_false-unreach-label.c
TEST(CrvFunctionalTest, SatStateful)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Mutex mutex;
  crv::External<int> i(10), j(10);

  bool error = false;
  do
  {
    crv::Thread t0(stateful_t0, mutex, i, j);
    crv::Thread t1(stateful_t1, mutex, i, j);

    t0.join();
    t1.join();

    crv::tracer().add_error(i == 16 && j == 5);

    if (!crv::tracer().errors().empty() &&
        smt::sat == encoder.check(crv::tracer()))
      error = true;
  }
  while (crv::tracer().flip());
  EXPECT_TRUE(error);
}

void sat_stack_t0(
  const unsigned N,
  crv::Mutex& mutex,
  crv::External<unsigned int>& top,
  crv::External<int>& flag)
{
  int i;
  for (i = 0; i < N; i++)
  {
    mutex.lock();
    top = top + 1U;
    flag = 1;
    mutex.unlock();
  }
}

void sat_stack_t1(
const unsigned N,
  crv::Mutex& mutex,
  crv::External<unsigned int>& top,
  crv::External<int>& flag)
{
  int i;
  for (i = 0; i < N; i++)
  {
    mutex.lock();
    if (crv::tracer().append_guard(flag == 1))
    {
      crv::tracer().add_error(top == 0U);
      top = top - 1U;
    }
    mutex.unlock();
  }
}

TEST(CrvFunctionalTest, SatStack)
{
  constexpr unsigned N = 5;

  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Mutex mutex;
  crv::External<unsigned int> top(0U);
  crv::External<int> flag(0);

  bool error = false;
  do
  {
    crv::Thread t0(sat_stack_t0, N, mutex, top, flag);
    crv::Thread t1(sat_stack_t1, N, mutex, top, flag);

    if (!crv::tracer().errors().empty() &&
        smt::sat == encoder.check(crv::tracer()))
      error = true;
  }
  while (crv::tracer().flip());
  EXPECT_TRUE(error);
}

void unsat_stack_t0(
  const unsigned N,
  crv::Mutex& mutex,
  crv::External<unsigned int>& top)
{
  int i;
  for (i = 0; i < N; i++)
  {
    mutex.lock();
    top = top + 1U;
    mutex.unlock();
  }
}

void unsat_stack_t1(
  const unsigned N,
  crv::Mutex& mutex,
  crv::External<unsigned int>& top)
{
  int i;
  for (i = 0; i < N; i++)
  {
    mutex.lock();
    if (crv::tracer().append_guard(0U < top))
    {
      crv::tracer().add_error(top == 0U);
      top = top - 1U;
    }
    mutex.unlock();
  }
}

TEST(CrvFunctionalTest, UnsatStack)
{
  constexpr unsigned N = 5;

  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Mutex mutex;
  crv::External<unsigned int> top(0U);

  bool error = false;
  do
  {
    crv::Thread t0(unsat_stack_t0, N, mutex, top);
    crv::Thread t1(unsat_stack_t1, N, mutex, top);

    if (!crv::tracer().errors().empty() &&
        smt::sat == encoder.check(crv::tracer()))
      error = true;
  }
  while (crv::tracer().flip());
  EXPECT_FALSE(error);
}

void sat_communication_f(crv::Channel<int>& s, crv::Channel<int>& t)
{
  t.send(1);
  crv::Internal<int> r(s.recv());
  s.send(r);
}

void sat_communication_g(crv::Channel<int>& s, crv::Channel<int>& t)
{
  crv::Internal<int> r(t.recv());
  s.send(r);
}

void sat_communication_h(crv::Channel<int>& s)
{
  s.recv();
}

TEST(CrvFunctionalTest, SatCommunication)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Channel<int> s, t;
  crv::Thread f(sat_communication_f, s, t);
  crv::Thread g(sat_communication_g, s, t);
  crv::Thread h(sat_communication_h, s);

  EXPECT_TRUE(crv::tracer().errors().empty());
  EXPECT_EQ(smt::sat, encoder.check_deadlock(crv::tracer()));
}

void sat_communication_g_prime(crv::Channel<int>& s, crv::Channel<int>& t)
{
  crv::Internal<int> r(t.recv());
  s.send(r);
  s.recv();
}

TEST(CrvFunctionalTest, UnsatCommunication)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Channel<int> s, t;
  crv::Thread f(sat_communication_f, s, t);
  crv::Thread g_prime(sat_communication_g_prime, s, t);

  EXPECT_TRUE(crv::tracer().errors().empty());
  EXPECT_EQ(smt::unsat, encoder.check_deadlock(crv::tracer()));
}

void unsat_communication_deadlock_with_guard_f(crv::Channel<int>& c)
{
  EXPECT_TRUE(crv::tracer().append_guard(6 == c.recv()));
  c.send(7);
}

void unsat_communication_deadlock_with_guard_g(crv::Channel<int>& c)
{
  c.send(6);
  c.recv();
}

TEST(CrvFunctionalTest, UnsatCommunicationDeadlockWithGuard)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Channel<int> c;
  crv::Thread f(unsat_communication_deadlock_with_guard_f, c);
  crv::Thread g(unsat_communication_deadlock_with_guard_g, c);

  EXPECT_EQ(smt::unsat, encoder.check_deadlock(crv::tracer()));
}

void sat_communication_deadlock_with_guard_f(crv::Channel<int>& c)
{
  EXPECT_TRUE(crv::tracer().append_guard(6 != c.recv()));
  c.send(7);
}

void sat_communication_deadlock_with_guard_g(crv::Channel<int>& c)
{
  c.send(6);
  c.recv();
}

TEST(CrvFunctionalTest, SatCommunicationDeadlockWithGuard)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  crv::Channel<int> c;
  crv::Thread f(sat_communication_deadlock_with_guard_f, c);
  crv::Thread g(sat_communication_deadlock_with_guard_g, c);

  EXPECT_EQ(smt::sat, encoder.check_deadlock(crv::tracer()));
}

// N is the number of philosophers

// For comparison, the equivalent CSP code of
// {Sat,Unsat}DiningPhilosophersDeadlock:
//
// N = 5
//
// FORK_ID = {0..N-1}
// PHIL_ID = {0..N-1}
//
// channel picksup, putsdown:FORK_ID.PHIL_ID
//
// PHIL(i) = picksup!i!i -> picksup!((i+1)%N)!i ->
//   putsdown!((i+1)%N)!i -> putsdown!i!i -> PHIL(i)
//
// FORK(i) = picksup!i?j -> putsdown!i!j -> FORK(i)
//
// PHILS = ||| i:PHIL_ID@ PHIL(i)
// FORKS = ||| i:FORK_ID@ FORK(i)
//
// SAT_SYSTEM = PHILS[|{|picksup, putsdown|}|]FORKS
// assert SAT_SYSTEM :[deadlock free [F]]
//
// LPHIL(i) = picksup!((i+1)%N)!i -> picksup!i!i ->
//   putsdown!((i+1)%N)!i -> putsdown!i!i -> LPHIL(i)
//
// PHILS' = ||| i:PHIL_ID @ if i==0 then LPHIL(0) else PHIL(i)
//
// UNSAT_SYSTEM = PHILS'[|{|picksup, putsdown|}|]FORKS
// assert UNSAT_SYSTEM :[deadlock free [F]]
template<size_t N>
struct DiningTable
{
  std::array<crv::Channel<int>, N> picksup;
  std::array<crv::Channel<int>, N> putsdown;
};

// Allow fork to be used twice, so it can be picked up and put
// down by the person to the fork's right and left
template<size_t N>
void phil_fork(size_t i, DiningTable<N>& t)
{
  t.picksup.at(i).recv();
  t.putsdown.at(i).recv();
  t.picksup.at(i).recv();
  t.putsdown.at(i).recv();
}

// Picks up left and then right fork;
// finally, puts down both forks
template<size_t N>
void phil_person(size_t i, DiningTable<N>& t)
{
  t.picksup.at(i).send(i);
  t.picksup.at((i + 1) % N).send(i);
  t.putsdown.at(i).send(i);
  t.putsdown.at((i + 1) % N).send(i);
}

// Picks up right fork then left fork;
// finally, puts down both forks
template<size_t N>
void phil_different_person(size_t i, DiningTable<N>& t)
{
  t.picksup.at((i + 1) % N).send(i);
  t.picksup.at(i).send(i);
  t.putsdown.at(i).send(i);
  t.putsdown.at((i + 1) % N).send(i);
}

TEST(CrvFunctionalTest, UnsatDiningPhilosophersDeadlock)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  constexpr size_t N = 5;
  DiningTable<N> t;

  for (int i = 0; i < N; i++)
  {
    crv::Thread fork(phil_fork<N>, i, t);

    if (i == 0)
      crv::Thread person(phil_different_person<N>, i, t);
    else
      crv::Thread person(phil_person<N>, i, t);
  }

  EXPECT_EQ(smt::unsat, encoder.check_deadlock(crv::tracer()));
}

TEST(CrvFunctionalTest, SatDiningPhilosophersDeadlock)
{
  crv::tracer().reset();
  crv::Encoder encoder;

  constexpr size_t N = 2;
  DiningTable<N> t;

  for (int i = 0; i < N; i++)
  {
    crv::Thread fork(phil_fork<N>, i, t);
    crv::Thread person(phil_person<N>, i, t);
  }

  EXPECT_EQ(smt::sat, encoder.check_deadlock(crv::tracer()));
}

<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen 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.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/Eigenvalues>
#include <Eigen/LU>

/* Check that two column vectors are approximately equal upto permutations,
   by checking that the k-th power sums are equal for k = 1, ..., vec1.rows() */
template<typename VectorType>
void verify_is_approx_upto_permutation(const VectorType& vec1, const VectorType& vec2)
{
  VERIFY(vec1.cols() == 1);
  VERIFY(vec2.cols() == 1);
  VERIFY(vec1.rows() == vec2.rows());
  for (int k = 1; k <= vec1.rows(); ++k)
  {
    VERIFY_IS_APPROX(vec1.array().pow(k).sum(), vec2.array().pow(k).sum());
  }
}

template<typename MatrixType> void eigensolver(const MatrixType& m)
{
  /* this test covers the following files:
     ComplexEigenSolver.h, and indirectly ComplexSchur.h
  */
  int rows = m.rows();
  int cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
  typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
  typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;

  MatrixType a = MatrixType::Random(rows,cols);
  MatrixType symmA =  a.adjoint() * a;

  ComplexEigenSolver<MatrixType> ei0(symmA);
  VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal());

  ComplexEigenSolver<MatrixType> ei1(a);
  VERIFY_IS_APPROX(a * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal());
  // Note: If MatrixType is real then a.eigenvalues() uses EigenSolver and thus
  // another algorithm so results may differ slightly
  verify_is_approx_upto_permutation(a.eigenvalues(), ei1.eigenvalues());

  // Regression test for issue #66
  MatrixType z = MatrixType::Zero(rows,cols);
  ComplexEigenSolver<MatrixType> eiz(z);
  VERIFY((eiz.eigenvalues().cwiseEqual(0)).all());

  MatrixType id = MatrixType::Identity(rows, cols);
  VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1));
}

template<typename MatrixType> void eigensolver_verify_assert()
{
  ComplexEigenSolver<MatrixType> eig;
  VERIFY_RAISES_ASSERT(eig.eigenvectors())
  VERIFY_RAISES_ASSERT(eig.eigenvalues())
}

void test_eigensolver_complex()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( eigensolver(Matrix4cf()) );
    CALL_SUBTEST_2( eigensolver(MatrixXcd(14,14)) );
    CALL_SUBTEST_3( eigensolver(Matrix<std::complex<float>, 1, 1>()) );
    CALL_SUBTEST_4( eigensolver(Matrix3f()) );
  }

  CALL_SUBTEST_1( eigensolver_verify_assert(Matrix4cf()) );
  CALL_SUBTEST_2( eigensolver_verify_assert(MatrixXcd(14,14)) );
  CALL_SUBTEST_3( eigensolver_verify_assert(Matrix<std::complex<float>, 1, 1>()) );
  CALL_SUBTEST_4( eigensolver_verify_assert(Matrix3f()) );

  // Test problem size constructors
  CALL_SUBTEST_5(ComplexEigenSolver<MatrixXf>(10));
}
<commit_msg>Fix stupid compilation error in test.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen 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.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/Eigenvalues>
#include <Eigen/LU>

/* Check that two column vectors are approximately equal upto permutations,
   by checking that the k-th power sums are equal for k = 1, ..., vec1.rows() */
template<typename VectorType>
void verify_is_approx_upto_permutation(const VectorType& vec1, const VectorType& vec2)
{
  VERIFY(vec1.cols() == 1);
  VERIFY(vec2.cols() == 1);
  VERIFY(vec1.rows() == vec2.rows());
  for (int k = 1; k <= vec1.rows(); ++k)
  {
    VERIFY_IS_APPROX(vec1.array().pow(k).sum(), vec2.array().pow(k).sum());
  }
}

template<typename MatrixType> void eigensolver(const MatrixType& m)
{
  /* this test covers the following files:
     ComplexEigenSolver.h, and indirectly ComplexSchur.h
  */
  int rows = m.rows();
  int cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
  typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
  typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;

  MatrixType a = MatrixType::Random(rows,cols);
  MatrixType symmA =  a.adjoint() * a;

  ComplexEigenSolver<MatrixType> ei0(symmA);
  VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal());

  ComplexEigenSolver<MatrixType> ei1(a);
  VERIFY_IS_APPROX(a * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal());
  // Note: If MatrixType is real then a.eigenvalues() uses EigenSolver and thus
  // another algorithm so results may differ slightly
  verify_is_approx_upto_permutation(a.eigenvalues(), ei1.eigenvalues());

  // Regression test for issue #66
  MatrixType z = MatrixType::Zero(rows,cols);
  ComplexEigenSolver<MatrixType> eiz(z);
  VERIFY((eiz.eigenvalues().cwiseEqual(0)).all());

  MatrixType id = MatrixType::Identity(rows, cols);
  VERIFY_IS_APPROX(id.operatorNorm(), RealScalar(1));
}

template<typename MatrixType> void eigensolver_verify_assert()
{
  ComplexEigenSolver<MatrixType> eig;
  VERIFY_RAISES_ASSERT(eig.eigenvectors())
  VERIFY_RAISES_ASSERT(eig.eigenvalues())
}

void test_eigensolver_complex()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( eigensolver(Matrix4cf()) );
    CALL_SUBTEST_2( eigensolver(MatrixXcd(14,14)) );
    CALL_SUBTEST_3( eigensolver(Matrix<std::complex<float>, 1, 1>()) );
    CALL_SUBTEST_4( eigensolver(Matrix3f()) );
  }

  CALL_SUBTEST_1( eigensolver_verify_assert<Matrix4cf>() );
  CALL_SUBTEST_2( eigensolver_verify_assert<MatrixXcd>() );
  CALL_SUBTEST_3(( eigensolver_verify_assert<Matrix<std::complex<float>, 1, 1> >() ));
  CALL_SUBTEST_4( eigensolver_verify_assert<Matrix3f>() );

  // Test problem size constructors
  CALL_SUBTEST_5(ComplexEigenSolver<MatrixXf>(10));
}
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen 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.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/Eigenvalues>
#include <Eigen/LU>

template<typename MatrixType> void eigensolver(const MatrixType& m)
{
  /* this test covers the following files:
     ComplexEigenSolver.h, and indirectly ComplexSchur.h
  */
  int rows = m.rows();
  int cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
  typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
  typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;

  MatrixType a = MatrixType::Random(rows,cols);
  MatrixType symmA =  a.adjoint() * a;

  ComplexEigenSolver<MatrixType> ei0(symmA);
  VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal());

  ComplexEigenSolver<MatrixType> ei1(a);
  VERIFY_IS_APPROX(a * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal());

}

void test_eigensolver_complex()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST( eigensolver(Matrix4cf()) );
    CALL_SUBTEST( eigensolver(MatrixXcd(14,14)) );
  }
}

<commit_msg>Add regression test for issue #66 (ComplexSchur of zero matrix).<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008-2009 Gael Guennebaud <g.gael@free.fr>
//
// Eigen 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.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <Eigen/Eigenvalues>
#include <Eigen/LU>

template<typename MatrixType> void eigensolver(const MatrixType& m)
{
  /* this test covers the following files:
     ComplexEigenSolver.h, and indirectly ComplexSchur.h
  */
  int rows = m.rows();
  int cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
  typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, 1> RealVectorType;
  typedef typename std::complex<typename NumTraits<typename MatrixType::Scalar>::Real> Complex;

  MatrixType a = MatrixType::Random(rows,cols);
  MatrixType symmA =  a.adjoint() * a;

  ComplexEigenSolver<MatrixType> ei0(symmA);
  VERIFY_IS_APPROX(symmA * ei0.eigenvectors(), ei0.eigenvectors() * ei0.eigenvalues().asDiagonal());

  ComplexEigenSolver<MatrixType> ei1(a);
  VERIFY_IS_APPROX(a * ei1.eigenvectors(), ei1.eigenvectors() * ei1.eigenvalues().asDiagonal());

  // Regression test for issue #66
  MatrixType z = MatrixType::Zero(rows,cols);
  ComplexEigenSolver<MatrixType> eiz(z);
  VERIFY((eiz.eigenvalues().cwise()==0).all());
}

void test_eigensolver_complex()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST( eigensolver(Matrix4cf()) );
    CALL_SUBTEST( eigensolver(MatrixXcd(14,14)) );
  }
}
<|endoftext|>