<commit_before>#include <ffigen/generate_node_ffi_interface.hpp>
#include <ffigen/utility/error_codes.hpp>
#include <ffigen/utility/exceptions.hpp>
#include <ffigen/utility/logger.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <vector>
#include <string>
#include <list>
#include <iostream>
#include <stdexcept>

namespace fs = boost::filesystem;

void recursive_glob_for_headers(std::list<std::string> & files, fs::path const& path)
{
    fs::recursive_directory_iterator i(path), end;
    for (; i != end; ++i)
    {
        fs::path const& path(i->path());

        std::string extension = path.extension().string();
        if (extension == ".h" || extension == ".hpp" || extension == ".hxx")
        {
            files.push_back(path.string());
        }
    }
}

//! required options:
//!   --file=path/to/file
//!     if directory, globs directory for .h/.hpp/.hxx files
//!     can be specified multiple times
//!   --dest=path/to/destination
//!     must be directory
//!   --src-root=path/to/root
//!     must be directory
//! TODO: add log level argument
int main(int argc, char ** argv)
{
    using namespace ffigen::utility::logs;
    using namespace ffigen::error_codes;

    std::string FILE_OPTION_PREFIX("--file="),
                DEST_OPTION_PREFIX("--dest="),
                SRC_OPTION_PREFIX("--src-root="),
                LOG_LEVEL_OPTION_PREFIX("--log-level="),
                INCLUDE_DIR_OPTION_PREFIX("--include=");

    std::list<std::string> files_to_process;
    std::string dest, src_root;
    std::list<std::string> include_directories;

    for (int i = 0; i < argc; ++i)
    {
        std::string arg(argv[i]);

        if (arg == "--help")
        {
            std::cout << "Generates node-ffi JS bindings using one or more C header files. Embeds clang's parser to do so.\n\n";
            std::cout << "Usage: node-ffi-generator --file=path/to/headers --dest=path/to/jsfiles/destination --src-root=path/headers/root/dir\n\n";
            std::cout << "Options:\n";
            std::cout << "  --file=path/to/file      C header file or directory with header files to process. If a directory,\n";
            std::cout << "                           it is searched recursively for .h, .hpp and .hxx files.\n";
            std::cout << "  --dest=path/to/dir       The destination directory for the mapping files.\n";
            std::cout << "  --src-root=path/to/dir   The root directory of the C library that's being mapped. Helps to determine\n";
            std::cout << "                           the destination's directory structure.\n";
            std::cout << "  --include=path/to/dir    A directory to use when searching for headers.\n";

            return SUCCESS;
        }
        else if (boost::starts_with(arg, FILE_OPTION_PREFIX)) // TODO should check if --file=...
        {
            std::string value = arg.substr(FILE_OPTION_PREFIX.length());

            // TODO: should support glob expressions
            fs::path path(value);
            if (fs::is_directory(path))
            {
                recursive_glob_for_headers(files_to_process, path);
            }
            else if (fs::is_regular_file(path))
            {
                files_to_process.push_back(value);
            }
            else
            {
                std::cout << "ERROR: '" << value << "' supplied in --file option does not exist.\n";
                return INVALID_ARGUMENT;
            }

            debug() << "Processed --file argument '" << value << "'" << std::endl;
        }
        else if (boost::starts_with(arg, DEST_OPTION_PREFIX))
        {
            std::string value = arg.substr(DEST_OPTION_PREFIX.length());

            if (!fs::is_directory(fs::path(value)))
            {
                std::cout << "ERROR: Destination '" << value << "' is not a valid directory.\n";
                return INVALID_ARGUMENT;
            }

            dest = value;

            debug() << "Processed --dest argument '" << dest << "'" << std::endl;
        }
        else if (boost::starts_with(arg, SRC_OPTION_PREFIX))
        {
            std::string value = arg.substr(SRC_OPTION_PREFIX.length());

            if (!fs::is_directory(fs::path(value)))
            {
                std::cout << "ERROR: Source root directory '" << value << "' is not a valid directory." << std::endl;
                return INVALID_ARGUMENT;
            }

            src_root = value;

            include_directories.push_back(src_root);

            debug() << "Processed --src-root argument '" << src_root << "'" << std::endl;
        }
        else if (boost::starts_with(arg, LOG_LEVEL_OPTION_PREFIX))
        {
            std::string value = arg.substr(LOG_LEVEL_OPTION_PREFIX.length());

            if (value == "ERROR")
            {
                set_level(levels::ERROR);
            }
            else if (value == "WARNING")
            {
                set_level(levels::WARNING);
            }
            else if (value == "INFO")
            {
                set_level(levels::INFO);
            }
            else if (value == "DEBUG")
            {
                set_level(levels::DEBUG);
            }
            else if (value == "VERBOSE")
            {
                set_level(levels::VERBOSE);
            }
            else
            {
                std::cout << "ERROR: Invalid log level supplied in --log-level option '" << value << "'." << std::endl;
                return INVALID_ARGUMENT;
            }
        }
        else if (boost::starts_with(arg, INCLUDE_DIR_OPTION_PREFIX))
        {
            std::string value = arg.substr(INCLUDE_DIR_OPTION_PREFIX.length());

            if (!fs::is_directory(fs::path(value)))
            {
                std::cout << "ERROR: Include directory '" << value << "' is not a valid directory." << std::endl;
                return INVALID_ARGUMENT;
            }

            include_directories.push_back(value);
        }
    }

    if (files_to_process.empty())
    {
        std::cout << "ERROR: Required option 'file' not supplied.\n";
        return MISSING_ARGUMENT;
    }

    if (dest.empty())
    {
        std::cout << "ERROR: Required option 'dest' not supplied.\n";
        return MISSING_ARGUMENT;
    }

    if (src_root.empty())
    {
        std::cout << "ERROR: Required option 'src-root' not supplied.\n";
        return MISSING_ARGUMENT;
    }

    // generate the interface
    try
    {
        ffigen::generate_node_ffi_interface(files_to_process, src_root, dest, include_directories);
    }
    catch (ffigen::fatal_error const& ex)
    {
        std::cout << "ERROR: " << ex.what() << std::endl;
        return ex.error_code;
    }
    catch (std::exception const& ex)
    {
        std::cout << "UNEXPECTED ERROR: " << ex.what() << std::endl;
        return UNKNOWN_ERROR;
    }
}
<commit_msg>Set default log level to INFO if none specified on command line.<commit_after>#include <ffigen/generate_node_ffi_interface.hpp>
#include <ffigen/utility/error_codes.hpp>
#include <ffigen/utility/exceptions.hpp>
#include <ffigen/utility/logger.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <vector>
#include <string>
#include <list>
#include <iostream>
#include <stdexcept>

namespace fs = boost::filesystem;

void recursive_glob_for_headers(std::list<std::string> & files, fs::path const& path)
{
    fs::recursive_directory_iterator i(path), end;
    for (; i != end; ++i)
    {
        fs::path const& path(i->path());

        std::string extension = path.extension().string();
        if (extension == ".h" || extension == ".hpp" || extension == ".hxx")
        {
            files.push_back(path.string());
        }
    }
}

//! required options:
//!   --file=path/to/file
//!     if directory, globs directory for .h/.hpp/.hxx files
//!     can be specified multiple times
//!   --dest=path/to/destination
//!     must be directory
//!   --src-root=path/to/root
//!     must be directory
//! TODO: add log level argument
int main(int argc, char ** argv)
{
    using namespace ffigen::utility::logs;
    using namespace ffigen::error_codes;

    set_level(levels::INFO);

    std::string FILE_OPTION_PREFIX("--file="),
                DEST_OPTION_PREFIX("--dest="),
                SRC_OPTION_PREFIX("--src-root="),
                LOG_LEVEL_OPTION_PREFIX("--log-level="),
                INCLUDE_DIR_OPTION_PREFIX("--include=");

    std::list<std::string> files_to_process;
    std::string dest, src_root;
    std::list<std::string> include_directories;

    for (int i = 0; i < argc; ++i)
    {
        std::string arg(argv[i]);

        if (arg == "--help")
        {
            std::cout << "Generates node-ffi JS bindings using one or more C header files. Embeds clang's parser to do so.\n\n";
            std::cout << "Usage: node-ffi-generator --file=path/to/headers --dest=path/to/jsfiles/destination --src-root=path/headers/root/dir\n\n";
            std::cout << "Options:\n";
            std::cout << "  --file=path/to/file      C header file or directory with header files to process. If a directory,\n";
            std::cout << "                           it is searched recursively for .h, .hpp and .hxx files.\n";
            std::cout << "  --dest=path/to/dir       The destination directory for the mapping files.\n";
            std::cout << "  --src-root=path/to/dir   The root directory of the C library that's being mapped. Helps to determine\n";
            std::cout << "                           the destination's directory structure.\n";
            std::cout << "  --include=path/to/dir    A directory to use when searching for headers.\n";

            return SUCCESS;
        }
        else if (boost::starts_with(arg, FILE_OPTION_PREFIX)) // TODO should check if --file=...
        {
            std::string value = arg.substr(FILE_OPTION_PREFIX.length());

            // TODO: should support glob expressions
            fs::path path(value);
            if (fs::is_directory(path))
            {
                recursive_glob_for_headers(files_to_process, path);
            }
            else if (fs::is_regular_file(path))
            {
                files_to_process.push_back(value);
            }
            else
            {
                std::cout << "ERROR: '" << value << "' supplied in --file option does not exist.\n";
                return INVALID_ARGUMENT;
            }

            debug() << "Processed --file argument '" << value << "'" << std::endl;
        }
        else if (boost::starts_with(arg, DEST_OPTION_PREFIX))
        {
            std::string value = arg.substr(DEST_OPTION_PREFIX.length());

            if (!fs::is_directory(fs::path(value)))
            {
                std::cout << "ERROR: Destination '" << value << "' is not a valid directory.\n";
                return INVALID_ARGUMENT;
            }

            dest = value;

            debug() << "Processed --dest argument '" << dest << "'" << std::endl;
        }
        else if (boost::starts_with(arg, SRC_OPTION_PREFIX))
        {
            std::string value = arg.substr(SRC_OPTION_PREFIX.length());

            if (!fs::is_directory(fs::path(value)))
            {
                std::cout << "ERROR: Source root directory '" << value << "' is not a valid directory." << std::endl;
                return INVALID_ARGUMENT;
            }

            src_root = value;

            include_directories.push_back(src_root);

            debug() << "Processed --src-root argument '" << src_root << "'" << std::endl;
        }
        else if (boost::starts_with(arg, LOG_LEVEL_OPTION_PREFIX))
        {
            std::string value = arg.substr(LOG_LEVEL_OPTION_PREFIX.length());

            if (value == "ERROR")
            {
                set_level(levels::ERROR);
            }
            else if (value == "WARNING")
            {
                set_level(levels::WARNING);
            }
            else if (value == "INFO")
            {
                set_level(levels::INFO);
            }
            else if (value == "DEBUG")
            {
                set_level(levels::DEBUG);
            }
            else if (value == "VERBOSE")
            {
                set_level(levels::VERBOSE);
            }
            else
            {
                std::cout << "ERROR: Invalid log level supplied in --log-level option '" << value << "'." << std::endl;
                return INVALID_ARGUMENT;
            }
        }
        else if (boost::starts_with(arg, INCLUDE_DIR_OPTION_PREFIX))
        {
            std::string value = arg.substr(INCLUDE_DIR_OPTION_PREFIX.length());

            if (!fs::is_directory(fs::path(value)))
            {
                std::cout << "ERROR: Include directory '" << value << "' is not a valid directory." << std::endl;
                return INVALID_ARGUMENT;
            }

            include_directories.push_back(value);
        }
    }

    if (files_to_process.empty())
    {
        std::cout << "ERROR: Required option 'file' not supplied.\n";
        return MISSING_ARGUMENT;
    }

    if (dest.empty())
    {
        std::cout << "ERROR: Required option 'dest' not supplied.\n";
        return MISSING_ARGUMENT;
    }

    if (src_root.empty())
    {
        std::cout << "ERROR: Required option 'src-root' not supplied.\n";
        return MISSING_ARGUMENT;
    }

    // generate the interface
    try
    {
        ffigen::generate_node_ffi_interface(files_to_process, src_root, dest, include_directories);
    }
    catch (ffigen::fatal_error const& ex)
    {
        std::cout << "ERROR: " << ex.what() << std::endl;
        return ex.error_code;
    }
    catch (std::exception const& ex)
    {
        std::cout << "UNEXPECTED ERROR: " << ex.what() << std::endl;
        return UNKNOWN_ERROR;
    }
}
<|endoftext|>


<commit_before>#include <list>
#include <vector>
#include <cstdlib>

#include <stdio.h>
#include <string.h>

#include <nds.h>

#include "background.h"
#include "background2.h"
#include "tiles.h"

//#define DEBUG

// Windows rand() function. Used to get the same deals as Windows Freecell.
long holdrand;
void win_srand (long seed)
{
	holdrand = seed;
}
int win_rand (void)
{
	return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
}

SpriteEntry spriteEntry[128];
SpriteRotation *spriteRotation = (SpriteRotation*)spriteEntry;

struct TouchHelper {
	bool held, down, up;
	touchPosition touch;
	u16 prevx, prevy;
};

enum Color { BLACK, RED };
enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES };
enum Value { ACE = 1, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE,
	TEN, JACK, QUEEN, KING };

#define COLOR(card) ((SUIT(card) == HEARTS || SUIT(card) == DIAMONDS) ? RED : BLACK)
#define SUIT(card) (card%4)
#define VALUE(card) ((card/4)+1)

class Card {
public:
	int card;

	Card()
	{
	}

	void Initialize(int card)
	{
		this->card = card;
	}

	inline int color() const
	{
		return COLOR(card);
	}

	inline int suit() const
	{
		return SUIT(card);
	}

	inline int value() const
	{
		return VALUE(card);
	}
};

class FreeCellGame {
public:
	/// The eight stacks in the playing field.
	std::vector<Card*> stack[8];
	/// The four free cells.
	Card *freecells[4];
	/// The four finished stacks.
	std::vector<Card*> finish[4];
	/// The stack that is currently being moved by the player.
	std::vector<Card*> moving;
	/// The deck of cards.
	Card cards[52];
	/// The shuffled pointers of cards.
	Card *shuffled[52];

	int movingx, movingy;
	int stack_moving_from;

	FreeCellGame()
	{
	}

	void Initialize()
	{
		movingx = movingy = 0;

		for (int i = 0; i < 8; i++)
			stack[i].reserve(21);

		for (int i = 0; i < 4; i++)
			finish[i].reserve(13);

		moving.reserve(13);

		for (int i = 0; i < 52; i++)
			cards[i].Initialize(i);

		Deal(time(NULL));

		DrawCards();
	}

	/// Deal the cards with the specified game number.
	void Deal(long seed)
	{
		for (int i = 0; i < 52; i++)
			shuffled[i] = &cards[i];

		for (int i = 0; i < 8; i++)
			stack[i].clear();
		printf("game #%ld\n", time(NULL)&0x7fff);

		win_srand(seed);
		int wLeft = 52;
		for (int i = 0; i < 52; i++)
		{
			int j = win_rand() % wLeft;
			stack[i%8].push_back(shuffled[j]);
			shuffled[j] = shuffled[--wLeft];
		}

		for (int i = 0; i < 4; i++)
			freecells[i] = NULL;

		for (int i = 0; i < 4; i++)
			finish[i].clear();
	}

	/// Moves the bottom n cards from the first stack to the second.
	void MoveStack(int n, int s1, int s2)
	{
		for (std::vector<Card*>::iterator it = stack[s1].end() - n;
				it != stack[s1].end(); ++it)
			stack[s2].push_back(*it);
		stack[s1].erase(stack[s1].end() - n, stack[s1].end());
	}

	/// Draws a single card.
	void DrawCard(Card *card, int sprite_pos, int x, int y)
	{
		int suit = card->suit();
		int value = card->value() - 1;
		int index = (value / 2) * 128 + (value % 2) * 16 + suit * 4;

		spriteEntry[sprite_pos].attribute[0] = ATTR0_NORMAL | ATTR0_COLOR_16 | ATTR0_SQUARE;
		spriteEntry[sprite_pos].attribute[1] = ATTR1_SIZE_32;
		spriteEntry[sprite_pos].attribute[2] = ATTR2_PRIORITY(3) | index;
		spriteEntry[sprite_pos].x = x;
		spriteEntry[sprite_pos].y = y;
	}

	/// Draws all the cards.
	void DrawCards()
	{
		int pos = 0;

		for (int j = moving.size() - 1; j >= 0; j--)
			DrawCard(moving[j], pos++, movingx - 8, movingy - 4 + j*11);

		for (int i = 0; i < 8; i++)
		{
			for (int j = stack[i].size() - 1; j >= 0; j--)
				DrawCard(stack[i][j], pos++, i*32, j*11 + 48);
		}

		for (int i = 0; i < 4; i++)
		{
			if (freecells[i] != NULL)
				DrawCard(freecells[i], pos++, i*32, 5);
		}

		for (int i = 0; i < 4; i++)
		{
			if (!finish[i].empty())
				DrawCard(finish[i][finish[i].size()-1], pos++, (4+i)*32, 5);
		}

		while (pos < 128)
			spriteEntry[pos++].attribute[0] = ATTR0_DISABLED;
	}

	/// Returns true if card1 can be moved under card2.
	bool IsCardUnderCard(const Card *card1, const Card *card2)
	{
		return (card1->color() != card2->color() &&
				card1->value() == card2->value() - 1);
	}

	/// Returns true if card1 can be moved over card2 on the finished stacks.
	bool IsCardOverCardFinish(const Card *card1, const Card *card2)
	{
		return (card1->suit() == card2->suit() &&
				card1->value() == card2->value() + 1);
	}

	/// Returns true if the card in position n of stack st can be moved.
	bool CanSelectCard(int st, int n)
	{
		int num_freecells = 0;
		for (int i = 0; i < 4; i++)
			if (freecells[i] == NULL)
				num_freecells++;

		int size = stack[st].size();

		if (size - n > num_freecells + 1)
			return false;

		while (n < size - 1)
		{
			if (!IsCardUnderCard(stack[st][n+1], stack[st][n]))
				return false;
			n++;
		}

		return true;
	}

	void SelectCards(const TouchHelper &touch)
	{
		int px = touch.touch.px;
		int py = touch.touch.py;

		unsigned int selx = px / 32;
		unsigned int sely = (py - 48) / 11;

		if (selx > 7)
			selx = 7;

		if (py < 40)
		{
			// Handle selecting from freecells.
			if (selx < 4)
			{
				if (freecells[selx] != NULL)
				{
					moving.push_back(freecells[selx]);
					stack_moving_from = selx + 8;
					freecells[selx] = NULL;

					movingx = px;
					movingy = py;
				}
			}
		}
		else
		{
			if (!CanSelectCard(selx, sely))
				return;

			if (stack[selx].size() > sely)
			{
				for (std::vector<Card*>::iterator it = stack[selx].begin() + sely;
						it != stack[selx].end(); ++it)
				{
					moving.push_back(*it);
				}
				stack[selx].erase(stack[selx].begin() + sely, stack[selx].end());
			}

			movingx = px;
			movingy = py;

			stack_moving_from = selx;
		}
	}

	void RevertMove()
	{
		if (stack_moving_from < 8)
		{
			for (std::vector<Card*>::iterator it = moving.begin();
					it != moving.end(); ++it)
			{
				stack[stack_moving_from].push_back(*it);
			}
		}
		else
		{
			freecells[stack_moving_from - 8] = moving[0];
		}

		moving.clear();
	}

	void MoveCards(const TouchHelper &touch)
	{
		int px = touch.prevx + 16;
		int py = touch.prevy;

		unsigned int selx = (px - 8) / 32;

		if (selx > 7)
			selx = 7;

		if (moving.empty())
			return;

		if (py < 40)
		{
			// Handle moving to freecells.
			if (selx < 4)
			{
				if (freecells[selx] == NULL && moving.size() == 1)
				{
					freecells[selx] = moving[0];
				}
				else
					RevertMove();
				moving.clear();
			}
			// Handle moving to the finished stacks.
			else
			{
				selx -= 4;
				if (moving.size() != 1)
				{
					RevertMove();
				}
				else
				{
					if (finish[selx].empty() && moving[0]->value() == ACE)
					{
						finish[selx].push_back(moving[0]);
						moving.clear();
					}
					else if (!finish[selx].empty() &&
							IsCardOverCardFinish(moving[0], finish[selx][finish[selx].size()-1]))
					{
						finish[selx].push_back(moving[0]);
						moving.clear();
					}
					else
					{
						RevertMove();
					}
				}
			}
		}
		else
		{
			// Handle moving to stack.
			if (!stack[selx].empty() &&
					!IsCardUnderCard(moving[0], stack[selx][stack[selx].size()-1]))
			{
				RevertMove();
			}
			else
			{
				for (std::vector<Card*>::iterator it = moving.begin();
						it != moving.end(); ++it)
				{
					stack[selx].push_back(*it);
				}
				moving.clear();
			}
		}
	}

	void HandleTouch(const TouchHelper &touch)
	{
		if (touch.down)
			SelectCards(touch);
		else if (touch.held)
		{
			movingx = touch.touch.px;
			movingy = touch.touch.py;
		}
		else if (touch.up)
			MoveCards(touch);
	}

	void Update(const TouchHelper &touch)
	{
		HandleTouch(touch);
		DrawCards();
	}
};

inline void dmaFlushCopy(void *src, void *dst, size_t size)
{
	//DC_FlushRange(src, size);
	DC_FlushAll();
	dmaCopy(src, dst, size);
}

void updateOAM() {
    //DC_FlushAll();
	memcpy(OAM, spriteEntry, 128*sizeof(SpriteEntry));
    //dmaCopyHalfWords(3, spriteEntry, OAM, 128 * sizeof(SpriteEntry));
}

int main(void) {
	int i;
	TouchHelper touch;

	powerOn(POWER_ALL_2D);
	lcdMainOnBottom();

#ifdef DEBUG
	consoleDemoInit();
#endif

	// Set the video ram banks.
    vramSetMainBanks(VRAM_A_MAIN_BG_0x06000000,
                     VRAM_B_MAIN_SPRITE_0x06400000,
                     VRAM_C_SUB_BG_0x06200000,
                     VRAM_D_LCD);

	// Set the graphic modes.
    videoSetMode(MODE_5_2D |
                 DISPLAY_BG3_ACTIVE |
                 DISPLAY_SPR_ACTIVE |
                 DISPLAY_SPR_2D);
#ifndef DEBUG
    videoSetModeSub(MODE_5_2D | DISPLAY_BG3_ACTIVE);
#endif

	// Initialize the background.
	bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
	REG_BG3CNT |= BG_PRIORITY_3;
#ifndef DEBUG
	bgInitSub(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
	REG_BG3CNT_SUB |= BG_PRIORITY_3;
#endif

	// Initialize the sprites to all be off.
	for (i = 0; i < 128; i++) {
		spriteEntry[i].attribute[0] = ATTR0_DISABLED;
		spriteEntry[i].attribute[1] = 0;
		spriteEntry[i].attribute[2] = 0;
	}
	for (i = 0; i < 32; i++) {
		spriteRotation[i].hdx = 256;
		spriteRotation[i].hdy = 0;
		spriteRotation[i].vdx = 0;
		spriteRotation[i].vdy = 256;
	}

	// Copy the graphics to video ram.
	DC_FlushAll();
	dmaCopy(tilesPal, SPRITE_PALETTE, sizeof(tilesPal));
	dmaCopy(tilesTiles, SPRITE_GFX, sizeof(tilesTiles));
	decompress(backgroundBitmap, BG_GFX, LZ77Vram);
#ifndef DEBUG
	decompress(background2Bitmap, BG_GFX_SUB, LZ77Vram);
#endif

	// Start the game.
	FreeCellGame game;
	game.Initialize();

	while (1) {
		scanKeys();
		touch.prevx = touch.touch.px;
		touch.prevy = touch.touch.py;
		touchRead(&touch.touch);
		touch.held = keysHeld() & KEY_TOUCH;
		touch.down = keysDown() & KEY_TOUCH;
		touch.up   = keysUp() & KEY_TOUCH;

		if (keysDown() & KEY_START)
			game.Deal(time(NULL));

		game.Update(touch);

		swiWaitForVBlank();
		updateOAM();
	}

	return 0;
}

<commit_msg>Better selecting of cards.<commit_after>#include <list>
#include <vector>
#include <cstdlib>

#include <stdio.h>
#include <string.h>

#include <nds.h>

#include "background.h"
#include "background2.h"
#include "tiles.h"

//#define DEBUG

// Windows rand() function. Used to get the same deals as Windows Freecell.
long holdrand;
void win_srand (long seed)
{
	holdrand = seed;
}
int win_rand (void)
{
	return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
}

SpriteEntry spriteEntry[128];
SpriteRotation *spriteRotation = (SpriteRotation*)spriteEntry;

struct TouchHelper {
	bool held, down, up;
	touchPosition touch;
	u16 prevx, prevy;
};

enum Color { BLACK, RED };
enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES };
enum Value { ACE = 1, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE,
	TEN, JACK, QUEEN, KING };

#define COLOR(card) ((SUIT(card) == HEARTS || SUIT(card) == DIAMONDS) ? RED : BLACK)
#define SUIT(card) (card%4)
#define VALUE(card) ((card/4)+1)

class Card {
public:
	int card;

	Card()
	{
	}

	void Initialize(int card)
	{
		this->card = card;
	}

	inline int color() const
	{
		return COLOR(card);
	}

	inline int suit() const
	{
		return SUIT(card);
	}

	inline int value() const
	{
		return VALUE(card);
	}
};

class FreeCellGame {
public:
	/// The eight stacks in the playing field.
	std::vector<Card*> stack[8];
	/// The four free cells.
	Card *freecells[4];
	/// The four finished stacks.
	std::vector<Card*> finish[4];
	/// The stack that is currently being moved by the player.
	std::vector<Card*> moving;
	/// The deck of cards.
	Card cards[52];
	/// The shuffled pointers of cards.
	Card *shuffled[52];

	int movingx, movingy;
	int stack_moving_from;

	FreeCellGame()
	{
	}

	void Initialize()
	{
		movingx = movingy = 0;

		for (int i = 0; i < 8; i++)
			stack[i].reserve(21);

		for (int i = 0; i < 4; i++)
			finish[i].reserve(13);

		moving.reserve(13);

		for (int i = 0; i < 52; i++)
			cards[i].Initialize(i);

		Deal(time(NULL));

		DrawCards();
	}

	/// Deal the cards with the specified game number.
	void Deal(long seed)
	{
		for (int i = 0; i < 52; i++)
			shuffled[i] = &cards[i];

		for (int i = 0; i < 8; i++)
			stack[i].clear();
		printf("game #%ld\n", time(NULL)&0x7fff);

		win_srand(seed);
		int wLeft = 52;
		for (int i = 0; i < 52; i++)
		{
			int j = win_rand() % wLeft;
			stack[i%8].push_back(shuffled[j]);
			shuffled[j] = shuffled[--wLeft];
		}

		for (int i = 0; i < 4; i++)
			freecells[i] = NULL;

		for (int i = 0; i < 4; i++)
			finish[i].clear();
	}

	/// Moves the bottom n cards from the first stack to the second.
	void MoveStack(int n, int s1, int s2)
	{
		for (std::vector<Card*>::iterator it = stack[s1].end() - n;
				it != stack[s1].end(); ++it)
			stack[s2].push_back(*it);
		stack[s1].erase(stack[s1].end() - n, stack[s1].end());
	}

	/// Draws a single card.
	void DrawCard(Card *card, int sprite_pos, int x, int y)
	{
		int suit = card->suit();
		int value = card->value() - 1;
		int index = (value / 2) * 128 + (value % 2) * 16 + suit * 4;

		spriteEntry[sprite_pos].attribute[0] = ATTR0_NORMAL | ATTR0_COLOR_16 | ATTR0_SQUARE;
		spriteEntry[sprite_pos].attribute[1] = ATTR1_SIZE_32;
		spriteEntry[sprite_pos].attribute[2] = ATTR2_PRIORITY(3) | index;
		spriteEntry[sprite_pos].x = x;
		spriteEntry[sprite_pos].y = y;
	}

	/// Draws all the cards.
	void DrawCards()
	{
		int pos = 0;

		for (int j = moving.size() - 1; j >= 0; j--)
			DrawCard(moving[j], pos++, movingx - 8, movingy - 4 + j*11);

		for (int i = 0; i < 8; i++)
		{
			for (int j = stack[i].size() - 1; j >= 0; j--)
				DrawCard(stack[i][j], pos++, i*32, j*11 + 48);
		}

		for (int i = 0; i < 4; i++)
		{
			if (freecells[i] != NULL)
				DrawCard(freecells[i], pos++, i*32, 5);
		}

		for (int i = 0; i < 4; i++)
		{
			if (!finish[i].empty())
				DrawCard(finish[i][finish[i].size()-1], pos++, (4+i)*32, 5);
		}

		while (pos < 128)
			spriteEntry[pos++].attribute[0] = ATTR0_DISABLED;
	}

	/// Returns true if card1 can be moved under card2.
	bool IsCardUnderCard(const Card *card1, const Card *card2)
	{
		return (card1->color() != card2->color() &&
				card1->value() == card2->value() - 1);
	}

	/// Returns true if card1 can be moved over card2 on the finished stacks.
	bool IsCardOverCardFinish(const Card *card1, const Card *card2)
	{
		return (card1->suit() == card2->suit() &&
				card1->value() == card2->value() + 1);
	}

	/// Returns true if the card in position n of stack st can be moved.
	bool CanSelectCard(int st, int n)
	{
		int num_freecells = 0;
		for (int i = 0; i < 4; i++)
			if (freecells[i] == NULL)
				num_freecells++;

		int size = stack[st].size();

		if (size - n > num_freecells + 1)
			return false;

		while (n < size - 1)
		{
			if (!IsCardUnderCard(stack[st][n+1], stack[st][n]))
				return false;
			n++;
		}

		return true;
	}

	void SelectCards(const TouchHelper &touch)
	{
		int px = touch.touch.px;
		int py = touch.touch.py;

		unsigned int selx = px / 32;
		unsigned int sely = (py - 48) / 11;

		if (selx > 7)
			selx = 7;

		if (py < 48)
		{
			// Handle selecting from freecells.
			if (selx < 4)
			{
				if (freecells[selx] != NULL)
				{
					moving.push_back(freecells[selx]);
					stack_moving_from = selx + 8;
					freecells[selx] = NULL;

					movingx = px;
					movingy = py;
				}
			}
		}
		else
		{
			if (sely > stack[selx].size() - 1)
				sely = stack[selx].size() - 1;

			if (!CanSelectCard(selx, sely))
				return;

			if (stack[selx].size() > sely)
			{
				for (std::vector<Card*>::iterator it = stack[selx].begin() + sely;
						it != stack[selx].end(); ++it)
				{
					moving.push_back(*it);
				}
				stack[selx].erase(stack[selx].begin() + sely, stack[selx].end());
			}

			movingx = px;
			movingy = py;

			stack_moving_from = selx;
		}
	}

	void RevertMove()
	{
		if (stack_moving_from < 8)
		{
			for (std::vector<Card*>::iterator it = moving.begin();
					it != moving.end(); ++it)
			{
				stack[stack_moving_from].push_back(*it);
			}
		}
		else
		{
			freecells[stack_moving_from - 8] = moving[0];
		}

		moving.clear();
	}

	void MoveCards(const TouchHelper &touch)
	{
		int px = touch.prevx + 16;
		int py = touch.prevy;

		unsigned int selx = (px - 8) / 32;

		if (selx > 7)
			selx = 7;

		if (moving.empty())
			return;

		if (py < 48)
		{
			// Handle moving to freecells.
			if (selx < 4)
			{
				if (freecells[selx] == NULL && moving.size() == 1)
				{
					freecells[selx] = moving[0];
				}
				else
					RevertMove();
				moving.clear();
			}
			// Handle moving to the finished stacks.
			else
			{
				selx -= 4;
				if (moving.size() != 1)
				{
					RevertMove();
				}
				else
				{
					if (finish[selx].empty() && moving[0]->value() == ACE)
					{
						finish[selx].push_back(moving[0]);
						moving.clear();
					}
					else if (!finish[selx].empty() &&
							IsCardOverCardFinish(moving[0], finish[selx][finish[selx].size()-1]))
					{
						finish[selx].push_back(moving[0]);
						moving.clear();
					}
					else
					{
						RevertMove();
					}
				}
			}
		}
		else
		{
			// Handle moving to stack.
			if (!stack[selx].empty() &&
					!IsCardUnderCard(moving[0], stack[selx][stack[selx].size()-1]))
			{
				RevertMove();
			}
			else
			{
				for (std::vector<Card*>::iterator it = moving.begin();
						it != moving.end(); ++it)
				{
					stack[selx].push_back(*it);
				}
				moving.clear();
			}
		}
	}

	void HandleTouch(const TouchHelper &touch)
	{
		if (touch.down)
			SelectCards(touch);
		else if (touch.held)
		{
			movingx = touch.touch.px;
			movingy = touch.touch.py;
		}
		else if (touch.up)
			MoveCards(touch);
	}

	void Update(const TouchHelper &touch)
	{
		HandleTouch(touch);
		DrawCards();
	}
};

inline void dmaFlushCopy(void *src, void *dst, size_t size)
{
	//DC_FlushRange(src, size);
	DC_FlushAll();
	dmaCopy(src, dst, size);
}

void updateOAM() {
    //DC_FlushAll();
	memcpy(OAM, spriteEntry, 128*sizeof(SpriteEntry));
    //dmaCopyHalfWords(3, spriteEntry, OAM, 128 * sizeof(SpriteEntry));
}

int main(void) {
	int i;
	TouchHelper touch;

	powerOn(POWER_ALL_2D);
	lcdMainOnBottom();

#ifdef DEBUG
	consoleDemoInit();
#endif

	// Set the video ram banks.
    vramSetMainBanks(VRAM_A_MAIN_BG_0x06000000,
                     VRAM_B_MAIN_SPRITE_0x06400000,
                     VRAM_C_SUB_BG_0x06200000,
                     VRAM_D_LCD);

	// Set the graphic modes.
    videoSetMode(MODE_5_2D |
                 DISPLAY_BG3_ACTIVE |
                 DISPLAY_SPR_ACTIVE |
                 DISPLAY_SPR_2D);
#ifndef DEBUG
    videoSetModeSub(MODE_5_2D | DISPLAY_BG3_ACTIVE);
#endif

	// Initialize the background.
	bgInit(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
	REG_BG3CNT |= BG_PRIORITY_3;
#ifndef DEBUG
	bgInitSub(3, BgType_Bmp16, BgSize_B16_256x256, 0, 0);
	REG_BG3CNT_SUB |= BG_PRIORITY_3;
#endif

	// Initialize the sprites to all be off.
	for (i = 0; i < 128; i++) {
		spriteEntry[i].attribute[0] = ATTR0_DISABLED;
		spriteEntry[i].attribute[1] = 0;
		spriteEntry[i].attribute[2] = 0;
	}
	for (i = 0; i < 32; i++) {
		spriteRotation[i].hdx = 256;
		spriteRotation[i].hdy = 0;
		spriteRotation[i].vdx = 0;
		spriteRotation[i].vdy = 256;
	}

	// Copy the graphics to video ram.
	DC_FlushAll();
	dmaCopy(tilesPal, SPRITE_PALETTE, sizeof(tilesPal));
	dmaCopy(tilesTiles, SPRITE_GFX, sizeof(tilesTiles));
	decompress(backgroundBitmap, BG_GFX, LZ77Vram);
#ifndef DEBUG
	decompress(background2Bitmap, BG_GFX_SUB, LZ77Vram);
#endif

	// Start the game.
	FreeCellGame game;
	game.Initialize();

	while (1) {
		scanKeys();
		touch.prevx = touch.touch.px;
		touch.prevy = touch.touch.py;
		touchRead(&touch.touch);
		touch.held = keysHeld() & KEY_TOUCH;
		touch.down = keysDown() & KEY_TOUCH;
		touch.up   = keysUp() & KEY_TOUCH;

		if (keysDown() & KEY_START)
			game.Deal(time(NULL));

		game.Update(touch);

		swiWaitForVBlank();
		updateOAM();
	}

	return 0;
}

<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
//      https://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.
#include <string>

#include "experimental/ModelBuilder/ModelBuilder.h"
#include "experimental/ModelBuilder/ModelRunner.h"
#include "experimental/ModelBuilder/VulkanWrapperPass.h"
#include "iree/base/initializer.h"
#include "iree/compiler/Conversion/CodegenUtils/MatmulCodegenStrategy.h"
#include "iree/compiler/Conversion/LinalgToSPIRV/MemorySpace.h"
#include "iree/compiler/Conversion/LinalgToSPIRV/Passes.h"
#include "iree/compiler/Conversion/LinalgToSPIRV/Utils.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
#include "mlir/Conversion/GPUToVulkan/ConvertGPUToVulkanPass.h"
#include "mlir/Conversion/LinalgToLLVM/LinalgToLLVM.h"
#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h"
#include "mlir/Conversion/StandardToSPIRV/ConvertStandardToSPIRVPass.h"
#include "mlir/Dialect/GPU/Passes.h"
#include "mlir/Dialect/Linalg/EDSC/Intrinsics.h"
#include "mlir/Dialect/Linalg/Passes.h"
#include "mlir/Dialect/Linalg/Transforms/Transforms.h"
#include "mlir/Dialect/SPIRV/Passes.h"
#include "mlir/Dialect/SPIRV/SPIRVOps.h"
#include "mlir/Dialect/SPIRV/TargetAndABI.h"
#include "mlir/Dialect/Vector/VectorOps.h"
#include "mlir/ExecutionEngine/CRunnerUtils.h"
#include "mlir/ExecutionEngine/RunnerUtils.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/OperationSupport.h"
#include "mlir/Parser.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Transforms/Passes.h"

using namespace mlir;                    // NOLINT
using namespace mlir::edsc;              // NOLINT
using namespace mlir::edsc::intrinsics;  // NOLINT

static llvm::cl::opt<std::string> vulkanWrapper(
    "vulkan-wrapper", llvm::cl::desc("Vulkan wrapper library"),
    llvm::cl::value_desc("filename"), llvm::cl::init("-"));

static llvm::cl::opt<bool> correctness(
    "correctness",
    llvm::cl::desc(
        "Compare the result to value calculated on CPU. We will use a smaller "
        "matrix multiply in this case to avoid long runtime."),
    llvm::cl::init(false));

static llvm::cl::opt<bool> useWorkgroupMemory(
    "use-workgroup-memory", llvm::cl::desc("Enable use of workgroup memory"),
    llvm::cl::value_desc("boolean"), llvm::cl::init(false));

static void addLoweringPasses(mlir::PassManager &pm,
                              llvm::ArrayRef<int64_t> numWorkgroups,
                              llvm::ArrayRef<Type> args) {
  pm.addPass(mlir::iree_compiler::createVectorToGPUPass());
  pm.addPass(mlir::createLowerAffinePass());
  pm.addPass(mlir::createLegalizeStdOpsForSPIRVLoweringPass());
  pm.addPass(mlir::createCanonicalizerPass());
  pm.addPass(mlir::createCSEPass());
  pm.addPass(mlir::iree_compiler::createConvertToSPIRVPass());

  auto &spirvModulePM = pm.nest<mlir::spirv::ModuleOp>();
  spirvModulePM.addPass(mlir::createSetSpirvABIPass());
  spirvModulePM.addPass(mlir::spirv::createLowerABIAttributesPass());
  spirvModulePM.addPass(mlir::createCanonicalizerPass());
  spirvModulePM.addPass(mlir::createCSEPass());
  spirvModulePM.addPass(
      mlir::spirv::createUpdateVersionCapabilityExtensionPass());

  pm.addPass(mlir::createAddVulkanLaunchWrapperPass(numWorkgroups, args));
  mlir::LowerToLLVMOptions llvmOptions = {
      /*useBarePtrCallConv=*/false,
      /*emitCWrappers=*/true,
      /*indexBitwidth=*/mlir::kDeriveIndexBitwidthFromDataLayout};
  pm.addPass(createLowerToLLVMPass(llvmOptions));
  pm.addPass(mlir::createConvertVulkanLaunchFuncToVulkanCallsPass());
}

static void insertBarrier(OpBuilder &b, Location loc) {
  b.create<spirv::ControlBarrierOp>(loc, spirv::Scope::Workgroup,
                                    spirv::Scope::Workgroup,
                                    spirv::MemorySemantics::AcquireRelease);
}

template <typename IdOp, typename NProcsOp>
static linalg::ProcInfo getGpuProcIds(OpBuilder &b, Location loc,
                                      unsigned loopNum) {
  Type indexType = b.getIndexType();
  switch (loopNum) {
    case 0:
      return {b.create<IdOp>(loc, indexType, b.getStringAttr("y")),
              b.create<NProcsOp>(loc, indexType, b.getStringAttr("y"))};
    case 1:
      return {b.create<IdOp>(loc, indexType, b.getStringAttr("x")),
              b.create<NProcsOp>(loc, indexType, b.getStringAttr("x"))};
    default:
      llvm_unreachable("test patterns handles only upto 2-level nested loops");
  }
  return {nullptr, nullptr};
}

constexpr int numSubgroupX = 2;
constexpr int numSubgroupY = 2;

static linalg::ProcInfo getSubgroupIds(OpBuilder &b, Location loc,
                                       unsigned loopNum) {
  Type indexType = b.getIndexType();
  Value sg = b.create<gpu::SubgroupIdOp>(loc, indexType);
  Value vSubgroupX = b.create<ConstantIndexOp>(loc, numSubgroupX);
  using namespace edsc::op;
  switch (loopNum) {
    case 0:
      return {sg % vSubgroupX, vSubgroupX};
    case 1: {
      Value vSubgroupY = b.create<ConstantIndexOp>(loc, numSubgroupY);
      Value sgdiv = b.create<SignedDivIOp>(loc, indexType, sg, vSubgroupX);
      return {sgdiv % vSubgroupY, vSubgroupY};
    }
    default:
      llvm_unreachable("test patterns handles only upto 2-level nested loops");
  }
  return {nullptr, nullptr};
}

void matMul(int m, int n, int k, int tileM, int tileN, int tileK,
            bool correctness) {
  const int warpSize = 32;
  const int resRows = m;
  const int resColumns = n;
  const int reductionSize = k;
  StringLiteral funcName = "kernel_matmul";
  MLIRContext context;
  ModelBuilder modelBuilder;

  auto typeA =
      modelBuilder.getMemRefType({resRows, reductionSize}, modelBuilder.i8);
  auto typeB =
      modelBuilder.getMemRefType({reductionSize, resColumns}, modelBuilder.i8);
  auto typeC = modelBuilder.getMemRefType({resRows, resColumns},
                                          modelBuilder.getI32Type());
  // 1. Build the kernel.
  {
    modelBuilder.addGPUAttr();
    FuncOp kernelFunc = modelBuilder.makeFunction(
        funcName, {}, {typeA, typeB, typeC}, MLIRFuncOpConfig());
    int workgroupSize = warpSize * numSubgroupX * numSubgroupY;
    // Right now we map one workgroup to one warp.
    kernelFunc.setAttr(
        spirv::getEntryPointABIAttrName(),
        spirv::getEntryPointABIAttr({workgroupSize, 1, 1}, &context));
    OpBuilder b(&kernelFunc.getBody());
    ScopedContext scope(b, kernelFunc.getLoc());

    auto A = kernelFunc.getArgument(0);
    auto B = kernelFunc.getArgument(1);
    auto C = kernelFunc.getArgument(2);

    linalg_matmul(TypeRange{}, ValueRange{A, B, C});
    std_ret();
  }

  // 2. Compile the function, pass in runtime support library to the execution
  // engine for vector.print.
  ModelRunner runner(modelBuilder.getModuleRef(),
                     ModelRunner::Target::GPUTarget);
  CompilationOptions options;
  options.loweringPasses = [&](mlir::PassManager &pm) {
    MatmulCodegenStrategy strategy;
    // Use hardcoded value for cooperative matrix size. Those will be pulled
    // from device properties eventually.
    const int cooperativeMatrixM = 16;
    const int cooperativeMatrixN = 16;
    const int cooperativeMatrixK = 32;

    linalg::LinalgLoopDistributionOptions WGDistribute;
    WGDistribute.distributionMethod = {
        linalg::DistributionMethod::CyclicNumProcsEqNumIters,
        linalg::DistributionMethod::CyclicNumProcsEqNumIters};
    WGDistribute.procInfo = getGpuProcIds<gpu::BlockIdOp, gpu::GridDimOp>;

    linalg::LinalgLoopDistributionOptions SGDistribute;
    SGDistribute.distributionMethod = {
        linalg::DistributionMethod::CyclicNumProcsEqNumIters,
        linalg::DistributionMethod::CyclicNumProcsEqNumIters};
    SGDistribute.procInfo = getSubgroupIds;

    // Swap the order of the parallel loops because PLoopToGPU pattern assigns
    // dimension in reverse order of the loop.
    strategy
        .tile<linalg::MatmulOp>(
            linalg::LinalgTilingOptions()
                .setLoopType(linalg::LinalgTilingLoopType::ParallelLoops)
                .setTileSizes({tileM, tileN, tileK})
                .setInterchange({1, 0, 2})
                .setDistributionOptions(WGDistribute))
        .setHoistInvariantCode(true);
    if (useWorkgroupMemory) {
      strategy
          .promote<linalg::MatmulOp>(
              linalg::LinalgPromotionOptions()
                  .setAllocationDeallocationFns(
                      mlir::iree_compiler::allocateWorkgroupMemory,
                      mlir::iree_compiler::deallocateWorkgroupMemory)
                  .setCopyInOutFns(mlir::iree_compiler::copyToWorkgroupMemory,
                                   mlir::iree_compiler::copyToWorkgroupMemory)
                  .setOperandsToPromote({0, 1})
                  .setUseFullTileBuffers({false, false}))
          .tile<linalg::MatmulOp>(
              linalg::LinalgTilingOptions()
                  .setLoopType(linalg::LinalgTilingLoopType::ParallelLoops)
                  .setTileSizes(
                      {tileM / numSubgroupX, tileN / numSubgroupY, tileK})
                  .setDistributionOptions(SGDistribute));
    }
    strategy.vectorize<linalg::MatmulOp>().unrollVector<vector::ContractionOp>(
        {cooperativeMatrixM, cooperativeMatrixN, cooperativeMatrixK});
    modelBuilder.getModuleRef()->walk(
        [&](FuncOp fn) { strategy.transform(fn); });
    addLoweringPasses(pm, {resRows / tileM, resColumns / tileN, 1},
                      {typeA, typeB, typeC});
  };
  runner.compile(options, {vulkanWrapper});

  // 3. Allocate data within data structures that interoperate with the MLIR ABI
  // conventions used by codegen.
  auto oneInit = [](unsigned idx, uint8_t *ptr) { ptr[idx] = 2 * idx + 1; };
  auto incInit = [](unsigned idx, uint8_t *ptr) { ptr[idx] = idx; };
  auto zeroInit = [](unsigned idx, uint32_t *ptr) { ptr[idx] = 0; };
  auto A = makeInitializedStridedMemRefDescriptor<uint8_t, 2>(
      {resRows, reductionSize}, oneInit);
  auto B = makeInitializedStridedMemRefDescriptor<uint8_t, 2>(
      {reductionSize, resColumns}, incInit);
  auto C = makeInitializedStridedMemRefDescriptor<uint32_t, 2>(
      {resRows, resColumns}, zeroInit);
  auto CPURes = makeInitializedStridedMemRefDescriptor<uint32_t, 2>(
      {resRows, resColumns}, zeroInit);

  // Is checking corretness compare to the value computed on CPU.
  if (correctness) {
    for (int i = 0; i < resRows; i++) {
      for (int j = 0; j < resColumns; j++) {
        uint32_t acc = (*C)[i][j];
        for (int k = 0; k < reductionSize; k++) {
          uint32_t a = (*A)[i][k];
          uint32_t b = (*B)[k][j];
          acc += a * b;
        }
        (*CPURes)[i][j] = acc;
      }
    }
  }

  // 4. Call the funcOp named `funcName`.
  auto err = runner.invoke(std::string(funcName) + "_wrapper", A, B, C);
  if (err) llvm_unreachable("Error running function.");

  if (correctness) {
    bool correct = true;
    for (int i = 0; i < resRows; i++) {
      for (int j = 0; j < resColumns; j++) {
        if ((*CPURes)[i][j] != (*C)[i][j]) {
          correct = false;
          printf("mismatch at index(%i, %i) was expecting %i but got %i\n", i,
                 j, (*CPURes)[i][j], (*C)[i][j]);
        }
      }
    }
    if (correct) printf("pass\n");
  }
}

int main(int argc, char **argv) {
  ModelBuilder::registerAllDialects();
  iree::Initializer::RunInitializers();
  // Allow LLVM setup through command line and parse the
  // test specific option for a runtime support library.
  llvm::InitLLVM y(argc, argv);
  llvm::cl::ParseCommandLineOptions(argc, argv, "BenchMatMulVectorGPU\n");
  int m = 4096;
  int n = 4096;
  int k = 4096;
  if (correctness) {
    m = 256;
    n = 256;
    k = 256;
  }
  printf("Matrix size: %ix%ix%i", m, n, k);
  for (int tileK = 32; tileK <= 64; tileK *= 2) {
    for (int tileM = 128; tileM <= 256; tileM *= 2) {
      for (int tileN = 128; tileN <= 256; tileN *= 2) {
        // Workgroup memory requires at least a tile size of 128x128 to be able
        // to do full speed copy from video memory to shared local memory.
        if (useWorkgroupMemory && (tileM < 128 || tileN < 128)) continue;
        printf("tileM=%i tileN=%i tileK=%i\n", tileM, tileN, tileK);
        // For non-power of two tile sizes, round up the matrix size to
        // be an even multiple of the tile size.
        // TODO(thomasraoux): enable non power of two tiles once affine.min
        // folding is fixed.
        auto paddedM = (m + tileM - 1) / tileM * tileM;
        auto paddedN = (n + tileN - 1) / tileN * tileN;
        auto paddedK = (k + tileK - 1) / tileK * tileK;

        matMul(paddedM, paddedN, paddedK, tileM, tileN, tileK, correctness);
      }
    }
  }
}
<commit_msg>Add control to enable LICM from command line and fix a bug (#2927)<commit_after>// Copyright 2020 Google LLC
//
// 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
//
//      https://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.
#include <string>

#include "experimental/ModelBuilder/ModelBuilder.h"
#include "experimental/ModelBuilder/ModelRunner.h"
#include "experimental/ModelBuilder/VulkanWrapperPass.h"
#include "iree/base/initializer.h"
#include "iree/compiler/Conversion/CodegenUtils/MatmulCodegenStrategy.h"
#include "iree/compiler/Conversion/LinalgToSPIRV/MemorySpace.h"
#include "iree/compiler/Conversion/LinalgToSPIRV/Passes.h"
#include "iree/compiler/Conversion/LinalgToSPIRV/Utils.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
#include "mlir/Conversion/GPUToVulkan/ConvertGPUToVulkanPass.h"
#include "mlir/Conversion/LinalgToLLVM/LinalgToLLVM.h"
#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVMPass.h"
#include "mlir/Conversion/StandardToSPIRV/ConvertStandardToSPIRVPass.h"
#include "mlir/Dialect/GPU/Passes.h"
#include "mlir/Dialect/Linalg/EDSC/Intrinsics.h"
#include "mlir/Dialect/Linalg/Passes.h"
#include "mlir/Dialect/Linalg/Transforms/Transforms.h"
#include "mlir/Dialect/SPIRV/Passes.h"
#include "mlir/Dialect/SPIRV/SPIRVOps.h"
#include "mlir/Dialect/SPIRV/TargetAndABI.h"
#include "mlir/Dialect/Vector/VectorOps.h"
#include "mlir/ExecutionEngine/CRunnerUtils.h"
#include "mlir/ExecutionEngine/RunnerUtils.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/OperationSupport.h"
#include "mlir/Parser.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Transforms/Passes.h"

using namespace mlir;                    // NOLINT
using namespace mlir::edsc;              // NOLINT
using namespace mlir::edsc::intrinsics;  // NOLINT

static llvm::cl::opt<std::string> vulkanWrapper(
    "vulkan-wrapper", llvm::cl::desc("Vulkan wrapper library"),
    llvm::cl::value_desc("filename"), llvm::cl::init("-"));

static llvm::cl::opt<bool> correctness(
    "correctness",
    llvm::cl::desc(
        "Compare the result to value calculated on CPU. We will use a smaller "
        "matrix multiply in this case to avoid long runtime."),
    llvm::cl::init(false));

static llvm::cl::opt<bool> useWorkgroupMemory(
    "use-workgroup-memory", llvm::cl::desc("Enable use of workgroup memory"),
    llvm::cl::value_desc("boolean"), llvm::cl::init(false));

static llvm::cl::opt<bool> enableLICM(
    "enable-licm",
    llvm::cl::desc("Enable loop invariant hoisting optimizations"),
    llvm::cl::value_desc("boolean"), llvm::cl::init(false));

static void addLoweringPasses(mlir::PassManager &pm,
                              llvm::ArrayRef<int64_t> numWorkgroups,
                              llvm::ArrayRef<Type> args) {
  pm.addPass(mlir::iree_compiler::createVectorToGPUPass());
  pm.addPass(mlir::createLowerAffinePass());
  pm.addPass(mlir::createLegalizeStdOpsForSPIRVLoweringPass());
  pm.addPass(mlir::createCanonicalizerPass());
  pm.addPass(mlir::createCSEPass());
  pm.addPass(mlir::iree_compiler::createConvertToSPIRVPass());

  auto &spirvModulePM = pm.nest<mlir::spirv::ModuleOp>();
  spirvModulePM.addPass(mlir::createSetSpirvABIPass());
  spirvModulePM.addPass(mlir::spirv::createLowerABIAttributesPass());
  spirvModulePM.addPass(mlir::createCanonicalizerPass());
  spirvModulePM.addPass(mlir::createCSEPass());
  spirvModulePM.addPass(
      mlir::spirv::createUpdateVersionCapabilityExtensionPass());

  pm.addPass(mlir::createAddVulkanLaunchWrapperPass(numWorkgroups, args));
  mlir::LowerToLLVMOptions llvmOptions = {
      /*useBarePtrCallConv=*/false,
      /*emitCWrappers=*/true,
      /*indexBitwidth=*/mlir::kDeriveIndexBitwidthFromDataLayout};
  pm.addPass(createLowerToLLVMPass(llvmOptions));
  pm.addPass(mlir::createConvertVulkanLaunchFuncToVulkanCallsPass());
}

static void insertBarrier(OpBuilder &b, Location loc) {
  b.create<spirv::ControlBarrierOp>(loc, spirv::Scope::Workgroup,
                                    spirv::Scope::Workgroup,
                                    spirv::MemorySemantics::AcquireRelease);
}

template <typename IdOp, typename NProcsOp>
static linalg::ProcInfo getGpuProcIds(OpBuilder &b, Location loc,
                                      unsigned loopNum) {
  Type indexType = b.getIndexType();
  switch (loopNum) {
    case 0:
      return {b.create<IdOp>(loc, indexType, b.getStringAttr("y")),
              b.create<NProcsOp>(loc, indexType, b.getStringAttr("y"))};
    case 1:
      return {b.create<IdOp>(loc, indexType, b.getStringAttr("x")),
              b.create<NProcsOp>(loc, indexType, b.getStringAttr("x"))};
    default:
      llvm_unreachable("test patterns handles only upto 2-level nested loops");
  }
  return {nullptr, nullptr};
}

constexpr int numSubgroupX = 2;
constexpr int numSubgroupY = 2;

static linalg::ProcInfo getSubgroupIds(OpBuilder &b, Location loc,
                                       unsigned loopNum) {
  Type indexType = b.getIndexType();
  Value sg = b.create<gpu::SubgroupIdOp>(loc, indexType);
  Value vSubgroupX = b.create<ConstantIndexOp>(loc, numSubgroupX);
  using namespace edsc::op;
  switch (loopNum) {
    case 0:
      return {sg % vSubgroupX, vSubgroupX};
    case 1: {
      Value vSubgroupY = b.create<ConstantIndexOp>(loc, numSubgroupY);
      Value sgdiv = b.create<SignedDivIOp>(loc, indexType, sg, vSubgroupX);
      return {sgdiv % vSubgroupY, vSubgroupY};
    }
    default:
      llvm_unreachable("test patterns handles only upto 2-level nested loops");
  }
  return {nullptr, nullptr};
}

void matMul(int m, int n, int k, int tileM, int tileN, int tileK,
            bool correctness) {
  const int warpSize = 32;
  const int resRows = m;
  const int resColumns = n;
  const int reductionSize = k;
  StringLiteral funcName = "kernel_matmul";
  MLIRContext context;
  ModelBuilder modelBuilder;

  auto typeA =
      modelBuilder.getMemRefType({resRows, reductionSize}, modelBuilder.i8);
  auto typeB =
      modelBuilder.getMemRefType({reductionSize, resColumns}, modelBuilder.i8);
  auto typeC = modelBuilder.getMemRefType({resRows, resColumns},
                                          modelBuilder.getI32Type());
  // 1. Build the kernel.
  {
    modelBuilder.addGPUAttr();
    FuncOp kernelFunc = modelBuilder.makeFunction(
        funcName, {}, {typeA, typeB, typeC}, MLIRFuncOpConfig());
    int workgroupSize = warpSize * numSubgroupX * numSubgroupY;
    // Right now we map one workgroup to one warp.
    kernelFunc.setAttr(
        spirv::getEntryPointABIAttrName(),
        spirv::getEntryPointABIAttr({workgroupSize, 1, 1}, &context));
    OpBuilder b(&kernelFunc.getBody());
    ScopedContext scope(b, kernelFunc.getLoc());

    auto A = kernelFunc.getArgument(0);
    auto B = kernelFunc.getArgument(1);
    auto C = kernelFunc.getArgument(2);

    linalg_matmul(TypeRange{}, ValueRange{A, B, C});
    std_ret();
  }

  // 2. Compile the function, pass in runtime support library to the execution
  // engine for vector.print.
  ModelRunner runner(modelBuilder.getModuleRef(),
                     ModelRunner::Target::GPUTarget);
  CompilationOptions options;
  options.loweringPasses = [&](mlir::PassManager &pm) {
    MatmulCodegenStrategy strategy;
    // Use hardcoded value for cooperative matrix size. Those will be pulled
    // from device properties eventually.
    const int cooperativeMatrixM = 16;
    const int cooperativeMatrixN = 16;
    const int cooperativeMatrixK = 32;

    linalg::LinalgLoopDistributionOptions WGDistribute;
    WGDistribute.distributionMethod = {
        linalg::DistributionMethod::CyclicNumProcsEqNumIters,
        linalg::DistributionMethod::CyclicNumProcsEqNumIters};
    WGDistribute.procInfo = getGpuProcIds<gpu::BlockIdOp, gpu::GridDimOp>;

    linalg::LinalgLoopDistributionOptions SGDistribute;
    SGDistribute.distributionMethod = {
        linalg::DistributionMethod::CyclicNumProcsEqNumIters,
        linalg::DistributionMethod::CyclicNumProcsEqNumIters};
    SGDistribute.procInfo = getSubgroupIds;

    // Swap the order of the parallel loops because PLoopToGPU pattern assigns
    // dimension in reverse order of the loop.
    strategy
        .tile<linalg::MatmulOp>(
            linalg::LinalgTilingOptions()
                .setLoopType(linalg::LinalgTilingLoopType::ParallelLoops)
                .setTileSizes({tileM, tileN, tileK})
                .setInterchange({1, 0, 2})
                .setDistributionOptions(WGDistribute))
        .setHoistInvariantCode(enableLICM);
    if (useWorkgroupMemory) {
      strategy
          .promote<linalg::MatmulOp>(
              linalg::LinalgPromotionOptions()
                  .setAllocationDeallocationFns(
                      mlir::iree_compiler::allocateWorkgroupMemory,
                      mlir::iree_compiler::deallocateWorkgroupMemory)
                  .setCopyInOutFns(mlir::iree_compiler::copyToWorkgroupMemory,
                                   mlir::iree_compiler::copyToWorkgroupMemory)
                  .setOperandsToPromote({0, 1})
                  .setUseFullTileBuffers({false, false}))
          .tile<linalg::MatmulOp>(
              linalg::LinalgTilingOptions()
                  .setLoopType(linalg::LinalgTilingLoopType::ParallelLoops)
                  .setTileSizes(
                      {tileM / numSubgroupX, tileN / numSubgroupY, tileK})
                  .setDistributionOptions(SGDistribute));
    }
    std::array<int64_t, 3> nativeSize = {cooperativeMatrixM, cooperativeMatrixN,
                                         cooperativeMatrixK};
    strategy.vectorize<linalg::MatmulOp>().unrollVector<vector::ContractionOp>(
        nativeSize);
    modelBuilder.getModuleRef()->walk(
        [&](FuncOp fn) { strategy.transform(fn); });
    addLoweringPasses(pm, {resRows / tileM, resColumns / tileN, 1},
                      {typeA, typeB, typeC});
  };
  runner.compile(options, {vulkanWrapper});

  // 3. Allocate data within data structures that interoperate with the MLIR ABI
  // conventions used by codegen.
  auto oneInit = [](unsigned idx, uint8_t *ptr) { ptr[idx] = 2 * idx + 1; };
  auto incInit = [](unsigned idx, uint8_t *ptr) { ptr[idx] = idx; };
  auto zeroInit = [](unsigned idx, uint32_t *ptr) { ptr[idx] = 0; };
  auto A = makeInitializedStridedMemRefDescriptor<uint8_t, 2>(
      {resRows, reductionSize}, oneInit);
  auto B = makeInitializedStridedMemRefDescriptor<uint8_t, 2>(
      {reductionSize, resColumns}, incInit);
  auto C = makeInitializedStridedMemRefDescriptor<uint32_t, 2>(
      {resRows, resColumns}, zeroInit);
  auto CPURes = makeInitializedStridedMemRefDescriptor<uint32_t, 2>(
      {resRows, resColumns}, zeroInit);

  // Is checking corretness compare to the value computed on CPU.
  if (correctness) {
    for (int i = 0; i < resRows; i++) {
      for (int j = 0; j < resColumns; j++) {
        uint32_t acc = (*C)[i][j];
        for (int k = 0; k < reductionSize; k++) {
          uint32_t a = (*A)[i][k];
          uint32_t b = (*B)[k][j];
          acc += a * b;
        }
        (*CPURes)[i][j] = acc;
      }
    }
  }

  // 4. Call the funcOp named `funcName`.
  auto err = runner.invoke(std::string(funcName) + "_wrapper", A, B, C);
  if (err) llvm_unreachable("Error running function.");

  if (correctness) {
    bool correct = true;
    for (int i = 0; i < resRows; i++) {
      for (int j = 0; j < resColumns; j++) {
        if ((*CPURes)[i][j] != (*C)[i][j]) {
          correct = false;
          printf("mismatch at index(%i, %i) was expecting %i but got %i\n", i,
                 j, (*CPURes)[i][j], (*C)[i][j]);
        }
      }
    }
    if (correct) printf("pass\n");
  }
}

int main(int argc, char **argv) {
  ModelBuilder::registerAllDialects();
  iree::Initializer::RunInitializers();
  // Allow LLVM setup through command line and parse the
  // test specific option for a runtime support library.
  llvm::InitLLVM y(argc, argv);
  llvm::cl::ParseCommandLineOptions(argc, argv, "BenchMatMulVectorGPU\n");
  int m = 4096;
  int n = 4096;
  int k = 4096;
  if (correctness) {
    m = 256;
    n = 256;
    k = 256;
  }
  printf("Matrix size: %ix%ix%i", m, n, k);
  for (int tileK = 32; tileK <= 64; tileK *= 2) {
    for (int tileM = 128; tileM <= 256; tileM *= 2) {
      for (int tileN = 128; tileN <= 256; tileN *= 2) {
        // Workgroup memory requires at least a tile size of 128x128 to be able
        // to do full speed copy from video memory to shared local memory.
        if (useWorkgroupMemory && (tileM < 128 || tileN < 128)) continue;
        printf("tileM=%i tileN=%i tileK=%i\n", tileM, tileN, tileK);
        // For non-power of two tile sizes, round up the matrix size to
        // be an even multiple of the tile size.
        // TODO(thomasraoux): enable non power of two tiles once affine.min
        // folding is fixed.
        auto paddedM = (m + tileM - 1) / tileM * tileM;
        auto paddedN = (n + tileN - 1) / tileN * tileN;
        auto paddedK = (k + tileK - 1) / tileK * tileK;

        matMul(paddedM, paddedN, paddedK, tileM, tileN, tileK, correctness);
      }
    }
  }
}
<|endoftext|>


<commit_before>#include <queue>
#include <iostream>
#include "nfa.h"
#include "utils.cpp"

string error_message = "NFA Creation Error : ";

void verify_state_set(const set<string>& states, const set<string>& state_set) {

    set<string>::const_iterator it;
    for (it = state_set.begin(); it != state_set.end(); ++it) {
        if(!states.count(*it))
            throw error_message + "State '" + *it + "' does not belong to Q!";
    }
}

void verify_states(set<string> states, set<string> initial, set<string> final) {
    if(initial.size() != 1)
        throw error_message + "There should be one and only one initial state!";

    if(final.size() < 1 || final.size() > states.size() )
        throw error_message + "Final states should be between 1 and total number of states!";

    // Verify if all the states in initial and final belong to state vector

    if (!states.count(*initial.begin()))
        throw error_message + "Initial state '" + *initial.begin() + "' does not belong to Q!";

    try {
        verify_state_set(states, final);
    } catch (const string& message) {
        cout << "Invalid Final State!" << endl;
        throw;
    }
}

void nfa::set_states(const set<string> &states, const set<string> &initial, const set<string> &final) {
    verify_states(states, initial, final);

    this->states = states;
    this->final = final;
    this->initial = *initial.begin();
}

void nfa::set_alphabet(const set<string> &alphabet) {
    if(alphabet.count("e"))
        throw "NFA Parse Error : Language alphabet 'e' clashes with keyword for epsilon!";

    this->alphabet = alphabet;
}

void nfa::add_transition(const string& current_state, const string& alphabet, const set<string>& result) {
    verify_state_set(states, result);
    transitions[make_pair(current_state, alphabet)] = result;
}

const set<string> nfa::get_states(const string& state, const string& alphabet) {
    pair<string, string> key = make_pair(state, alphabet);
    if(!transitions.count(key))
        throw "NFA Error : Invalid Transition!";

    return transitions[key];
}

const set<string> nfa::get_states(const set<string> &states, const string &alphabet) {
    set<string> compound_states;

    set<string>::const_iterator it;
    for(it = states.begin(); it != states.end(); ++it) {
        set<string> out_state = get_states(*it, alphabet);
        compound_states.insert(out_state.begin(), out_state.end());
    }

    return compound_states;
}

const set<string> nfa::get_epsilon_closure(const string &state) {
    set<string> key;
    key.insert(state);

    if(epsilon_closures.count(key))
        return epsilon_closures[key];

    set<string> epsilon_states;

    queue<string> remaining;
    remaining.push(state);

    while (!remaining.empty()) {
        string current = remaining.front();

        epsilon_states.insert(current);

        set<string> epsilon_moves = get_states(current, "e");
        set<string>::const_iterator it;
        for(it = epsilon_moves.begin(); it != epsilon_moves.end(); ++it) {
            if(!epsilon_states.count(*it))
                remaining.push(*it);
        }

        remaining.pop();
    }

    epsilon_closures[key] = epsilon_states;

    return epsilon_states;
}

const set<string> nfa::get_epsilon_closure(const set<string> &states) {
    if (epsilon_closures.count(states))
        return epsilon_closures[states];

    set<string> epsilon_states;

    set<string>::const_iterator it;
    for(it = states.begin(); it != states.end(); ++it) {
        set<string> current_states = get_epsilon_closure(*it);
        epsilon_states.insert(current_states.begin(), current_states.end());
    }

    epsilon_closures[states] = epsilon_states;

    return epsilon_states;
}

bool nfa::is_final(const set<string> &states) {
    set<string>::const_iterator it;

    for(it = states.begin(); it != states.end(); ++it) {
        if(contains(final, *it))
            return true;
    }

    return false;
}

void nfa::to_dfa() {
    cout << "DFA Conversion : \n" << endl;
    set<string> initial = get_epsilon_closure(this->initial);

    queue< set<string> > remaining;
    remaining.push(initial);

    vector< set<string> > dfa_states;

    set<string>::const_iterator it;

    while(!remaining.empty()) {
        set<string> current = remaining.front();
        remaining.pop();

        if(contains(dfa_states, current))
            continue;

        cout << "For state : { " << to_string(current, ',') << " }" << endl;
        for (it = alphabet.begin(); it != alphabet.end(); ++it) {
            set<string> epsilon_state = get_epsilon_closure(get_states(current, *it));
            cout << "    " << *it << " -> { " << to_string(epsilon_state, ',') << " }" << endl;

            if (!contains(dfa_states, epsilon_state))
                remaining.push(epsilon_state);
        }

        dfa_states.push_back(current);
        cout << endl;
    }

    cout << "\nFinal States : " << endl;
    for (int i = 0; i < dfa_states.size(); ++i) {
        set<string> current = dfa_states[i];

        if(is_final(current))
            cout << "{ " << to_string(current, ',') << " }" << endl;
    }

}

const string get_transition_string(const map< pair<string, string>, set<string> > m) {
    string output;
    map< pair<string, string>, set<string> >::const_iterator it;

    for(it = m.begin(); it != m.end(); ++it) {
        output += "(" + it->first.first + ", " + it->first.second + ") -> { " + to_string(it->second) + " }\n";
    }

    return output;
}

string nfa::tostring() {
    return "Alphabet:\n" +
            to_string(alphabet) +
            "\nStates:\n" +
            to_string(states) +
            "\nInitial State : \n" +
            initial +
            "\nFinal States:\n" +
            to_string(final) +
            "\nTransitions:\n" +
            get_transition_string(transitions);
}<commit_msg>Removed phi state from possible DFA State and printed Initial state<commit_after>#include <queue>
#include <iostream>
#include "nfa.h"
#include "utils.cpp"

string error_message = "NFA Creation Error : ";

void verify_state_set(const set<string>& states, const set<string>& state_set) {

    set<string>::const_iterator it;
    for (it = state_set.begin(); it != state_set.end(); ++it) {
        if(!states.count(*it))
            throw error_message + "State '" + *it + "' does not belong to Q!";
    }
}

void verify_states(set<string> states, set<string> initial, set<string> final) {
    if(initial.size() != 1)
        throw error_message + "There should be one and only one initial state!";

    if(final.size() < 1 || final.size() > states.size() )
        throw error_message + "Final states should be between 1 and total number of states!";

    // Verify if all the states in initial and final belong to state vector

    if (!states.count(*initial.begin()))
        throw error_message + "Initial state '" + *initial.begin() + "' does not belong to Q!";

    try {
        verify_state_set(states, final);
    } catch (const string& message) {
        cout << "Invalid Final State!" << endl;
        throw;
    }
}

void nfa::set_states(const set<string> &states, const set<string> &initial, const set<string> &final) {
    verify_states(states, initial, final);

    this->states = states;
    this->final = final;
    this->initial = *initial.begin();
}

void nfa::set_alphabet(const set<string> &alphabet) {
    if(alphabet.count("e"))
        throw "NFA Parse Error : Language alphabet 'e' clashes with keyword for epsilon!";

    this->alphabet = alphabet;
}

void nfa::add_transition(const string& current_state, const string& alphabet, const set<string>& result) {
    verify_state_set(states, result);
    transitions[make_pair(current_state, alphabet)] = result;
}

const set<string> nfa::get_states(const string& state, const string& alphabet) {
    pair<string, string> key = make_pair(state, alphabet);
    if(!transitions.count(key))
        throw "NFA Error : Invalid Transition!";

    return transitions[key];
}

const set<string> nfa::get_states(const set<string> &states, const string &alphabet) {
    set<string> compound_states;

    set<string>::const_iterator it;
    for(it = states.begin(); it != states.end(); ++it) {
        set<string> out_state = get_states(*it, alphabet);
        compound_states.insert(out_state.begin(), out_state.end());
    }

    return compound_states;
}

const set<string> nfa::get_epsilon_closure(const string &state) {
    set<string> key;
    key.insert(state);

    if(epsilon_closures.count(key))
        return epsilon_closures[key];

    set<string> epsilon_states;

    queue<string> remaining;
    remaining.push(state);

    while (!remaining.empty()) {
        string current = remaining.front();

        epsilon_states.insert(current);

        set<string> epsilon_moves = get_states(current, "e");
        set<string>::const_iterator it;
        for(it = epsilon_moves.begin(); it != epsilon_moves.end(); ++it) {
            if(!epsilon_states.count(*it))
                remaining.push(*it);
        }

        remaining.pop();
    }

    epsilon_closures[key] = epsilon_states;

    return epsilon_states;
}

const set<string> nfa::get_epsilon_closure(const set<string> &states) {
    if (epsilon_closures.count(states))
        return epsilon_closures[states];

    set<string> epsilon_states;

    set<string>::const_iterator it;
    for(it = states.begin(); it != states.end(); ++it) {
        set<string> current_states = get_epsilon_closure(*it);
        epsilon_states.insert(current_states.begin(), current_states.end());
    }

    epsilon_closures[states] = epsilon_states;

    return epsilon_states;
}

bool nfa::is_final(const set<string> &states) {
    set<string>::const_iterator it;

    for(it = states.begin(); it != states.end(); ++it) {
        if(contains(final, *it))
            return true;
    }

    return false;
}

void nfa::to_dfa() {
    cout << "DFA Conversion : \n" << endl;
    set<string> initial = get_epsilon_closure(this->initial);

    queue< set<string> > remaining;
    remaining.push(initial);

    vector< set<string> > dfa_states;

    set<string>::const_iterator it;

    while(!remaining.empty()) {
        set<string> current = remaining.front();
        remaining.pop();

        if(contains(dfa_states, current))
            continue;

        cout << "For state : { " << to_string(current, ',') << " }" << endl;
        for (it = alphabet.begin(); it != alphabet.end(); ++it) {
            set<string> epsilon_state = get_epsilon_closure(get_states(current, *it));
            cout << "    " << *it << " -> { " << to_string(epsilon_state, ',') << " }" << endl;

            if (!contains(dfa_states, epsilon_state) && !epsilon_state.empty())
                remaining.push(epsilon_state);
        }

        dfa_states.push_back(current);
        cout << endl;
    }

    cout << "\nInitial State : " << endl;
    cout << "{ " << to_string(dfa_states[0], ',') << " }" << endl;

    cout << "Final States : " << endl;
    for (int i = 0; i < dfa_states.size(); ++i) {
        set<string> current = dfa_states[i];

        if(is_final(current))
            cout << "{ " << to_string(current, ',') << " }" << endl;
    }

}

const string get_transition_string(const map< pair<string, string>, set<string> > m) {
    string output;
    map< pair<string, string>, set<string> >::const_iterator it;

    for(it = m.begin(); it != m.end(); ++it) {
        output += "(" + it->first.first + ", " + it->first.second + ") -> { " + to_string(it->second) + " }\n";
    }

    return output;
}

string nfa::tostring() {
    return "Alphabet:\n" +
            to_string(alphabet) +
            "\nStates:\n" +
            to_string(states) +
            "\nInitial State : \n" +
            initial +
            "\nFinal States:\n" +
            to_string(final) +
            "\nTransitions:\n" +
            get_transition_string(transitions);
}<|endoftext|>


<commit_before>#include "ofxFaceTracker.h"

using namespace ofxCv;
using namespace cv;
using namespace FACETRACKER;

// can be compiled with OpenMP for even faster threaded execution

#define it at<int>
#define db at<double>

vector<int> consecutive(int start, int end) {
	int n = end - start;
	vector<int> result(n);
	for(int i = 0; i < n; i++) {
		result[i] = start + i;
	}
	return result;
}

vector<int> ofxFaceTracker::getFeatureIndices(Feature feature) {
	switch(feature) {
		case LEFT_JAW: return consecutive(0, 9);
		case RIGHT_JAW: return consecutive(8, 17);
		case JAW: return consecutive(0, 17);
		case LEFT_EYEBROW: return consecutive(17, 22);
		case RIGHT_EYEBROW: return consecutive(22, 27);
		case LEFT_EYE: return consecutive(36, 42);
		case RIGHT_EYE: return consecutive(42, 48);
		case OUTER_MOUTH: return consecutive(48, 60);
		case INNER_MOUTH:
			static int innerMouth[] = {48,60,61,62,54,63,64,65};
			return vector<int>(innerMouth, innerMouth + 8);
		case NOSE_BRIDGE: return consecutive(27, 31);
		case NOSE_BASE: return consecutive(31, 36);
		case FACE_OUTLINE:
			static int faceOutline[] = {17,18,19,20,21,22,23,24,25,26, 16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
			return vector<int>(faceOutline, faceOutline + 27);
		case ALL_FEATURES: return consecutive(0, 66);
	}
}

ofxFaceTracker::ofxFaceTracker()
:rescale(1)
,iterations(10) // [1-25] 1 is fast and inaccurate, 25 is slow and accurate
,clamp(3) // [0-4] 1 gives a very loose fit, 4 gives a very tight fit
,tolerance(.01) // [.01-1] match tolerance
,attempts(1) // [1-4] 1 is fast and may not find faces, 4 is slow but will find faces
,failed(true)
,fcheck(true) // check for whether the tracking failed
,frameSkip(-1) // how often to skip frames
,useInvisible(true)
,age(-1)
{
}

void ofxFaceTracker::setup() {
	wSize1.resize(1);
	wSize1[0] = 7;

	wSize2.resize(3);
	wSize2[0] = 11;
	wSize2[1] = 9;
	wSize2[2] = 7;

	string ftFile = ofToDataPath("model/face2.tracker");
	string triFile = ofToDataPath("model/face.tri");
	string conFile = ofToDataPath("model/face.con");

	tracker.Load(ftFile.c_str());
	tri = IO::LoadTri(triFile.c_str());
	con = IO::LoadCon(conFile.c_str());  // not being used right now
}

bool ofxFaceTracker::update(Mat image) {
	if(rescale == 1) {
		im = image;
	} else {
		resize(image, im, cv::Size(rescale * image.cols, rescale * image.rows));
	}

	cvtColor(im, gray, CV_RGB2GRAY);

	bool tryAgain = true;
	for(int i = 0; tryAgain && i < attempts; i++) {
		vector<int> wSize;
		if(failed) {
			wSize = wSize2;
		} else {
			wSize = wSize1;
		}

		if(tracker.Track(gray, wSize, frameSkip, iterations, clamp, tolerance, fcheck) == 0) {
			currentView = tracker._clm.GetViewIdx();
			failed = false;
			age++;
			tryAgain = false;
			updateObjectPoints();
		} else {
			tracker.FrameReset();
			failed = true;
			age = -1;
		}
	}
	return !failed;
}

void ofxFaceTracker::draw(bool drawLabels) const{
	if(failed) {
		return;
	}

	ofPushStyle();
	ofNoFill();
	getImageFeature(LEFT_EYE).draw();
	getImageFeature(RIGHT_EYE).draw();
	getImageFeature(LEFT_EYEBROW).draw();
	getImageFeature(RIGHT_EYEBROW).draw();
	getImageFeature(NOSE_BRIDGE).draw();
	getImageFeature(NOSE_BASE).draw();
	getImageFeature(INNER_MOUTH).draw();
	getImageFeature(OUTER_MOUTH).draw();
	getImageFeature(JAW).draw();
	ofPopStyle();

	if(drawLabels) {
		int n = size();
		for(int i = 0; i < n; i++){
			if(getVisibility(i)) {
				ofDrawBitmapString(ofToString(i), getImagePoint(i));
			}
		}
	}
}

void ofxFaceTracker::reset() {
	tracker.FrameReset();
}

int ofxFaceTracker::size() const {
	return tracker._shape.rows / 2;
}

bool ofxFaceTracker::getFound() const {
	return !failed;
}

int ofxFaceTracker::getAge() const {
	return age;
}

bool ofxFaceTracker::getVisibility(int i) const {
	if(failed) {
		return false;
	}
	const Mat& visi = tracker._clm._visi[currentView];
	return (visi.it(i, 0) != 0);
}

vector<ofVec2f> ofxFaceTracker::getImagePoints() const {
	int n = size();
	vector<ofVec2f> imagePoints(n);
	for(int i = 0; i < n; i++) {
		imagePoints[i] = getImagePoint(i);
	}
	return imagePoints;
}

vector<ofVec3f> ofxFaceTracker::getObjectPoints() const {
	int n = size();
	vector<ofVec3f> objectPoints(n);
	for(int i = 0; i < n; i++) {
		objectPoints[i] = getObjectPoint(i);
	}
	return objectPoints;
}

vector<ofVec3f> ofxFaceTracker::getMeanObjectPoints() const {
	int n = size();
	vector<ofVec3f> meanObjectPoints(n);
	for(int i = 0; i < n; i++) {
		meanObjectPoints[i] = getMeanObjectPoint(i);
	}
	return meanObjectPoints;
}

ofVec2f ofxFaceTracker::getImagePoint(int i) const {
	if(failed) {
		return ofVec2f();
	}
	const Mat& shape = tracker._shape;
	int n = shape.rows / 2;
	return ofVec2f(shape.db(i, 0), shape.db(i + n, 0)) / rescale;
}

ofVec3f ofxFaceTracker::getObjectPoint(int i) const {
	if(failed) {
		return ofVec3f();
	}
	int n = objectPoints.rows / 3;
	return ofVec3f(objectPoints.db(i,0), objectPoints.db(i+n,0), objectPoints.db(i+n+n,0));
}

ofVec3f ofxFaceTracker::getMeanObjectPoint(int i) const {
	const Mat& mean = tracker._clm._pdm._M;
	int n = mean.rows / 3;
	return ofVec3f(mean.db(i,0), mean.db(i+n,0), mean.db(i+n+n,0));
}

ofMesh ofxFaceTracker::getImageMesh() const{
	return getMesh(getImagePoints());
}

ofMesh ofxFaceTracker::getObjectMesh() const {
	return getMesh(getObjectPoints());
}

ofMesh ofxFaceTracker::getMeanObjectMesh() const {
	return getMesh(getMeanObjectPoints());
}

const Mat& ofxFaceTracker::getObjectPointsMat() const {
	return objectPoints;
}

ofVec2f ofxFaceTracker::getPosition() const {
	const Mat& pose = tracker._clm._pglobl;
	return ofVec2f(pose.db(4,0), pose.db(5,0)) / rescale;
}

 // multiply by ~20-23 to get pixel units (+/-20 units in the x axis, +23/-18 on the y axis)
float ofxFaceTracker::getScale() const {
	const Mat& pose = tracker._clm._pglobl;
	return pose.db(0,0) / rescale;
}

ofVec3f ofxFaceTracker::getOrientation() const {
	const Mat& pose = tracker._clm._pglobl;
	ofVec3f euler(pose.db(1, 0), pose.db(2, 0), pose.db(3, 0));
	return euler;
}

ofMatrix4x4 ofxFaceTracker::getRotationMatrix() const {
	ofVec3f euler = getOrientation();
	ofMatrix4x4 matrix;
	matrix.makeRotationMatrix(ofRadToDeg(euler.x), ofVec3f(1,0,0),
														ofRadToDeg(euler.y), ofVec3f(0,1,0),
														ofRadToDeg(euler.z), ofVec3f(0,0,1));
														return matrix;
}

ofxFaceTracker::Direction ofxFaceTracker::getDirection() const {
	if(failed) {
		return FACING_UNKNOWN;
	}
	switch(currentView) {
		case 0: return FACING_FORWARD;
		case 1: return FACING_LEFT;
		case 2: return FACING_RIGHT;
	}
}

ofPolyline ofxFaceTracker::getImageFeature(Feature feature) const {
	return getFeature(feature, getImagePoints());
}

ofPolyline ofxFaceTracker::getObjectFeature(Feature feature) const {
	return getFeature(feature, getObjectPoints());
}

ofPolyline ofxFaceTracker::getMeanObjectFeature(Feature feature) const {
	return getFeature(feature, getMeanObjectPoints());
}

float ofxFaceTracker::getGesture(Gesture gesture) const {
	if(failed) {
		return 0;
	}
	int start = 0, end = 0;
	switch(gesture) {
		// left to right of mouth
		case MOUTH_WIDTH: start = 48; end = 54; break;
		 // top to bottom of inner mouth
		case MOUTH_HEIGHT: start = 61; end = 64; break;
		// center of the eye to middle of eyebrow
		case LEFT_EYEBROW_HEIGHT: start = 38; end = 20; break;
		// center of the eye to middle of eyebrow
		case RIGHT_EYEBROW_HEIGHT: start = 43; end = 23; break;
		// upper inner eye to lower outer eye
		case LEFT_EYE_OPENNESS: start = 38; end = 41; break;
		// upper inner eye to lower outer eye
		case RIGHT_EYE_OPENNESS: start = 43; end = 46; break;
		// nose center to chin center
		case JAW_OPENNESS: start = 33; end = 8; break;
		// left side of nose to right side of nose
		case NOSTRIL_FLARE: start = 31; end = 35; break;
	}

	return (getObjectPoint(start) - getObjectPoint(end)).length();
}

void ofxFaceTracker::setRescale(float rescale) {
	this->rescale = rescale;
}

void ofxFaceTracker::setIterations(int iterations) {
	this->iterations = iterations;
}

void ofxFaceTracker::setClamp(float clamp) {
	this->clamp = clamp;
}

void ofxFaceTracker::setTolerance(float tolerance) {
	this->tolerance = tolerance;
}

void ofxFaceTracker::setAttempts(int attempts) {
	this->attempts = attempts;
}

void ofxFaceTracker::setUseInvisible(bool useInvisible) {
	this->useInvisible = useInvisible;
}

void ofxFaceTracker::updateObjectPoints() {
	const Mat& mean = tracker._clm._pdm._M;
	const Mat& variation = tracker._clm._pdm._V;
	const Mat& weights = tracker._clm._plocal;
	objectPoints = mean + variation * weights;
}

void ofxFaceTracker::addTriangleIndices(ofMesh& mesh) const {
	int in = tri.rows;
	for(int i = 0; i < tri.rows; i++) {
		int i0 = tri.it(i, 0), i1 = tri.it(i, 1), i2 = tri.it(i, 2);
		bool visible = getVisibility(i0) && getVisibility(i1) && getVisibility(i2);
		if(useInvisible || visible) {
			mesh.addIndex(i0);
			mesh.addIndex(i1);
			mesh.addIndex(i2);
		}
	}
}
<commit_msg>i think this closes #27<commit_after>#include "ofxFaceTracker.h"

using namespace ofxCv;
using namespace cv;
using namespace FACETRACKER;

// can be compiled with OpenMP for even faster threaded execution

#define it at<int>
#define db at<double>

vector<int> consecutive(int start, int end) {
	int n = end - start;
	vector<int> result(n);
	for(int i = 0; i < n; i++) {
		result[i] = start + i;
	}
	return result;
}

vector<int> ofxFaceTracker::getFeatureIndices(Feature feature) {
	switch(feature) {
		case LEFT_JAW: return consecutive(0, 9);
		case RIGHT_JAW: return consecutive(8, 17);
		case JAW: return consecutive(0, 17);
		case LEFT_EYEBROW: return consecutive(17, 22);
		case RIGHT_EYEBROW: return consecutive(22, 27);
		case LEFT_EYE: return consecutive(36, 42);
		case RIGHT_EYE: return consecutive(42, 48);
		case OUTER_MOUTH: return consecutive(48, 60);
		case INNER_MOUTH: {
			static int innerMouth[] = {48,60,61,62,54,63,64,65};
			return vector<int>(innerMouth, innerMouth + 8);
		}
		case NOSE_BRIDGE: return consecutive(27, 31);
		case NOSE_BASE: return consecutive(31, 36);
		case FACE_OUTLINE: {
			static int faceOutline[] = {17,18,19,20,21,22,23,24,25,26, 16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0};
			return vector<int>(faceOutline, faceOutline + 27);
		}
		case ALL_FEATURES: return consecutive(0, 66);
	}
}

ofxFaceTracker::ofxFaceTracker()
:rescale(1)
,iterations(10) // [1-25] 1 is fast and inaccurate, 25 is slow and accurate
,clamp(3) // [0-4] 1 gives a very loose fit, 4 gives a very tight fit
,tolerance(.01) // [.01-1] match tolerance
,attempts(1) // [1-4] 1 is fast and may not find faces, 4 is slow but will find faces
,failed(true)
,fcheck(true) // check for whether the tracking failed
,frameSkip(-1) // how often to skip frames
,useInvisible(true)
,age(-1)
{
}

void ofxFaceTracker::setup() {
	wSize1.resize(1);
	wSize1[0] = 7;

	wSize2.resize(3);
	wSize2[0] = 11;
	wSize2[1] = 9;
	wSize2[2] = 7;

	string ftFile = ofToDataPath("model/face2.tracker");
	string triFile = ofToDataPath("model/face.tri");
	string conFile = ofToDataPath("model/face.con");

	tracker.Load(ftFile.c_str());
	tri = IO::LoadTri(triFile.c_str());
	con = IO::LoadCon(conFile.c_str());  // not being used right now
}

bool ofxFaceTracker::update(Mat image) {
	if(rescale == 1) {
		im = image;
	} else {
		resize(image, im, cv::Size(rescale * image.cols, rescale * image.rows));
	}

	cvtColor(im, gray, CV_RGB2GRAY);

	bool tryAgain = true;
	for(int i = 0; tryAgain && i < attempts; i++) {
		vector<int> wSize;
		if(failed) {
			wSize = wSize2;
		} else {
			wSize = wSize1;
		}

		if(tracker.Track(gray, wSize, frameSkip, iterations, clamp, tolerance, fcheck) == 0) {
			currentView = tracker._clm.GetViewIdx();
			failed = false;
			age++;
			tryAgain = false;
			updateObjectPoints();
		} else {
			tracker.FrameReset();
			failed = true;
			age = -1;
		}
	}
	return !failed;
}

void ofxFaceTracker::draw(bool drawLabels) const{
	if(failed) {
		return;
	}

	ofPushStyle();
	ofNoFill();
	getImageFeature(LEFT_EYE).draw();
	getImageFeature(RIGHT_EYE).draw();
	getImageFeature(LEFT_EYEBROW).draw();
	getImageFeature(RIGHT_EYEBROW).draw();
	getImageFeature(NOSE_BRIDGE).draw();
	getImageFeature(NOSE_BASE).draw();
	getImageFeature(INNER_MOUTH).draw();
	getImageFeature(OUTER_MOUTH).draw();
	getImageFeature(JAW).draw();
	ofPopStyle();

	if(drawLabels) {
		int n = size();
		for(int i = 0; i < n; i++){
			if(getVisibility(i)) {
				ofDrawBitmapString(ofToString(i), getImagePoint(i));
			}
		}
	}
}

void ofxFaceTracker::reset() {
	tracker.FrameReset();
}

int ofxFaceTracker::size() const {
	return tracker._shape.rows / 2;
}

bool ofxFaceTracker::getFound() const {
	return !failed;
}

int ofxFaceTracker::getAge() const {
	return age;
}

bool ofxFaceTracker::getVisibility(int i) const {
	if(failed) {
		return false;
	}
	const Mat& visi = tracker._clm._visi[currentView];
	return (visi.it(i, 0) != 0);
}

vector<ofVec2f> ofxFaceTracker::getImagePoints() const {
	int n = size();
	vector<ofVec2f> imagePoints(n);
	for(int i = 0; i < n; i++) {
		imagePoints[i] = getImagePoint(i);
	}
	return imagePoints;
}

vector<ofVec3f> ofxFaceTracker::getObjectPoints() const {
	int n = size();
	vector<ofVec3f> objectPoints(n);
	for(int i = 0; i < n; i++) {
		objectPoints[i] = getObjectPoint(i);
	}
	return objectPoints;
}

vector<ofVec3f> ofxFaceTracker::getMeanObjectPoints() const {
	int n = size();
	vector<ofVec3f> meanObjectPoints(n);
	for(int i = 0; i < n; i++) {
		meanObjectPoints[i] = getMeanObjectPoint(i);
	}
	return meanObjectPoints;
}

ofVec2f ofxFaceTracker::getImagePoint(int i) const {
	if(failed) {
		return ofVec2f();
	}
	const Mat& shape = tracker._shape;
	int n = shape.rows / 2;
	return ofVec2f(shape.db(i, 0), shape.db(i + n, 0)) / rescale;
}

ofVec3f ofxFaceTracker::getObjectPoint(int i) const {
	if(failed) {
		return ofVec3f();
	}
	int n = objectPoints.rows / 3;
	return ofVec3f(objectPoints.db(i,0), objectPoints.db(i+n,0), objectPoints.db(i+n+n,0));
}

ofVec3f ofxFaceTracker::getMeanObjectPoint(int i) const {
	const Mat& mean = tracker._clm._pdm._M;
	int n = mean.rows / 3;
	return ofVec3f(mean.db(i,0), mean.db(i+n,0), mean.db(i+n+n,0));
}

ofMesh ofxFaceTracker::getImageMesh() const{
	return getMesh(getImagePoints());
}

ofMesh ofxFaceTracker::getObjectMesh() const {
	return getMesh(getObjectPoints());
}

ofMesh ofxFaceTracker::getMeanObjectMesh() const {
	return getMesh(getMeanObjectPoints());
}

const Mat& ofxFaceTracker::getObjectPointsMat() const {
	return objectPoints;
}

ofVec2f ofxFaceTracker::getPosition() const {
	const Mat& pose = tracker._clm._pglobl;
	return ofVec2f(pose.db(4,0), pose.db(5,0)) / rescale;
}

 // multiply by ~20-23 to get pixel units (+/-20 units in the x axis, +23/-18 on the y axis)
float ofxFaceTracker::getScale() const {
	const Mat& pose = tracker._clm._pglobl;
	return pose.db(0,0) / rescale;
}

ofVec3f ofxFaceTracker::getOrientation() const {
	const Mat& pose = tracker._clm._pglobl;
	ofVec3f euler(pose.db(1, 0), pose.db(2, 0), pose.db(3, 0));
	return euler;
}

ofMatrix4x4 ofxFaceTracker::getRotationMatrix() const {
	ofVec3f euler = getOrientation();
	ofMatrix4x4 matrix;
	matrix.makeRotationMatrix(ofRadToDeg(euler.x), ofVec3f(1,0,0),
														ofRadToDeg(euler.y), ofVec3f(0,1,0),
														ofRadToDeg(euler.z), ofVec3f(0,0,1));
														return matrix;
}

ofxFaceTracker::Direction ofxFaceTracker::getDirection() const {
	if(failed) {
		return FACING_UNKNOWN;
	}
	switch(currentView) {
		case 0: return FACING_FORWARD;
		case 1: return FACING_LEFT;
		case 2: return FACING_RIGHT;
	}
}

ofPolyline ofxFaceTracker::getImageFeature(Feature feature) const {
	return getFeature(feature, getImagePoints());
}

ofPolyline ofxFaceTracker::getObjectFeature(Feature feature) const {
	return getFeature(feature, getObjectPoints());
}

ofPolyline ofxFaceTracker::getMeanObjectFeature(Feature feature) const {
	return getFeature(feature, getMeanObjectPoints());
}

float ofxFaceTracker::getGesture(Gesture gesture) const {
	if(failed) {
		return 0;
	}
	int start = 0, end = 0;
	switch(gesture) {
		// left to right of mouth
		case MOUTH_WIDTH: start = 48; end = 54; break;
		 // top to bottom of inner mouth
		case MOUTH_HEIGHT: start = 61; end = 64; break;
		// center of the eye to middle of eyebrow
		case LEFT_EYEBROW_HEIGHT: start = 38; end = 20; break;
		// center of the eye to middle of eyebrow
		case RIGHT_EYEBROW_HEIGHT: start = 43; end = 23; break;
		// upper inner eye to lower outer eye
		case LEFT_EYE_OPENNESS: start = 38; end = 41; break;
		// upper inner eye to lower outer eye
		case RIGHT_EYE_OPENNESS: start = 43; end = 46; break;
		// nose center to chin center
		case JAW_OPENNESS: start = 33; end = 8; break;
		// left side of nose to right side of nose
		case NOSTRIL_FLARE: start = 31; end = 35; break;
	}

	return (getObjectPoint(start) - getObjectPoint(end)).length();
}

void ofxFaceTracker::setRescale(float rescale) {
	this->rescale = rescale;
}

void ofxFaceTracker::setIterations(int iterations) {
	this->iterations = iterations;
}

void ofxFaceTracker::setClamp(float clamp) {
	this->clamp = clamp;
}

void ofxFaceTracker::setTolerance(float tolerance) {
	this->tolerance = tolerance;
}

void ofxFaceTracker::setAttempts(int attempts) {
	this->attempts = attempts;
}

void ofxFaceTracker::setUseInvisible(bool useInvisible) {
	this->useInvisible = useInvisible;
}

void ofxFaceTracker::updateObjectPoints() {
	const Mat& mean = tracker._clm._pdm._M;
	const Mat& variation = tracker._clm._pdm._V;
	const Mat& weights = tracker._clm._plocal;
	objectPoints = mean + variation * weights;
}

void ofxFaceTracker::addTriangleIndices(ofMesh& mesh) const {
	int in = tri.rows;
	for(int i = 0; i < tri.rows; i++) {
		int i0 = tri.it(i, 0), i1 = tri.it(i, 1), i2 = tri.it(i, 2);
		bool visible = getVisibility(i0) && getVisibility(i1) && getVisibility(i2);
		if(useInvisible || visible) {
			mesh.addIndex(i0);
			mesh.addIndex(i1);
			mesh.addIndex(i2);
		}
	}
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "assert.hpp"
#include "Variable.hpp"

#include "mtac/ConstantPropagationProblem.hpp"

using namespace eddic;

typedef mtac::ConstantPropagationProblem::ProblemDomain ProblemDomain;

ProblemDomain mtac::ConstantPropagationProblem::meet(ProblemDomain& in, ProblemDomain& out){
    auto result = mtac::intersection_meet(in, out);

    //Remove all the temporary
    for(auto it = std::begin(result.values()); it != std::end(result.values());){
        if(auto* ptr = boost::get<std::shared_ptr<Variable>>(&it->second)){
            auto variable = *ptr;

            if (variable->position().isTemporary()){
                it = result.values().erase(it);
            } else {
                ++it;
            }
        } else {
            ++it;
        }
    }

    return result;
}

ProblemDomain mtac::ConstantPropagationProblem::transfer(std::shared_ptr<mtac::BasicBlock> basic_block, mtac::Statement& statement, ProblemDomain& in){
    auto out = in;

    //Only quadruple affects variable
    if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&statement)){
        auto quadruple = *ptr;

        if(quadruple->op == mtac::Operator::ASSIGN || quadruple->op == mtac::Operator::FASSIGN){
            if(auto* ptr = boost::get<int>(&*quadruple->arg1)){
                out[quadruple->result] = *ptr;
            } else if(auto* ptr = boost::get<std::shared_ptr<Variable>>(&*quadruple->arg1)){
                out[quadruple->result] = *ptr;
            } else if(auto* ptr = boost::get<double>(&*quadruple->arg1)){
                out[quadruple->result] = *ptr;
            } else if(auto* ptr = boost::get<std::string>(&*quadruple->arg1)){
                out[quadruple->result] = *ptr;
            } else {
                //The result is not constant at this point
                out.erase(quadruple->result);
            }
        } else {
            auto op = quadruple->op;

            //Check if the operator erase the contents of the result variable
            if(op != mtac::Operator::ARRAY_ASSIGN && op != mtac::Operator::DOT_ASSIGN && op != mtac::Operator::RETURN){
                //The result is not constant at this point
                out.erase(quadruple->result);
            }
        }
    }

    return out;
}

bool optimize_arg(mtac::Argument* arg, ProblemDomain& results){
    if(auto* ptr = boost::get<std::shared_ptr<Variable>>(arg)){
        if(results.find(*ptr) != results.end()){
            *arg = results[*ptr];
            return true;
        }
    }

    return false;
}

bool optimize_optional(boost::optional<mtac::Argument>& arg, ProblemDomain& results){
    if(arg){
        return optimize_arg(&*arg, results);
    }

    return false;
}

bool mtac::ConstantPropagationProblem::optimize(mtac::Statement& statement, std::shared_ptr<mtac::DataFlowResults<ProblemDomain>>& global_results){
    auto& results = global_results->IN_S[statement];

    bool changes = false;

    if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&statement)){
        auto& quadruple = *ptr;

        //Do not replace a variable by a constant when used in offset
        if(quadruple->op != mtac::Operator::ARRAY && quadruple->op != mtac::Operator::DOT){
            changes |= optimize_optional(quadruple->arg1, results);
        }

        changes |= optimize_optional(quadruple->arg2, results);
    } else if(auto* ptr = boost::get<std::shared_ptr<mtac::Param>>(&statement)){
        auto& param = *ptr;

        changes |= optimize_arg(&param->arg, results);
    } else if(auto* ptr = boost::get<std::shared_ptr<mtac::IfFalse>>(&statement)){
        auto& ifFalse = *ptr;

        changes |= optimize_arg(&ifFalse->arg1, results);
        changes |= optimize_optional(ifFalse->arg2, results);
    } else if(auto* ptr = boost::get<std::shared_ptr<mtac::If>>(&statement)){
        auto& if_ = *ptr;

        changes |= optimize_arg(&if_->arg1, results);
        changes |= optimize_optional(if_->arg2, results);
    }

    return changes;
}
<commit_msg>Fix an infinite loop due to constant propagation optimization<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "assert.hpp"
#include "Variable.hpp"

#include "mtac/ConstantPropagationProblem.hpp"

using namespace eddic;

typedef mtac::ConstantPropagationProblem::ProblemDomain ProblemDomain;

ProblemDomain mtac::ConstantPropagationProblem::meet(ProblemDomain& in, ProblemDomain& out){
    auto result = mtac::intersection_meet(in, out);

    //Remove all the temporary
    for(auto it = std::begin(result.values()); it != std::end(result.values());){
        if(auto* ptr = boost::get<std::shared_ptr<Variable>>(&it->second)){
            auto variable = *ptr;

            if (variable->position().isTemporary()){
                it = result.values().erase(it);
            } else {
                ++it;
            }
        } else {
            ++it;
        }
    }

    return result;
}

ProblemDomain mtac::ConstantPropagationProblem::transfer(std::shared_ptr<mtac::BasicBlock>/* basic_block*/, mtac::Statement& statement, ProblemDomain& in){
    auto out = in;

    //Only quadruple affects variable
    if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&statement)){
        auto quadruple = *ptr;

        if(quadruple->op == mtac::Operator::ASSIGN || quadruple->op == mtac::Operator::FASSIGN){
            if(auto* ptr = boost::get<int>(&*quadruple->arg1)){
                out[quadruple->result] = *ptr;
            } else if(auto* ptr = boost::get<std::shared_ptr<Variable>>(&*quadruple->arg1)){
                if(*ptr != quadruple->result){
                    out[quadruple->result] = *ptr;
                }
            } else if(auto* ptr = boost::get<double>(&*quadruple->arg1)){
                out[quadruple->result] = *ptr;
            } else if(auto* ptr = boost::get<std::string>(&*quadruple->arg1)){
                out[quadruple->result] = *ptr;
            } else {
                //The result is not constant at this point
                out.erase(quadruple->result);
            }
        } else {
            auto op = quadruple->op;

            //Check if the operator erase the contents of the result variable
            if(op != mtac::Operator::ARRAY_ASSIGN && op != mtac::Operator::DOT_ASSIGN && op != mtac::Operator::RETURN){
                //The result is not constant at this point
                out.erase(quadruple->result);
            }
        }
    }

    return out;
}

bool optimize_arg(mtac::Argument* arg, ProblemDomain& results){
    if(auto* ptr = boost::get<std::shared_ptr<Variable>>(arg)){
        if(results.find(*ptr) != results.end()){
            *arg = results[*ptr];
            return true;
        }
    }

    return false;
}

bool optimize_optional(boost::optional<mtac::Argument>& arg, ProblemDomain& results){
    if(arg){
        return optimize_arg(&*arg, results);
    }

    return false;
}

bool mtac::ConstantPropagationProblem::optimize(mtac::Statement& statement, std::shared_ptr<mtac::DataFlowResults<ProblemDomain>>& global_results){
    auto& results = global_results->IN_S[statement];

    bool changes = false;

    if(auto* ptr = boost::get<std::shared_ptr<mtac::Quadruple>>(&statement)){
        auto& quadruple = *ptr;

        //Do not replace a variable by a constant when used in offset
        if(quadruple->op != mtac::Operator::ARRAY && quadruple->op != mtac::Operator::DOT){
            changes |= optimize_optional(quadruple->arg1, results);
        }

        changes |= optimize_optional(quadruple->arg2, results);
    } else if(auto* ptr = boost::get<std::shared_ptr<mtac::Param>>(&statement)){
        auto& param = *ptr;

        changes |= optimize_arg(&param->arg, results);
    } else if(auto* ptr = boost::get<std::shared_ptr<mtac::IfFalse>>(&statement)){
        auto& ifFalse = *ptr;

        changes |= optimize_arg(&ifFalse->arg1, results);
        changes |= optimize_optional(ifFalse->arg2, results);
    } else if(auto* ptr = boost::get<std::shared_ptr<mtac::If>>(&statement)){
        auto& if_ = *ptr;

        changes |= optimize_arg(&if_->arg1, results);
        changes |= optimize_optional(if_->arg2, results);
    }

    return changes;
}
<|endoftext|>