Click here to Skip to main content
15,891,136 members
Articles / Programming Languages / C++

Combinations in C++, Part 2

Rate me:
Please Sign up or sign in to vote.
4.81/5 (30 votes)
12 Apr 2016CPOL15 min read 103.1K   2.3K   50  
Introduce 4 new algorithms on finding combinations
// TimeCombinationsDlg.cpp : implementation file
//

#include "stdafx.h"
#include "TimeCombinations.h"
#include "TimeCombinationsDlg.h"

#include "FindCombByIdx.h"
#include "FindTotalComb.h"
#include "IndexCombination.h"

#include <mmsystem.h>
#include <vector>

#include "BigIntegerLibrary.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif

UINT IndividualThreadProc( LPVOID pParam );

UINT MainThreadProc( LPVOID pParam );

struct StartEndIndexes
{
	// Constructor
	StartEndIndexes() : 
		nSet(1), 
		nComb(1), 
		biStart(1), 
		biEnd(1),
		hEvtDone(INVALID_HANDLE_VALUE) 
		{}

	int nSet;
	int nComb;
	BigInteger biStart;
	BigInteger biEnd;
	HANDLE hEvtDone;
};

struct MainStruct
{
	// Constructor
	MainStruct() :
		nSet(1),
		nComb(1),
		nTimes(1),
		nNumberOfThreads(1),
		nDuration(0)
		{}

	UINT nSet;
	UINT nComb;
	UINT nTimes;
	UINT nNumberOfThreads;
	UINT nDuration;
};



// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CTimeCombinationsDlg dialog




CTimeCombinationsDlg::CTimeCombinationsDlg(CWnd* pParent /*=NULL*/)
: 
m_nNumberOfProcessors(1),
m_nUseNumThread(1),
m_nR(1),
m_nN(1),
m_nTimes(1),
CDialog(CTimeCombinationsDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CTimeCombinationsDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_CHK_CPUS, m_chkCpus);
	DDX_Control(pDX, IDC_EDT_R, m_edtR);
	DDX_Control(pDX, IDC_EDT_N, m_edtN);
	DDX_Control(pDX, IDC_EDT_NUMTHREADS, m_edtNumThreads);
	DDX_Control(pDX, IDC_STATIC_NUMTHREADS, m_staticNumThreads);
	DDX_Control(pDX, IDC_EDT_NUMTIMES, m_edtNumTimes);
	DDX_Control(pDX, IDC_FIND, m_btnFind);
}

BEGIN_MESSAGE_MAP(CTimeCombinationsDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_CHK_CPUS, &CTimeCombinationsDlg::OnBnClickedChkCpus)
	ON_BN_DOUBLECLICKED(IDC_CHK_CPUS, &CTimeCombinationsDlg::OnBnDoubleclickedChkCpus)
	ON_BN_CLICKED(IDC_FIND, &CTimeCombinationsDlg::OnBnClickedFind)
	ON_MESSAGE(WM_DONE, OnTaskDone)
END_MESSAGE_MAP()


// CTimeCombinationsDlg message handlers

BOOL CTimeCombinationsDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	m_chkCpus.SetCheck(1);
	m_edtNumThreads.EnableWindow( FALSE );
	m_staticNumThreads.EnableWindow( FALSE );

	// Get number of processor information
	SYSTEM_INFO si;
	memset( &si, 0, sizeof(si) );
	GetSystemInfo( &si );

	m_nNumberOfProcessors = si.dwNumberOfProcessors;

	CString str;
	str.Format( L"%d", m_nNumberOfProcessors );
	m_edtNumThreads.SetWindowTextW(str);

	str.Format( L"%d", m_nTimes );
	m_edtNumTimes.SetWindowTextW(str);


	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CTimeCombinationsDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CTimeCombinationsDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CTimeCombinationsDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CTimeCombinationsDlg::OnBnClickedChkCpus()
{
	int nChecked = m_chkCpus.GetCheck();

	if( nChecked )
	{
		m_edtNumThreads.EnableWindow( FALSE );
		m_staticNumThreads.EnableWindow( FALSE );
	}
	else
	{
		m_edtNumThreads.EnableWindow( TRUE );
		m_staticNumThreads.EnableWindow( TRUE );
	}
	
}

void CTimeCombinationsDlg::OnBnDoubleclickedChkCpus()
{
	int nChecked = m_chkCpus.GetCheck();

	if( nChecked )
	{
		m_edtNumThreads.EnableWindow( FALSE );
		m_staticNumThreads.EnableWindow( FALSE );
	}
	else
	{
		m_edtNumThreads.EnableWindow( TRUE );
		m_staticNumThreads.EnableWindow( TRUE );
	}
	
}

bool CTimeCombinationsDlg::VerifyInput()
{
	CString szR;
	m_edtR.GetWindowText( szR );

	if( szR.IsEmpty() )
	{
		MessageBox( _T("The number of R elements is empty!") );
		return false;
	}

	m_nR = _ttoi( szR );


	CString szN;
	m_edtN.GetWindowText( szN );

	if( szN.IsEmpty() )
	{
		MessageBox( _T("The number of N elements is empty!") );
		return false;
	}

	m_nN = _ttoi( szN );

	if( m_nR > m_nN )
	{
		MessageBox( _T("The number of R elements is greater than the N elements!") );
		return false;
	}

	CString szTimes;
	m_edtNumTimes.GetWindowText( szTimes );

	if( szTimes.IsEmpty() )
	{
		MessageBox( _T("The number of times to run, is empty!") );
		return false;
	}

	m_nTimes = _ttoi( szTimes );

	if( m_nTimes == 0 )
	{
		MessageBox( _T("The number of times to loop is zero or less!") );
		return false;
	}

	if( 0 == m_chkCpus.GetCheck() )
	{
		CString szNumThreads;
		m_edtNumThreads.GetWindowText( szNumThreads );

		m_nUseNumThread = _ttoi( szNumThreads );

		if( m_nUseNumThread == 0 )
		{
			MessageBox( L"Invalid number of threads to use!", L"Error" );
			return false;
		}
	}
	else
	{
		m_nUseNumThread = m_nNumberOfProcessors;
	}

	BigInteger biTotalComb(1);

	CFindTotalComb< BigInteger > ftc(1);
	ftc.Init();
	ftc.FindTotalComb( m_nN, m_nR );
	biTotalComb = ftc.GetResult();
	ftc.Destroy();

	const size_t bufsize = 10000;
	char buf[bufsize];
	memset(buf,0,sizeof(buf));
	std::ostrstream oostream( buf, bufsize );
	oostream<<biTotalComb;

	wchar_t wbuf[bufsize];
	memset(wbuf,0,sizeof(wbuf));
	size_t nConvertedChars = 0;
	mbstowcs_s(
	   &nConvertedChars,
	   wbuf,
	   bufsize,
	   buf,
	   _TRUNCATE );

	szTotalComb = wbuf;

	//szTotalComb = szTotalComb.Left(szTotalComb.GetLength()-1);

	CString str;
	str.Format( L"Total number of combinations to be generated is %s\n Do you want to continue?", wbuf);

	if( IDOK == MessageBox( str, L"Confirmation", MB_OKCANCEL ) )
		return true;

	return false;
}

void CTimeCombinationsDlg::OnBnClickedFind()
{
	if( false == VerifyInput() )
		return;

	MainStruct* pMainStruct = new MainStruct();
	pMainStruct->nComb = m_nR;
	pMainStruct->nSet = m_nN;
	pMainStruct->nNumberOfThreads = m_nUseNumThread;
	pMainStruct->nTimes = m_nTimes;

	EnableCtrls(FALSE);
	
	AfxBeginThread( MainThreadProc, pMainStruct );
}

void CTimeCombinationsDlg::EnableCtrls(BOOL bEnable)
{
	m_btnFind.EnableWindow(bEnable);
	m_chkCpus.EnableWindow(bEnable);
	m_edtR.EnableWindow(bEnable);
	m_edtN.EnableWindow(bEnable);
	m_edtNumThreads.EnableWindow(bEnable);
	m_staticNumThreads.EnableWindow(bEnable);
	m_edtNumTimes.EnableWindow(bEnable);

	if( bEnable )
	{
		if( 0 == m_chkCpus.GetCheck() )
		{
			m_edtNumThreads.EnableWindow(TRUE);
			m_staticNumThreads.EnableWindow(TRUE);
		}
		else
		{
			m_edtNumThreads.EnableWindow(FALSE);
			m_staticNumThreads.EnableWindow(FALSE);
		}
	}
}

LRESULT CTimeCombinationsDlg::OnTaskDone(WPARAM wParam, LPARAM lParam)
{
	MainStruct* pMainStruct = (MainStruct*)wParam;
	CString szMsg;
	szMsg.Format( L"R: %d,\nN: %d,\nNumber of Threads: %d,\nNumber of Times: %d,\nNumber of processor detected: %d,\nTotal Duration Taken: %dmsec,\nTotal Combinations: %s",
		pMainStruct->nComb,
		pMainStruct->nSet,
		pMainStruct->nNumberOfThreads,
		pMainStruct->nTimes,
		m_nNumberOfProcessors,
		pMainStruct->nDuration,
		(LPCTSTR)szTotalComb );

	MessageBox( szMsg, L"Results", MB_OK );

	if( pMainStruct )
	{
		delete [] pMainStruct;
		pMainStruct = 0;
	}

	EnableCtrls(TRUE);

	return 0;
}

UINT IndividualThreadProc( LPVOID pParam )
{
	using namespace stdcomb;
	StartEndIndexes* psei = (StartEndIndexes*) pParam;

	CFindCombByIdx< CFindTotalComb<BigInteger>, BigInteger > findcomb;

	std::vector<unsigned int> vec(psei->nComb);
	
	findcomb.FindCombByIdx( psei->nSet, psei->nComb, psei->biStart, vec );
	CIdxComb idxComb(psei->nSet, psei->nComb);

	BigInteger cnt(psei->biStart);
	do
	{
		++cnt;
		if( psei->biEnd < cnt )
			break;
	}
	while( idxComb.GetNextComb(vec) );

	SetEvent( psei->hEvtDone );

	return 0;
}

UINT MainThreadProc( LPVOID pParam )
{
	MainStruct* pMainStruct = (MainStruct*)pParam;

	DWORD start=0, finish=0, duration=0;

	if (timeBeginPeriod (1) == TIMERR_NOERROR)
	{
		start = timeGetTime ();

		BigInteger biTotalComb(1);

		CFindTotalComb< BigInteger > ftc(1);
		ftc.Init();
		ftc.FindTotalComb( pMainStruct->nSet, pMainStruct->nComb );
		biTotalComb = ftc.GetResult();
		BigInteger biLoad = biTotalComb / pMainStruct->nNumberOfThreads;
		ftc.Destroy();

		BigInteger biTotal(0);
		StartEndIndexes* pIndexes = new StartEndIndexes[pMainStruct->nNumberOfThreads];
		UINT a=0;

		for( a=0; a<pMainStruct->nNumberOfThreads; ++a)
		{
			pIndexes[a].nComb = pMainStruct->nComb;
			pIndexes[a].nSet = pMainStruct->nSet;

			pIndexes[a].biStart = biTotal;
			biTotal += biLoad;

			if( a != pMainStruct->nNumberOfThreads-1 )
				pIndexes[a].biEnd = biTotal;
			else
				pIndexes[a].biEnd = biTotalComb;
		}

		HANDLE* pHandles = new HANDLE[pMainStruct->nNumberOfThreads];
		memset( pHandles, 0, sizeof(HANDLE) * pMainStruct->nNumberOfThreads );
		for( a=0; a<pMainStruct->nTimes; ++a)
		{
			UINT b=0;
			for( b=0; b<pMainStruct->nNumberOfThreads; ++b )
			{
				pIndexes[b].hEvtDone = CreateEvent( NULL, FALSE, FALSE, NULL );
				CWinThread* pThread = AfxBeginThread( IndividualThreadProc, &pIndexes[b] );
				pHandles[b] = pIndexes[b].hEvtDone;
			}

			WaitForMultipleObjects( 
				pMainStruct->nNumberOfThreads, pHandles, TRUE, INFINITE );

			for( b=0; b<pMainStruct->nNumberOfThreads; ++b )
			{
				CloseHandle( pHandles[b] );
			}
		}
		
		finish = timeGetTime ();
		duration = finish - start;
		pMainStruct->nDuration = duration;


		if( pHandles )
		{
			delete [] pHandles;
			pHandles = 0;
		}

		if( pIndexes )
		{
			delete [] pIndexes;
			pIndexes = 0; 
		}
	}

	timeEndPeriod (1);

	AfxGetMainWnd()->PostMessageW( WM_DONE, WPARAM(pMainStruct) );

	return 0;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Singapore Singapore
Shao Voon is from Singapore. His interest lies primarily in computer graphics, software optimization, concurrency, security, and Agile methodologies.

In recent years, he shifted focus to software safety research. His hobby is writing a free C++ DirectX photo slideshow application which can be viewed here.

Comments and Discussions