<commit_before>#ifndef SERVER_MIDDLEWARE_HPP
#define SERVER_MIDDLEWARE_HPP

#include "request.hpp"
#include "response.hpp"

namespace server {

class Middleware;
using Middleware_ptr = std::shared_ptr<Middleware>;

using next_t = delegate<void()>;
using Next = std::shared_ptr<next_t>;
using Callback = delegate<void(Request_ptr, Response_ptr, Next)>;

class Middleware {
public:

  virtual void process(Request_ptr, Response_ptr, Next) = 0;

  Callback callback() {
    return Callback::from<Middleware, &Middleware::process>(this);
  }

  virtual void onMount(const std::string&) {
    // do nothing
  }

};

}; // << namespace server

#endif
<commit_msg>Director now use mount path to resolve file path<commit_after>#ifndef SERVER_MIDDLEWARE_HPP
#define SERVER_MIDDLEWARE_HPP

#include "request.hpp"
#include "response.hpp"

namespace server {

class Middleware;
using Middleware_ptr = std::shared_ptr<Middleware>;

using next_t = delegate<void()>;
using Next = std::shared_ptr<next_t>;
using Callback = delegate<void(Request_ptr, Response_ptr, Next)>;

class Middleware {
public:

  virtual void process(Request_ptr, Response_ptr, Next) = 0;

  Callback callback() {
    return Callback::from<Middleware, &Middleware::process>(this);
  }

  virtual void onMount(const std::string& path) {
    mountpath_ = path;
  }

protected:
  std::string mountpath_;

};

}; // << namespace server

#endif
<|endoftext|>


<commit_before>#define WIN32_LEAN_AND_MEAN
#pragma comment (lib, "Shlwapi.lib")

#pragma warning (disable:4996)

#include <Windows.h>
#include <Shlwapi.h>
#include <unordered_map>
#include <mutex>

using namespace std;

#define BUF_SIZE MAX_PATH * 3

long long CurrentTime()
{
    long long t;
    GetSystemTimeAsFileTime((LPFILETIME) &t);
    return t;
}

BOOL unhook_by_code(LPCTSTR szDllName, LPCTSTR szFuncName, PBYTE pOrgBytes)
{
    FARPROC pFunc;
    DWORD dwOldProtect;

    // API ּ Ѵ
    pFunc = GetProcAddress(GetModuleHandle(szDllName), szFuncName);

    //  ڵ (5 byte)   ޸𸮿 WRITE Ӽ ߰
    VirtualProtect((LPVOID) pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

    // Unhook
    memcpy(pFunc, pOrgBytes, 5);

    // ޸ Ӽ
    VirtualProtect((LPVOID) pFunc, 5, dwOldProtect, &dwOldProtect);

    return TRUE;
}

BOOL hook_by_code(LPCTSTR szDllName, LPCTSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes)
{
    FARPROC pfnOrg;
    DWORD dwOldProtect, dwAddress;
    BYTE pBuf[5] = { 0xE9, 0, };
    PBYTE pByte;

    // ŷ API ּҸ Ѵ
    pfnOrg = (FARPROC) GetProcAddress(GetModuleHandle(szDllName), szFuncName);
    pByte = (PBYTE) pfnOrg;

    //  ̹ ŷǾ ִٸ return FALSE
    if (pByte[0] == 0xE9)
        return FALSE;

    // 5 byte ġ Ͽ ޸𸮿 WRITE Ӽ ߰
    VirtualProtect((LPVOID) pfnOrg, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

    // ڵ (5 byte)
    memcpy(pOrgBytes, pfnOrg, 5);

    // JMP ּҰ (E9 XXXX)
    // => XXXX = pfnNew - pfnOrg - 5
    dwAddress = (DWORD) pfnNew - (DWORD) pfnOrg - 5;
    memcpy(&pBuf[1], &dwAddress, 4);

    // Hook - 5 byte ġ(JMP XXXX)
    memcpy(pfnOrg, pBuf, 5);

    // ޸ Ӽ
    VirtualProtect((LPVOID) pfnOrg, 5, dwOldProtect, &dwOldProtect);

    return TRUE;
}

HANDLE hPipe;
char buffer[BUF_SIZE];
mutex pQueueMutex;

volatile BOOL bCancelPipeThread = FALSE;
volatile BOOL bPipeConnected = FALSE;

DWORD WINAPI PipeManager(LPVOID lParam)
{
    hPipe = CreateNamedPipe("\\\\.\\pipe\\osu!Lyrics", PIPE_ACCESS_OUTBOUND,
        PIPE_TYPE_MESSAGE | PIPE_WAIT, 1, BUF_SIZE * 5, 0, INFINITE, NULL);
    //   û   Ŭ̾Ʈ
    while (!bCancelPipeThread)
    {
        // ConnectNamedPipe Ŭ̾Ʈ    :
        // Ҵ DisconnectNamedPipe
        if (ConnectNamedPipe(hPipe, NULL) || GetLastError() == ERROR_PIPE_CONNECTED)
        {
            bPipeConnected = TRUE;

            OVERLAPPED overlapped = {};
            string message;
            pQueueMutex.lock(); //ť ؽ ϵɶ ٸ. ϵǸ .
            {
                message = buffer;
            }
            pQueueMutex.unlock(); //ϵǸ buffer ޼ ī  ٽ Ѵ.
            if (WriteFileEx(hPipe, message.c_str(), message.length(), &overlapped, [](DWORD, DWORD, LPOVERLAPPED) {}))
            {
                continue;
            }
            // WriteFileEx д Ŭ̾Ʈ  ٴ ...
        }
        bPipeConnected = FALSE;
        DisconnectNamedPipe(hPipe);
    }
    // Ŭ̾Ʈ
    DisconnectNamedPipe(hPipe);
    CloseHandle(hPipe);
    return 0;
}

typedef BOOL (WINAPI *tReadFile)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
tReadFile pReadFile;
BYTE pReadFileJMP[5];
mutex pBinaryMutex;

unordered_map<string, string> audioInfo;

// osu! ReadFile ȣϸ   osu!Lyrics
BOOL WINAPI hkReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
    long long calledAt = CurrentTime();

    BOOL result;
    pBinaryMutex.lock();
    {
        unhook_by_code("kernel32.dll", "ReadFile", pReadFileJMP);
        result = pReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
        hook_by_code("kernel32.dll", "ReadFile", (PROC) hkReadFile, pReadFileJMP);
    }
    pBinaryMutex.unlock();
    if (!result)
    {
        return result;
    }

    char path[MAX_PATH];
    DWORD pathLength = GetFinalPathNameByHandle(hFile, path, MAX_PATH, VOLUME_NAME_DOS);
    //                  1: \\?\D:\Games\osu!\...
    DWORD seekPosition = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - *lpNumberOfBytesRead;
    //  д  Ʈ ̰ պκ оٸ:
    // AudioFilename պκп  /  ڵ       !
    if (strnicmp(".osu", &path[pathLength - 4], 4) == 0 && seekPosition == 0)
    {
        // strtok ҽ ϹǷ ϴ
        char *buffer = strdup((char *) lpBuffer);
        char *line = strtok(buffer, "\n");
        while (line != NULL)
        {
            // Ʈ
            if (strnicmp(line, "AudioFilename:", 14) == 0)
            {
                char *beatmapDir = strdup(path);
                PathRemoveFileSpec(beatmapDir);

                char audioPath[MAX_PATH];

                // get value & trim
                int i = 14;
                for (; line[i] == ' '; i++);
                buffer[0] = '\0';
                strncat(buffer, &line[i], strlen(line) - i - 1);
                PathCombine(audioPath, beatmapDir, buffer);

                // ˻  ҹ ϹǷ
                WIN32_FIND_DATA fdata;
                FindClose(FindFirstFile(audioPath, &fdata));
                PathRemoveFileSpec(audioPath);
                PathCombine(audioPath, audioPath, fdata.cFileName);

                audioInfo.insert(make_pair(string(audioPath), string(path)));

                free(beatmapDir);
                break;
            }
            line = strtok(NULL, "\n");
        }
        free(buffer);
    }
    else if (bPipeConnected)
    {
        // [ audioPath, beatmapPath ]
        unordered_map<string, string>::iterator it = audioInfo.find(string(path));
        if (it != audioInfo.end())
        {
            sprintf(buffer, "%llx|%s|%lx|%s\n", calledAt, &path[4], seekPosition, &it->second[4]);
            pQueueMutex.unlock(); //ۿ ޼  Ѵ. ׷ κ  lockȴ.
            // ý  ̴  尡 ޼
            pQueueMutex.lock();
            /* lockǰ  ؽ ٽ  ť ٸ. ׷  ϵ Ŀ ٽ ϵȴ.
              ׷ (޼)  ó ̷.  ٽ ϵǸ  ٽ ޼ ޾Ƽ Ҷ
                lockԼ ٸ ȴ.*/
        }
    }
    return result;
}

HANDLE hPipeThread;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH)
    {
        hPipeThread = CreateThread(NULL, 0, PipeManager, NULL, 0, NULL);

        pBinaryMutex.lock();
        {
            pReadFile = (tReadFile) GetProcAddress(GetModuleHandle("kernel32.dll"), "ReadFile");
            hook_by_code("kernel32.dll", "ReadFile", (PROC) hkReadFile, pReadFileJMP);
        }
        pBinaryMutex.unlock();
    }
    else if (fdwReason == DLL_PROCESS_DETACH)
    {
        bCancelPipeThread = TRUE;
        WaitForSingleObject(hPipeThread, INFINITE);
        CloseHandle(hPipeThread);

        pBinaryMutex.lock();
        {
            unhook_by_code("kernel32.dll", "ReadFile", pReadFileJMP);
        }
        pBinaryMutex.unlock();
    }
    return TRUE;
}<commit_msg>데이터를 얻어서 처리하고 파이프라인에 보네는곳에서 나타난 스레드 동기화 버그를 수정했습니다 #19<commit_after>#define WIN32_LEAN_AND_MEAN
#pragma comment (lib, "Shlwapi.lib")

#pragma warning (disable:4996)

#include <Windows.h>
#include <Shlwapi.h>
#include <unordered_map>
#include <mutex>
#include <queue>

using namespace std;

volatile HANDLE hQueueObject;
mutex QueueMutex;
queue <string> InfoQueue;

#define BUF_SIZE 256

long long CurrentTime()
{
    long long t;
    GetSystemTimeAsFileTime((LPFILETIME) &t);
    return t;
}

BOOL unhook_by_code(LPCTSTR szDllName, LPCTSTR szFuncName, PBYTE pOrgBytes)
{
    FARPROC pFunc;
    DWORD dwOldProtect;

    // API ּ Ѵ
    pFunc = GetProcAddress(GetModuleHandle(szDllName), szFuncName);

    //  ڵ (5 byte)   ޸𸮿 WRITE Ӽ ߰
    VirtualProtect((LPVOID) pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

    // Unhook
    memcpy(pFunc, pOrgBytes, 5);

    // ޸ Ӽ
    VirtualProtect((LPVOID) pFunc, 5, dwOldProtect, &dwOldProtect);

    return TRUE;
}

BOOL hook_by_code(LPCTSTR szDllName, LPCTSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes)
{
    FARPROC pfnOrg;
    DWORD dwOldProtect, dwAddress;
    BYTE pBuf[5] = { 0xE9, 0, };
    PBYTE pByte;

    // ŷ API ּҸ Ѵ
    pfnOrg = (FARPROC) GetProcAddress(GetModuleHandle(szDllName), szFuncName);
    pByte = (PBYTE) pfnOrg;

    //  ̹ ŷǾ ִٸ return FALSE
    if (pByte[0] == 0xE9)
        return FALSE;

    // 5 byte ġ Ͽ ޸𸮿 WRITE Ӽ ߰
    VirtualProtect((LPVOID) pfnOrg, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect);

    // ڵ (5 byte)
    memcpy(pOrgBytes, pfnOrg, 5);

    // JMP ּҰ (E9 XXXX)
    // => XXXX = pfnNew - pfnOrg - 5
    dwAddress = (DWORD) pfnNew - (DWORD) pfnOrg - 5;
    memcpy(&pBuf[1], &dwAddress, 4);

    // Hook - 5 byte ġ(JMP XXXX)
    memcpy(pfnOrg, pBuf, 5);

    // ޸ Ӽ
    VirtualProtect((LPVOID) pfnOrg, 5, dwOldProtect, &dwOldProtect);

    return TRUE;
}

HANDLE hPipe;

volatile BOOL bCancelPipeThread = FALSE;
volatile BOOL bIsPipeConnected = FALSE;

DWORD WINAPI PipeManager(LPVOID lParam)
{
    hPipe = CreateNamedPipeA("\\\\.\\pipe\\osu!Lyrics", PIPE_ACCESS_OUTBOUND,
        PIPE_TYPE_MESSAGE | PIPE_WAIT, 1, BUF_SIZE * 5, 0, INFINITE, NULL);

    // Ŭ̾Ʈ
    while (!bCancelPipeThread)
    {
		if ((ConnectNamedPipe(hPipe, NULL)) || GetLastError() == ERROR_PIPE_CONNECTED)
        {
			bIsPipeConnected = TRUE;

            OVERLAPPED overlapped = {};
			string tmpstring;

			WaitForSingleObject(hQueueObject, INFINITE);

			QueueMutex.lock();
			while(!InfoQueue.empty())
			{
				tmpstring = (InfoQueue.front());
				InfoQueue.pop();
				if (WriteFileEx(hPipe, tmpstring.c_str(), tmpstring.length(), &overlapped, [](DWORD, DWORD, LPOVERLAPPED) {}))
				{
					continue;
				}
			}
			QueueMutex.unlock();
			continue;
        }
		bIsPipeConnected = FALSE;
		DisconnectNamedPipe(hPipe);
    }
    // Ŭ̾Ʈ
    return 0;
}

typedef BOOL (WINAPI *tReadFile)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
tReadFile pReadFile;
BYTE pReadFileJMP[5];

mutex pBinaryMutex;

unordered_map<string, string> audioInfo;

// osu! ReadFile ȣϸ   osu!Lyrics
BOOL WINAPI hkReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped)
{
    long long calledAt = CurrentTime();
    BOOL result = FALSE;

	pBinaryMutex.lock();
    {
        unhook_by_code("kernel32.dll", "ReadFile", pReadFileJMP);
        result = pReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
        hook_by_code("kernel32.dll", "ReadFile", (PROC) hkReadFile, pReadFileJMP);
    }
	pBinaryMutex.unlock();
    if (!result)
    {
        // result ϰų  ĿƮǾ 쿣 ٷ Լ Ѵ.
        return FALSE;
    }

    char path[MAX_PATH];
    DWORD pathLength = GetFinalPathNameByHandle(hFile, path, MAX_PATH, VOLUME_NAME_DOS);
    //                  1: \\?\D:\Games\osu!\...
    DWORD seekPosition = SetFilePointer(hFile, 0, NULL, FILE_CURRENT) - *lpNumberOfBytesRead;
    //  д  Ʈ ̰ պκ оٸ:
    // AudioFilename պκп  /  ڵ       !
    if (strnicmp(".osu", &path[pathLength - 4], 4) == 0 && seekPosition == 0)
    {
        // strtok ҽ ϹǷ ϴ
        char *buffer = strdup((char *) lpBuffer);
        char *line = strtok(buffer, "\n");
        while (line != NULL)
        {
            // Ʈ
            if (strnicmp(line, "AudioFilename:", 14) == 0)
            {
                char *beatmapDir = strdup(path);
                PathRemoveFileSpec(beatmapDir);

                char audioPath[MAX_PATH];

                // get value & trim
                int i = 14;
                for (; line[i] == ' '; i++);
                buffer[0] = '\0';
                strncat(buffer, &line[i], strlen(line) - i - 1);
                PathCombine(audioPath, beatmapDir, buffer);

                // ˻  ҹ ϹǷ
                WIN32_FIND_DATA fdata;
                FindClose(FindFirstFile(audioPath, &fdata));
                PathRemoveFileSpec(audioPath);
                PathCombine(audioPath, audioPath, fdata.cFileName);

                audioInfo.insert(make_pair(string(audioPath), string(path)));

                free(beatmapDir);
                break;
            }
            line = strtok(NULL, "\n");
        }
        free(buffer);

    }
	else
    {
        // [ audioPath, beatmapPath ]
        unordered_map<string, string>::iterator it = audioInfo.find(string(path));
        if (it != audioInfo.end())
        {
			char *buffer = nullptr;

			buffer = new char[BUF_SIZE];
            sprintf(buffer, "%llx|%s|%lx|%s\n", calledAt, &path[4], seekPosition, &it->second[4]);

			QueueMutex.lock();
			InfoQueue.push(string(buffer));
			QueueMutex.unlock();
			SetEvent(hQueueObject);

			delete[] buffer;
        }
    }
    return TRUE;
}

HANDLE hPipeThread;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH)
    {
        hPipeThread = CreateThread(NULL, 0, PipeManager, NULL, 0, NULL);
		hQueueObject = CreateEventA(NULL, TRUE, FALSE, NULL);

		pBinaryMutex.lock();
        {
            pReadFile = (tReadFile) GetProcAddress(GetModuleHandle("kernel32.dll"), "ReadFile");
            hook_by_code("kernel32.dll", "ReadFile", (PROC) hkReadFile, pReadFileJMP);
        }
		pBinaryMutex.unlock();
    }
    else if (fdwReason == DLL_PROCESS_DETACH)
    {
        bCancelPipeThread = TRUE;

        WaitForSingleObject(hPipeThread, INFINITE);

		DisconnectNamedPipe(hPipe);

        CloseHandle(hPipeThread);
		CloseHandle(hPipe);

		pBinaryMutex.lock();
        {
            unhook_by_code("kernel32.dll", "ReadFile", pReadFileJMP);
        }
		pBinaryMutex.unlock();
    }
    return TRUE;
}<|endoftext|>


<commit_before>/*-----------------------------------------------------------------------------

 Copyright 2017 Hopsan Group

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

 The full license is available in the file LICENSE.
 For details about the 'Hopsan Group' or information about Authors and
 Contributors see the HOPSANGROUP and AUTHORS files that are located in
 the Hopsan source code root directory.

-----------------------------------------------------------------------------*/

//!
//! @file   MechanicPulley.hpp
//! @author Robert Braun <robert.braun@liu.se>
//! @date   2013-02-28
//!
//! @brief Contains a mechanic pulley
//!
//$Id$

#ifndef MECHANICPULLEY_HPP_INCLUDED
#define MECHANICPULLEY_HPP_INCLUDED

#include "ComponentEssentials.h"
#include "ComponentUtilities.h"

namespace hopsan {

    //!
    //! @brief
    //! @ingroup MechanicalComponents
    //!
    class MechanicPulley : public ComponentQ
    {

    private:
        double m;
        double *mpB;
        double mNumTheta[3];
        double mDenTheta[3];
        double mNumOmega[2];
        double mDenOmega[2];
        SecondOrderTransferFunction mFilterTheta;
        FirstOrderTransferFunction mFilterOmega;
        //        DoubleIntegratorWithDamping mIntegrator;
        double *mpND_f1, *mpND_x1, *mpND_v1, *mpND_me1, *mpND_c1, *mpND_Zx1,
               *mpND_f2, *mpND_x2, *mpND_v2, *mpND_me2, *mpND_c2, *mpND_Zx2;
        double f1, x1, v1, c1, Zx1,
               f2, x2, v2, c2, Zx2;
        Port *mpP1, *mpP2;

    public:
        static Component *Creator()
        {
            return new MechanicPulley();
        }

        void configure()
        {
            //Add ports to the component
            mpP1 = addPowerPort("P1", "NodeMechanic");
            mpP2 = addPowerPort("P2", "NodeMechanic");

            //Register changeable parameters to the HOPSAN++ core
            addConstant("m", "Inertia", "kg", 1.0, m);
            addInputVariable("B", "Viscous Friction", "Nms/rad", 10, &mpB);
        }

        void initialize()
        {
            mpND_f1 = getSafeNodeDataPtr(mpP1, NodeMechanic::Force);
            mpND_x1 = getSafeNodeDataPtr(mpP1, NodeMechanic::Position);
            mpND_v1 = getSafeNodeDataPtr(mpP1, NodeMechanic::Velocity);
            mpND_me1 = getSafeNodeDataPtr(mpP1, NodeMechanic::EquivalentMass);
            mpND_c1 = getSafeNodeDataPtr(mpP1, NodeMechanic::WaveVariable);
            mpND_Zx1 = getSafeNodeDataPtr(mpP1, NodeMechanic::CharImpedance);

            mpND_f2 = getSafeNodeDataPtr(mpP2, NodeMechanic::Force);
            mpND_x2 = getSafeNodeDataPtr(mpP2, NodeMechanic::Position);
            mpND_v2 = getSafeNodeDataPtr(mpP2, NodeMechanic::Velocity);
            mpND_me2 = getSafeNodeDataPtr(mpP2, NodeMechanic::EquivalentMass);
            mpND_c2 = getSafeNodeDataPtr(mpP2, NodeMechanic::WaveVariable);
            mpND_Zx2 = getSafeNodeDataPtr(mpP2, NodeMechanic::CharImpedance);

            f1 = (*mpND_f1)*2.0;
            x1 = (*mpND_x1)/2.0;
            v1 = (*mpND_v1)/2.0;
            f2 = (*mpND_f2);
            x2 = (*mpND_x2);
            v2 = (*mpND_v2);

            mNumTheta[0] = 1.0;
            mNumTheta[1] = 0.0;
            mNumTheta[2] = 0.0;
            mDenTheta[0] = 0;
            mDenTheta[1] = (*mpB);
            mDenTheta[2] = m;
            mNumOmega[0] = 1.0;
            mNumOmega[1] = 0.0;
            mDenOmega[0] = (*mpB);
            mDenOmega[1] = m;

            mFilterTheta.initialize(mTimestep, mNumTheta, mDenTheta, f1-f2, -x1, -1.5e300, 1.5e300, -v1);
            mFilterOmega.initialize(mTimestep, mNumOmega, mDenOmega, f1-f2, -v1);

            (*mpND_me1) = m;
            (*mpND_me2) = m;
        }

        void simulateOneTimestep()
        {
            //Get variable values from nodes
            c1  = (*mpND_c1)*2;
            Zx1 = (*mpND_Zx1)*4;
            c2  = (*mpND_c2);
            Zx2 = (*mpND_Zx2);

            //Mass equations
            mDenTheta[1] = ((*mpB)+Zx1+Zx2);
            mDenOmega[0] = ((*mpB)+Zx1+Zx2);
            mFilterTheta.setDen(mDenTheta);
            mFilterOmega.setDen(mDenOmega);

            x2 = mFilterTheta.update(c1-c2);
            v2 = mFilterOmega.update(c1-c2);
            f2 = c2 + Zx2*v2;

            v1 = -v2*2;
            x1 = -x2*2;
            f1 = (c1 + Zx1*v1)/2.0;

            //Write new values to nodes
            (*mpND_f1) = f1;
            (*mpND_x1) = x1;
            (*mpND_v1) = v1;
            (*mpND_f2) = f2;
            (*mpND_x2) = x2;
            (*mpND_v2) = v2;
        }
    };
}

#endif // MECHANICPULLEY_HPP_INCLUDED

<commit_msg>Fix wrong impedance for pulley component<commit_after>/*-----------------------------------------------------------------------------

 Copyright 2017 Hopsan Group

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

 The full license is available in the file LICENSE.
 For details about the 'Hopsan Group' or information about Authors and
 Contributors see the HOPSANGROUP and AUTHORS files that are located in
 the Hopsan source code root directory.

-----------------------------------------------------------------------------*/

//!
//! @file   MechanicPulley.hpp
//! @author Robert Braun <robert.braun@liu.se>
//! @date   2013-02-28
//!
//! @brief Contains a mechanic pulley
//!
//$Id$

#ifndef MECHANICPULLEY_HPP_INCLUDED
#define MECHANICPULLEY_HPP_INCLUDED

#include "ComponentEssentials.h"
#include "ComponentUtilities.h"

namespace hopsan {

    //!
    //! @brief
    //! @ingroup MechanicalComponents
    //!
    class MechanicPulley : public ComponentQ
    {

    private:
        double m;
        double *mpB;
        double mNumTheta[3];
        double mDenTheta[3];
        double mNumOmega[2];
        double mDenOmega[2];
        SecondOrderTransferFunction mFilterTheta;
        FirstOrderTransferFunction mFilterOmega;
        //        DoubleIntegratorWithDamping mIntegrator;
        double *mpND_f1, *mpND_x1, *mpND_v1, *mpND_me1, *mpND_c1, *mpND_Zx1,
               *mpND_f2, *mpND_x2, *mpND_v2, *mpND_me2, *mpND_c2, *mpND_Zx2;
        double f1, x1, v1, c1, Zx1,
               f2, x2, v2, c2, Zx2;
        Port *mpP1, *mpP2;

    public:
        static Component *Creator()
        {
            return new MechanicPulley();
        }

        void configure()
        {
            //Add ports to the component
            mpP1 = addPowerPort("P1", "NodeMechanic");
            mpP2 = addPowerPort("P2", "NodeMechanic");

            //Register changeable parameters to the HOPSAN++ core
            addConstant("m", "Inertia", "kg", 1.0, m);
            addInputVariable("B", "Viscous Friction", "Nms/rad", 10, &mpB);
        }

        void initialize()
        {
            mpND_f1 = getSafeNodeDataPtr(mpP1, NodeMechanic::Force);
            mpND_x1 = getSafeNodeDataPtr(mpP1, NodeMechanic::Position);
            mpND_v1 = getSafeNodeDataPtr(mpP1, NodeMechanic::Velocity);
            mpND_me1 = getSafeNodeDataPtr(mpP1, NodeMechanic::EquivalentMass);
            mpND_c1 = getSafeNodeDataPtr(mpP1, NodeMechanic::WaveVariable);
            mpND_Zx1 = getSafeNodeDataPtr(mpP1, NodeMechanic::CharImpedance);

            mpND_f2 = getSafeNodeDataPtr(mpP2, NodeMechanic::Force);
            mpND_x2 = getSafeNodeDataPtr(mpP2, NodeMechanic::Position);
            mpND_v2 = getSafeNodeDataPtr(mpP2, NodeMechanic::Velocity);
            mpND_me2 = getSafeNodeDataPtr(mpP2, NodeMechanic::EquivalentMass);
            mpND_c2 = getSafeNodeDataPtr(mpP2, NodeMechanic::WaveVariable);
            mpND_Zx2 = getSafeNodeDataPtr(mpP2, NodeMechanic::CharImpedance);

            f1 = (*mpND_f1)*2.0;
            x1 = (*mpND_x1)/2.0;
            v1 = (*mpND_v1)/2.0;
            f2 = (*mpND_f2);
            x2 = (*mpND_x2);
            v2 = (*mpND_v2);

            mNumTheta[0] = 1.0;
            mNumTheta[1] = 0.0;
            mNumTheta[2] = 0.0;
            mDenTheta[0] = 0;
            mDenTheta[1] = (*mpB);
            mDenTheta[2] = m;
            mNumOmega[0] = 1.0;
            mNumOmega[1] = 0.0;
            mDenOmega[0] = (*mpB);
            mDenOmega[1] = m;

            mFilterTheta.initialize(mTimestep, mNumTheta, mDenTheta, f1-f2, -x1, -1.5e300, 1.5e300, -v1);
            mFilterOmega.initialize(mTimestep, mNumOmega, mDenOmega, f1-f2, -v1);

            (*mpND_me1) = m;
            (*mpND_me2) = m;
        }

        void simulateOneTimestep()
        {
            //Get variable values from nodes
            c1  = (*mpND_c1);
            Zx1 = (*mpND_Zx1);
            c2  = (*mpND_c2);
            Zx2 = (*mpND_Zx2);

            //Mass equations
            mDenTheta[1] = ((*mpB)+4*Zx1+Zx2);
            mDenOmega[0] = ((*mpB)+4*Zx1+Zx2);
            mFilterTheta.setDen(mDenTheta);
            mFilterOmega.setDen(mDenOmega);

            x2 = mFilterTheta.update(2*c1-c2);
            v2 = mFilterOmega.update(2*c1-c2);
            f2 = c2 + Zx2*v2;

            v1 = -v2*2;
            x1 = -x2*2;
            f1 = c1 + Zx1*v1;

            //Write new values to nodes
            (*mpND_f1) = f1;
            (*mpND_x1) = x1;
            (*mpND_v1) = v1;
            (*mpND_f2) = f2;
            (*mpND_x2) = x2;
            (*mpND_v2) = v2;
        }
    };
}

#endif // MECHANICPULLEY_HPP_INCLUDED

<|endoftext|>


<commit_before>
/*
 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef DATABLOCK_H
#define DATABLOCK_H

#include "mem/ruby/common/Global.hh"
#include "mem/ruby/system/System.hh"
#include "mem/gems_common/Vector.hh"

class DataBlock {
 public:
  // Constructors
  DataBlock() {alloc();}
  DataBlock(const DataBlock & cp) {
    m_data = new uint8[RubySystem::getBlockSizeBytes()];
    memcpy(m_data, cp.m_data, RubySystem::getBlockSizeBytes());
    m_alloc = true;
  }

  // Destructor
  ~DataBlock() { if(m_alloc) delete [] m_data;}

  DataBlock& operator=(const DataBlock& obj);

  // Public Methods
  void assign(uint8* data);

  void clear();
  uint8 getByte(int whichByte) const;
  const uint8* getData(int offset, int len) const;
  void setByte(int whichByte, uint8 data);
  void setData(uint8* data, int offset, int len);
  void copyPartial(const DataBlock & dblk, int offset, int len);
  bool equal(const DataBlock& obj) const;
  void print(ostream& out) const;

private:
  void alloc();
  // Data Members (m_ prefix)
  uint8* m_data;
  bool m_alloc;
};

// Output operator declaration
ostream& operator<<(ostream& out, const DataBlock& obj);

bool operator==(const DataBlock& obj1, const DataBlock& obj2);

// inline functions for speed

inline
void DataBlock::assign(uint8* data)
{
  delete [] m_data;
  m_data = data;
  m_alloc = false;
}

inline
void DataBlock::alloc()
{
  m_data = new uint8[RubySystem::getBlockSizeBytes()];
  m_alloc = true;
  clear();
}

inline
void DataBlock::clear()
{
  memset(m_data, 0, RubySystem::getBlockSizeBytes());
}

inline
bool DataBlock::equal(const DataBlock& obj) const
{
  return !memcmp(m_data, obj.m_data, RubySystem::getBlockSizeBytes());
}

inline
void DataBlock::print(ostream& out) const
{
  int size = RubySystem::getBlockSizeBytes();
  out << "[ ";
  for (int i = 0; i < size; i++) {
    out << setw(2) << setfill('0') << hex << "0x" << (int)m_data[i] << " ";
  }
  out << dec << "]" << flush;
}

inline
uint8 DataBlock::getByte(int whichByte) const
{
  return m_data[whichByte];
}

inline
const uint8* DataBlock::getData(int offset, int len) const
{
  assert(offset + len <= RubySystem::getBlockSizeBytes());
  return &m_data[offset];
}

inline
void DataBlock::setByte(int whichByte, uint8 data)
{
    m_data[whichByte] = data;
}

inline
void DataBlock::setData(uint8* data, int offset, int len)
{
  assert(offset + len <= RubySystem::getBlockSizeBytes());
  memcpy(&m_data[offset], data, len);
}

inline
void DataBlock::copyPartial(const DataBlock & dblk, int offset, int len)
{
  setData(&dblk.m_data[offset], offset, len);
}

// ******************* Definitions *******************

// Output operator definition
extern inline
ostream& operator<<(ostream& out, const DataBlock& obj)
{
  obj.print(out);
  out << flush;
  return out;
}

extern inline
bool operator==(const DataBlock& obj1,const DataBlock& obj2)
{
  return (obj1.equal(obj2));
}

#endif //DATABLOCK_H
<commit_msg>Object print bug fix<commit_after>
/*
 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef DATABLOCK_H
#define DATABLOCK_H

#include "mem/ruby/common/Global.hh"
#include "mem/ruby/system/System.hh"
#include "mem/gems_common/Vector.hh"

class DataBlock {
 public:
  // Constructors
  DataBlock() {alloc();}
  DataBlock(const DataBlock & cp) {
    m_data = new uint8[RubySystem::getBlockSizeBytes()];
    memcpy(m_data, cp.m_data, RubySystem::getBlockSizeBytes());
    m_alloc = true;
  }

  // Destructor
  ~DataBlock() { if(m_alloc) delete [] m_data;}

  DataBlock& operator=(const DataBlock& obj);

  // Public Methods
  void assign(uint8* data);

  void clear();
  uint8 getByte(int whichByte) const;
  const uint8* getData(int offset, int len) const;
  void setByte(int whichByte, uint8 data);
  void setData(uint8* data, int offset, int len);
  void copyPartial(const DataBlock & dblk, int offset, int len);
  bool equal(const DataBlock& obj) const;
  void print(ostream& out) const;

private:
  void alloc();
  // Data Members (m_ prefix)
  uint8* m_data;
  bool m_alloc;
};

// Output operator declaration
ostream& operator<<(ostream& out, const DataBlock& obj);

bool operator==(const DataBlock& obj1, const DataBlock& obj2);

// inline functions for speed

inline
void DataBlock::assign(uint8* data)
{
  delete [] m_data;
  m_data = data;
  m_alloc = false;
}

inline
void DataBlock::alloc()
{
  m_data = new uint8[RubySystem::getBlockSizeBytes()];
  m_alloc = true;
  clear();
}

inline
void DataBlock::clear()
{
  memset(m_data, 0, RubySystem::getBlockSizeBytes());
}

inline
bool DataBlock::equal(const DataBlock& obj) const
{
  return !memcmp(m_data, obj.m_data, RubySystem::getBlockSizeBytes());
}

inline
void DataBlock::print(ostream& out) const
{
  int size = RubySystem::getBlockSizeBytes();
  out << "[ ";
  for (int i = 0; i < size; i++) {
    out << setw(2) << setfill('0') << hex << "0x" << (int)m_data[i] << " ";
    out << setfill(' ');
  }
  out << dec << "]" << flush;
}

inline
uint8 DataBlock::getByte(int whichByte) const
{
  return m_data[whichByte];
}

inline
const uint8* DataBlock::getData(int offset, int len) const
{
  assert(offset + len <= RubySystem::getBlockSizeBytes());
  return &m_data[offset];
}

inline
void DataBlock::setByte(int whichByte, uint8 data)
{
    m_data[whichByte] = data;
}

inline
void DataBlock::setData(uint8* data, int offset, int len)
{
  assert(offset + len <= RubySystem::getBlockSizeBytes());
  memcpy(&m_data[offset], data, len);
}

inline
void DataBlock::copyPartial(const DataBlock & dblk, int offset, int len)
{
  setData(&dblk.m_data[offset], offset, len);
}

// ******************* Definitions *******************

// Output operator definition
extern inline
ostream& operator<<(ostream& out, const DataBlock& obj)
{
  obj.print(out);
  out << flush;
  return out;
}

extern inline
bool operator==(const DataBlock& obj1,const DataBlock& obj2)
{
  return (obj1.equal(obj2));
}

#endif //DATABLOCK_H
<|endoftext|>


<commit_before>#pragma once

#include <algorithm>
#include <cassert>
#include <cstring>

namespace {
	template <typename T>
	void swapEndian (T* p) {
		uint8_t* q = reinterpret_cast<uint8_t*>(p);

		std::reverse(q, q + sizeof(T));
	}
}

struct Slice {
	uint8_t* begin;
	uint8_t* end;

	Slice() : begin(nullptr), end(nullptr) {}
	Slice(uint8_t* begin, uint8_t* end) : begin(begin), end(end) {
		assert(begin);
		assert(end);
	}

	void popFrontN (size_t n) {
		assert(n <= this->length());
		begin += n;
	}

	void popFront () {
		this->popFrontN(1);
	}

	auto drop (size_t n) const {
		assert(n <= this->length());
		return Slice(this->begin + n, this->end);
	}

	auto take (size_t n) const {
		assert(n <= this->length());
		return Slice(this->begin, this->begin + n);
	}

	size_t length () const {
		return static_cast<size_t>(this->end - this->begin);
	}

	template <typename Y = uint8_t>
	Y peek (size_t offset = 0) const {
		return *(reinterpret_cast<Y*>(this->begin + offset));
	}

	template <typename Y, bool swap = false>
	void put (Y value, size_t offset = 0) {
		assert(offset + sizeof(Y) <= this->length());
		auto ptr = reinterpret_cast<Y*>(this->begin + offset);
		*ptr = value;

		if (swap) swapEndian(ptr);
	}

	void put (uint8_t* value, size_t n, size_t offset = 0) {
		assert(offset + n <= this->length());
		memcpy(this->begin + offset, value, n);
	}

	void put (Slice value, size_t offset = 0) {
		this->put(value.begin, value.length(), offset);
	}

	template <typename Y = uint8_t>
	Y read () {
		const Y value = this->peek<Y>();
		this->popFrontN(sizeof(Y));
		return value;
	}

	template <typename Y, bool swap = false>
	void write (Y value) {
		this->put<Y, swap>(value);
		this->popFrontN(sizeof(Y));
	}

	void write (Slice value) {
		this->put(value);
		this->popFrontN(value.length());
	}

	void write (uint8_t* value, size_t n) {
		this->put(value, n);
		this->popFrontN(n);
	}

	uint8_t& operator[](const size_t i) {
		assert(i <= this->length());
		return this->begin[i];
	}

	const uint8_t& operator[](const size_t i) const {
		assert(i <= this->length());
		return this->begin[i];
	}
};
<commit_msg>slice: consistent use of this<commit_after>#pragma once

#include <algorithm>
#include <cassert>
#include <cstring>

namespace {
	template <typename T>
	void swapEndian (T* p) {
		uint8_t* q = reinterpret_cast<uint8_t*>(p);

		std::reverse(q, q + sizeof(T));
	}
}

struct Slice {
	uint8_t* begin;
	uint8_t* end;

	Slice() : begin(nullptr), end(nullptr) {}
	Slice(uint8_t* begin, uint8_t* end) : begin(begin), end(end) {
		assert(this->begin);
		assert(this->end);
	}

	void popFrontN (size_t n) {
		assert(n <= this->length());
		this->begin += n;
	}

	void popFront () {
		this->popFrontN(1);
	}

	auto drop (size_t n) const {
		assert(n <= this->length());
		return Slice(this->begin + n, this->end);
	}

	auto take (size_t n) const {
		assert(n <= this->length());
		return Slice(this->begin, this->begin + n);
	}

	size_t length () const {
		return static_cast<size_t>(this->end - this->begin);
	}

	template <typename Y = uint8_t>
	Y peek (size_t offset = 0) const {
		return *(reinterpret_cast<Y*>(this->begin + offset));
	}

	template <typename Y, bool swap = false>
	void put (Y value, size_t offset = 0) {
		assert(offset + sizeof(Y) <= this->length());
		auto ptr = reinterpret_cast<Y*>(this->begin + offset);
		*ptr = value;

		if (swap) swapEndian(ptr);
	}

	void put (uint8_t* value, size_t n, size_t offset = 0) {
		assert(offset + n <= this->length());
		memcpy(this->begin + offset, value, n);
	}

	void put (Slice value, size_t offset = 0) {
		this->put(value.begin, value.length(), offset);
	}

	template <typename Y = uint8_t>
	Y read () {
		const Y value = this->peek<Y>();
		this->popFrontN(sizeof(Y));
		return value;
	}

	template <typename Y, bool swap = false>
	void write (Y value) {
		this->put<Y, swap>(value);
		this->popFrontN(sizeof(Y));
	}

	void write (Slice value) {
		this->put(value);
		this->popFrontN(value.length());
	}

	void write (uint8_t* value, size_t n) {
		this->put(value, n);
		this->popFrontN(n);
	}

	uint8_t& operator[](const size_t i) {
		assert(i <= this->length());
		return this->begin[i];
	}

	const uint8_t& operator[](const size_t i) const {
		assert(i <= this->length());
		return this->begin[i];
	}
};
<|endoftext|>


<commit_before>#ifndef stack_cpp
#define stack_cpp
#pragma once
#include <iostream>
#include <memory>

class bitset
{
public:
	explicit
		bitset(size_t size) /*strong*/;

	bitset(bitset const & other) = delete;
	auto operator =(bitset const & other)->bitset & = delete;

	bitset(bitset && other) = delete;
	auto operator =(bitset && other)->bitset & = delete;

	auto set(size_t index) /*strong*/ -> void;
	auto reset(size_t index) /*strong*/ -> void;
	auto test(size_t index) /*strong*/ -> bool;

	auto size() const /*noexcept*/ -> size_t;
	auto counter() const /*noexcept*/ -> size_t;

private:
	std::unique_ptr<bool[]>  ptr_;
	size_t size_;
	size_t counter_;
};

bitset::bitset(size_t size) : ptr_(std::make_unique<bool[]>(size)), size_(size), counter_(0) {}

auto bitset::set(size_t index) -> void
{ if (index < size_) {
	ptr_[index] = true;
	++counter_; }
	else throw("false_index");
}

auto bitset::reset(size_t index) -> void
{	if (index < size_)
	{
		ptr_[index] = false;
		--counter_;
	}
	else throw("false_index");
}

auto bitset::test(size_t index) -> bool
{
	if (index < size_)
	{
		return !ptr_[index];
	}
	else throw("false_index");

}
auto bitset::size() const -> size_t
{
	return size_;
}

auto bitset::counter() const -> size_t
{
	return counter_;
}

template <typename T>
class allocator
{
public:
	explicit
		allocator(std::size_t size = 0) /*strong*/;
	allocator(allocator const & other) /*strong*/;
	auto operator =(allocator const & other)->allocator & = delete;
	~allocator();

	auto resize() /*strong*/ -> void;

	auto construct(T * ptr, T const & value) /*strong*/ -> void;
	auto destroy(T * ptr) /*noexcept*/ -> void;

	auto get() /*noexcept*/ -> T *;
	auto get() const /*noexcept*/ -> T const *;

	auto count() const /*noexcept*/ -> size_t;
	auto full() const /*noexcept*/ -> bool;
	auto empty() const /*noexcept*/ -> bool;
private:
	auto destroy(T * first, T * last) /*noexcept*/ -> void;
	auto swap(allocator & other) /*noexcept*/ -> void;

	T * ptr_;
	size_t size_;
	std::unique_ptr<bitset> map_;
};

template <typename T>
class stack
{
public:
	explicit
		stack(size_t size = 0);
	auto operator =(stack const & other) /*strong*/ -> stack &;

	auto empty() const /*noexcept*/ -> bool;
	auto count() const /*noexcept*/ -> size_t;

	auto push(T const & value) /*strong*/ -> void;
	auto pop() /*strong*/ -> void;
	auto top() /*strong*/ -> T &;
	auto top() const /*strong*/ -> T const &;

private:
	allocator<T> allocator_;

	auto throw_is_empty() const -> void;
};

template <typename T>
allocator<T>::allocator(size_t size) : ptr_((T*)(operator new(size*sizeof(T)))), size_(size), map_(std::make_unique<bitset>(size)) {};

template<typename T>
	allocator<T>::allocator(allocator const& other) :
	allocator<T>(other.size_){
	for (size_t i=0; i < size_; ++i)
		if (map_->test(i))
		construct(ptr_ + i, other.ptr_[i]);
}
template<typename T>
allocator<T>::~allocator() {
	destroy(ptr_, ptr_+size_);
	operator delete(ptr_);
}

template<typename T>
auto allocator<T>::resize() -> void
{
	allocator<T> buff(size_ * 2 + (size_ == 0));
	for (size_t i = 0; i < size_; ++i) construct(buff.ptr_ + i, ptr_[i]);
	this->swap(buff);
}

template<typename T>
auto allocator<T>::construct(T * ptr, T const & value)->void {
	if (ptr >= ptr_&&ptr < ptr_ + size_&&map_->test(ptr - ptr_)) {
		new(ptr)T(value);
		map_->set(ptr - ptr_);
	}
	else throw("error");
}

template<typename T>
auto allocator<T>::destroy(T * ptr) -> void {
	if (!map_->test(ptr-ptr_)&&ptr>=ptr_&&ptr<=ptr_+this->count()){
	ptr->~T();
	map_->reset(ptr-ptr_);
	}
	else throw("error");
}

template<typename T>
auto allocator<T>::destroy(T * first, T * last) -> void
{	if(first>=ptr_&&last<=ptr_+this->count())
	for (; first != last; ++first) {
		destroy(&*first);
	}
}

template<typename T>
auto allocator<T>::get()-> T* {
	return ptr_;
}

template<typename T>
auto allocator<T>::get() const -> T const * {
	return ptr_;
}

template<typename T>
auto allocator<T>::count() const -> size_t
{
	return map_->counter();
}

template<typename T>
auto allocator<T>::full() const -> bool
{
	return map_->counter()==size_;
}

template<typename T>
auto allocator<T>::empty() const -> bool
{
	return map_->counter()==0;
}

template<typename T>
auto allocator<T>::swap(allocator & other) -> void {
	std::swap(ptr_, other.ptr_);
	std::swap(map_, other.map_);
	std::swap(size_, other.size_);
}

template <typename T>
size_t stack<T>::count() const
{
	return allocator_.count();
}
template <typename T>
stack<T>::stack(size_t size) :allocator_(size) {}

template <typename T>
void stack<T>::push(T const &item) {
	if (allocator_.full()) allocator_.resize();
	allocator_.construct(allocator_.get() + this->count(), item);
}
template<typename T>
void stack<T>::pop()
{
	if (this->count() > 0)
		allocator_.destroy(allocator_.get() + (this->count()-1));
	else throw_is_empty();
}
template<typename T>
auto stack<T>::top() -> T &
{
	if (allocator_.count() == 0) {
		throw_is_empty();
	}
	return (*(allocator_.get() + allocator_.count() - 1));
}
template<typename T>
auto stack<T>::top() const -> T const &
{
	if (allocator_.count() == 0) {
		throw_is_empty();
	}
	return (*(allocator_.get() + allocator_.count() - 1));
}

template<typename T>
auto stack<T>::throw_is_empty() const -> void
{
		throw("Stack is empty!");
}

template<typename T>
auto stack<T>::operator =(stack const & right)-> stack &{
	if (this != &right) {
		(allocator<T>(right.allocator_)).swap(allocator_);
	}
	return *this;
}
template<typename T>
auto stack<T>::empty() const -> bool {
	return allocator_.empty();
}

#endif
<commit_msg>Update stack.hpp<commit_after>#ifndef stack_cpp
#define stack_cpp
#pragma once
#include <iostream>
#include <memory>

class bitset
{
public:
	explicit
		bitset(size_t size) /*strong*/;

	bitset(bitset const & other) = delete;
	auto operator =(bitset const & other)->bitset & = delete;

	bitset(bitset && other) = delete;
	auto operator =(bitset && other)->bitset & = delete;

	auto set(size_t index) /*strong*/ -> void;
	auto reset(size_t index) /*strong*/ -> void;
	auto test(size_t index) /*strong*/ -> bool;

	auto size() const /*noexcept*/ -> size_t;
	auto counter() const /*noexcept*/ -> size_t;

private:
	std::unique_ptr<bool[]>  ptr_;
	size_t size_;
	size_t counter_;
};

bitset::bitset(size_t size) : ptr_(std::make_unique<bool[]>(size)), size_(size), counter_(0) {}

auto bitset::set(size_t index) -> void
{ if (index < size_) {
	ptr_[index] = true;
	++counter_; }
	else throw("false_index");
}

auto bitset::reset(size_t index) -> void
{	if (index < size_)
	{
		ptr_[index] = false;
		--counter_;
	}
	else throw("false_index");
}

auto bitset::test(size_t index) -> bool
{
	if (index < size_)
	{
		return !ptr_[index];
	}
	else throw("false_index");

}
auto bitset::size() const -> size_t
{
	return size_;
}

auto bitset::counter() const -> size_t
{
	return counter_;
}

template <typename T>
class allocator
{
public:
	explicit
		allocator(std::size_t size = 0) /*strong*/;
	allocator(allocator const & other) /*strong*/;
	auto operator =(allocator const & other)->allocator & = delete;
	~allocator();

	auto resize() /*strong*/ -> void;

	auto construct(T * ptr, T const & value) /*strong*/ -> void;
	auto destroy(T * ptr) /*noexcept*/ -> void;

	auto get() /*noexcept*/ -> T *;
	auto get() const /*noexcept*/ -> T const *;

	auto count() const /*noexcept*/ -> size_t;
	auto full() const /*noexcept*/ -> bool;
	auto empty() const /*noexcept*/ -> bool;
private:
	auto destroy(T * first, T * last) /*noexcept*/ -> void;
	auto swap(allocator & other) /*noexcept*/ -> void;

	T * ptr_;
	size_t size_;
	std::unique_ptr<bitset> map_;
};

template <typename T>
class stack
{
public:
	explicit
		stack(size_t size = 0);
	auto operator =(stack const & other) /*strong*/ -> stack &;

	auto empty() const /*noexcept*/ -> bool;
	auto count() const /*noexcept*/ -> size_t;

	auto push(T const & value) /*strong*/ -> void;
	auto pop() /*strong*/ -> void;
	auto top() /*strong*/ -> T &;
	auto top() const /*strong*/ -> T const &;

private:
	allocator<T> allocator_;

	auto throw_is_empty() const -> void;
};

template <typename T>
allocator<T>::allocator(size_t size) : ptr_((T*)(operator new(size*sizeof(T)))), size_(size), map_(std::make_unique<bitset>(size)) {};

template<typename T>
	allocator<T>::allocator(allocator const& other) :
	allocator<T>(other.size_){
	for (size_t i=0; i < size_; ++i)
		if (other.map_->test(i))
		construct(ptr_ + i, other.ptr_[i]);
}
template<typename T>
allocator<T>::~allocator() {
	destroy(ptr_, ptr_+size_);
	operator delete(ptr_);
}

template<typename T>
auto allocator<T>::resize() -> void
{
	allocator<T> buff(size_ * 2 + (size_ == 0));
	for (size_t i = 0; i < size_; ++i) construct(buff.ptr_ + i, ptr_[i]);
	this->swap(buff);
}

template<typename T>
auto allocator<T>::construct(T * ptr, T const & value)->void {
	if (ptr >= ptr_&&ptr < ptr_ + size_&&map_->test(ptr - ptr_)) {
		new(ptr)T(value);
		map_->set(ptr - ptr_);
	}
	else throw("error");
}

template<typename T>
auto allocator<T>::destroy(T * ptr) -> void {
	if(ptr>=ptr_&&ptr<=ptr_+this->size())
	if (!map_->test(ptr-ptr_){
	ptr->~T();
	map_->reset(ptr-ptr_);
	}
}
	else throw("error");
}

template<typename T>
auto allocator<T>::destroy(T * first, T * last) -> void
{	if(first>=ptr_&&last<=ptr_+this->())
	for (; first != last; ++first) {
		destroy(&*first);
	}
}

template<typename T>
auto allocator<T>::get()-> T* {
	return ptr_;
}

template<typename T>
auto allocator<T>::get() const -> T const * {
	return ptr_;
}

template<typename T>
auto allocator<T>::count() const -> size_t
{
	return map_->counter();
}

template<typename T>
auto allocator<T>::full() const -> bool
{
	return map_->counter()==size_;
}

template<typename T>
auto allocator<T>::empty() const -> bool
{
	return map_->counter()==0;
}

template<typename T>
auto allocator<T>::swap(allocator & other) -> void {
	std::swap(ptr_, other.ptr_);
	std::swap(map_, other.map_);
	std::swap(size_, other.size_);
}

template <typename T>
size_t stack<T>::count() const
{
	return allocator_.count();
}
template <typename T>
stack<T>::stack(size_t size) :allocator_(size) {}

template <typename T>
void stack<T>::push(T const &item) {
	if (allocator_.full()) allocator_.resize();
	allocator_.construct(allocator_.get() + this->count(), item);
}
template<typename T>
void stack<T>::pop()
{
	if (this->count() > 0)
		allocator_.destroy(allocator_.get() + (this->count()-1));
	else throw_is_empty();
}
template<typename T>
auto stack<T>::top() -> T &
{
	if (allocator_.count() == 0) {
		throw_is_empty();
	}
	return (*(allocator_.get() + allocator_.count() - 1));
}
template<typename T>
auto stack<T>::top() const -> T const &
{
	if (allocator_.count() == 0) {
		throw_is_empty();
	}
	return (*(allocator_.get() + allocator_.count() - 1));
}

template<typename T>
auto stack<T>::throw_is_empty() const -> void
{
		throw("Stack is empty!");
}

template<typename T>
auto stack<T>::operator =(stack const & right)-> stack &{
	if (this != &right) {
		(allocator<T>(right.allocator_)).swap(allocator_);
	}
	return *this;
}
template<typename T>
auto stack<T>::empty() const -> bool {
	return allocator_.empty();
}

#endif
<|endoftext|>


<commit_before>#ifndef stack_cpp
#define stack_cpp
#pragma once
#include <iostream>
#include <memory>
#include <thread>
#include <mutex>
class bitset
{
public:
	explicit
		bitset(size_t size) /*strong*/;

	bitset(bitset const & other) = delete;
	auto operator =(bitset const & other)->bitset & = delete;

	bitset(bitset && other) = delete;
	auto operator =(bitset && other)->bitset & = delete;

	auto set(size_t index) /*strong*/ -> void;
	auto reset(size_t index) /*strong*/ -> void;
	auto test(size_t index) /*strong*/ -> bool;

	auto size() const /*noexcept*/ -> size_t;
	auto counter() const /*noexcept*/ -> size_t;

private:
	std::unique_ptr<bool[]>  ptr_;
	size_t size_;
	size_t counter_;
};

bitset::bitset(size_t size) : ptr_(std::make_unique<bool[]>(size)), size_(size), counter_(0) {}

auto bitset::set(size_t index) -> void
{ if (index < size_) {
	ptr_[index] = true;
	++counter_; }
	else throw("false_index");
}

auto bitset::reset(size_t index) -> void
{	if (index < size_)
	{
		ptr_[index] = false;
		--counter_;
	}
	else throw("false_index");
}

auto bitset::test(size_t index) -> bool
{
	if (index < size_)
	{
		return !ptr_[index];
	}
	else throw("false_index");

}
auto bitset::size() const -> size_t
{
	return size_;
}

auto bitset::counter() const -> size_t
{
	return counter_;
}

template <typename T>
class allocator
{
public:
	explicit
		allocator(std::size_t size = 0) /*strong*/;
	allocator(allocator const & other) /*strong*/;
	auto operator =(allocator const & other)->allocator & = delete;
	~allocator();

	auto resize() /*strong*/ -> void;

	auto construct(T * ptr, T const & value) /*strong*/ -> void;
	auto destroy(T * ptr) /*noexcept*/ -> void;

	auto get() /*noexcept*/ -> T *;
	auto get() const /*noexcept*/ -> T const *;

	auto count() const /*noexcept*/ -> size_t;
	auto full() const /*noexcept*/ -> bool;
	auto swap(allocator & other) /*noexcept*/ -> void;
	auto empty() const /*noexcept*/ -> bool;
private:
	auto destroy(T * first, T * last) /*noexcept*/ -> void;
	T * ptr_;
	size_t size_;
	std::unique_ptr<bitset> map_;
};

template <typename T>
allocator<T>::allocator(size_t size) : ptr_((T*)(operator new(size*sizeof(T)))), size_(size), map_(std::make_unique<bitset>(size)) {};

template<typename T>
	allocator<T>::allocator(allocator const& other) :
	allocator<T>(other.size_){
	for (size_t i=0; i < size_; ++i)
		if (other.map_->test(i))
		construct(ptr_ + i, other.ptr_[i]);
}
template<typename T>
allocator<T>::~allocator() {
	destroy(ptr_, ptr_+size_);
	operator delete(ptr_);
}

template<typename T>
auto allocator<T>::resize() -> void
{
	allocator<T> buff(size_ * 2 + (size_ == 0));
	for (size_t i = 0; i < size_; ++i) construct(buff.ptr_ + i, ptr_[i]);
	this->swap(buff);
}

template<typename T>
auto allocator<T>::construct(T * ptr, T const & value)->void {
	if (ptr >= ptr_&&ptr < ptr_ + size_&&map_->test(ptr - ptr_)) {
		new(ptr)T(value);
		map_->set(ptr - ptr_);
	}
	else throw("error");
}

template<typename T>
auto allocator<T>::destroy(T * ptr) -> void {
	if(ptr>=ptr_&&ptr<=ptr_+this->size_){
	if (!map_->test(ptr-ptr_)){
	ptr->~T();
	map_->reset(ptr-ptr_);
	}
}
	else throw("error");
}

template<typename T>
auto allocator<T>::destroy(T * first, T * last) -> void
{	if(first>=ptr_&&last<=ptr_+this->size_)
	for (; first != last; ++first) {
		destroy(&*first);
	}
}

template<typename T>
auto allocator<T>::get()-> T* {
	return ptr_;
}

template<typename T>
auto allocator<T>::get() const -> T const * {
	return ptr_;
}

template<typename T>
auto allocator<T>::count() const -> size_t
{
	return map_->counter();
}

template<typename T>
auto allocator<T>::full() const -> bool
{
	return map_->counter()==size_;
}

template<typename T>
auto allocator<T>::empty() const -> bool
{
	return map_->counter()==0;
}

template<typename T>
auto allocator<T>::swap(allocator & other) -> void {
	std::swap(ptr_, other.ptr_);
	std::swap(map_, other.map_);
	std::swap(size_, other.size_);
}
template <typename T>
class stack
{
public:
	explicit
	stack(size_t size = 0);
	stack(stack const & other);
	auto operator =(stack const & other) /*strong*/ -> stack &;

	auto empty() const /*noexcept*/ -> bool;
	auto count() const /*noexcept*/ -> size_t;

	auto push(T const & value) /*strong*/ -> void;
	auto pop() /*strong*/ -> void;
	auto top() /*strong*/ -> T &;
	auto top() const /*strong*/ -> T const &;

private:
	allocator<T> allocator_;
	mutable std::mutex m;
	auto throw_is_empty() const -> void;
};
template <typename T>
size_t stack<T>::count() const
{
	return allocator_.count();
}

template<typename T>
stack<T>::stack(stack const & other): allocator_(other.allocator_), m(){};
template <typename T>
stack<T>::stack(size_t size):allocator_(size), m() {} ;

template <typename T>
void stack<T>::push(T const &item) {
	std::lock_guard<std::mutex> locker(m);
	if (allocator_.full()) allocator_.resize();
	allocator_.construct(allocator_.get() + this->count(), item);
}
template<typename T>
void stack<T>::pop()
{
	std::lock_guard<std::mutex> locker(m);
	if (this->count() > 0)
		allocator_.destroy(allocator_.get() + (this->count()-1));
	else throw_is_empty();
}
template<typename T>
auto stack<T>::top() -> T &
{
	std::lock_guard<std::mutex> locker(m);
	if (allocator_.count() == 0) {
		throw_is_empty();
	}
	return (*(allocator_.get() + allocator_.count() - 1));
}
template<typename T>
auto stack<T>::top() const -> T const &
{
	std::lock_guard<std::mutex> locker(m);
	if (allocator_.count() == 0) {
		throw_is_empty();
	}
	return (*(allocator_.get() + allocator_.count() - 1));
}

template<typename T>
auto stack<T>::throw_is_empty() const -> void
{
		throw("Stack is empty!");
}

template<typename T>
auto stack<T>::operator =(stack const & right)-> stack &{
	if (this != &right) {
		std::lock(m, right.m);
		std::lock_guard<std::mutex> locker1(m, std::adopt_lock);
		std::lock_guard<std::mutex> locker2(right.m, std::adopt_lock);
		(allocator<T>(right.allocator_)).swap(allocator_);
	}
	return *this;
}
template<typename T>
auto stack<T>::empty() const -> bool {
	return allocator_.empty();
}

#endif
<commit_msg>Update stack.hpp<commit_after>#ifndef stack_cpp
#define stack_cpp
#pragma once
#include <iostream>
#include <memory>
#include <thread>
#include <mutex>

class bitset
{
public:
	explicit bitset(size_t size) /*strong*/;

	bitset(bitset const & other) = delete;
	auto operator =(bitset const & other)->bitset & = delete;

	bitset(bitset && other) = delete;
	auto operator =(bitset && other)->bitset & = delete;

	auto set(size_t index) /*strong*/ -> void;
	auto reset(size_t index) /*strong*/ -> void;
	auto test(size_t index) /*strong*/ -> bool;

	auto size() /*noexcept*/ -> size_t;
	auto counter() /*noexcept*/ -> size_t;
private:
	std::unique_ptr<bool[]>  ptr_;
	size_t size_;
	size_t counter_;
};

bitset::bitset(size_t size) : ptr_(std::make_unique<bool[]>(size)), size_(size), counter_(0){}

auto bitset::set(size_t index)->void {
	if (index >= 0 && index < size_) { ptr_[index] = true; ++counter_; }
	else throw("bad_index");
}

auto bitset::reset(size_t index)->void {
	if (index >= 0 && index < size_) { ptr_[index] = false; --counter_; }
	else throw("bad_index");
}

auto bitset::test(size_t index)->bool {
	if (index >= 0 && index < size_) return !ptr_[index];
	else throw("bad_index");
}

auto bitset::size()->size_t{ return size_; }

auto bitset::counter()->size_t{ return counter_; }

template <typename T>
class allocator{
public:
	explicit allocator(std::size_t size = 0) /*strong*/;
	allocator(allocator const & other) /*strong*/;
	auto operator =(allocator const & other)->allocator & = delete;
	~allocator();

	auto resize() /*strong*/ -> void;

	auto construct(T * ptr, T const & value) /*strong*/ -> void;
	auto destroy(T * ptr) /*noexcept*/ -> void;

	auto get() /*noexcept*/ -> T *;
	auto get() const /*noexcept*/ -> T const *;

	auto count() const /*noexcept*/ -> size_t;
	auto full() const /*noexcept*/ -> bool;
	auto empty() const /*noexcept*/ -> bool;
	auto swap(allocator & other) /*noexcept*/ -> void;
private:
	auto destroy(T * first, T * last) /*noexcept*/ -> void;
	size_t count_;
	T * ptr_;
	size_t size_;
	std::unique_ptr<bitset> map_;
};

template<typename T>
allocator<T>::allocator(size_t size) : ptr_((T*)operator new(size*sizeof(T))), size_(size), map_(std::make_unique<bitset>(size)), count_(0) {}

template<typename T>
allocator<T>::allocator(allocator const& other) : allocator<T>(other.size_) {
	for (size_t i = 0; i < other.count_; i++) if(map_->test(i)) construct(ptr_ + i, other.ptr_[i]);
}

template<typename T>
allocator<T>::~allocator(){
	if (this->count() > 0) {
		destroy(ptr_, ptr_ + size_);
	}
	operator delete(ptr_);
}

template<typename T>
auto allocator<T>::resize()->void{
	allocator<T> al(size_ * 2 + (size_ == 0));
	for (size_t i = 0; i < size_; ++i) if (al.map_->test(i)) al.construct(al.get() + i, ptr_[i]);
	al.swap(*this);
}

template<typename T>
auto allocator<T>::construct(T * ptr, T const & value)->void{
	if (ptr >= ptr_&&ptr < ptr_ + size_){
		new(ptr)T(value);
		map_->set(ptr - ptr_);
		++count_;
	}
	else { throw("error"); }
}

template<typename T>
auto allocator<T>::destroy(T* ptr)->void{
	if (!map_->test(ptr - ptr_) && ptr >= ptr_&&ptr <= ptr_ + this->count())
	{
		ptr->~T();
		map_->reset(ptr - ptr_);
		--count_;
	}
}

template<typename T>
auto allocator<T>::get()-> T* { return ptr_; }

template<typename T>
auto allocator<T>::get() const -> T const * { return ptr_; }

template<typename T>
auto allocator<T>::count() const -> size_t{ return count_; }

template<typename T>
auto allocator<T>::full() const -> bool { return (map_->counter() == size_); }

template<typename T>
auto allocator<T>::empty() const -> bool { return (map_->counter() == 0); }

template<typename T>
auto allocator<T>::destroy(T * first, T * last)->void{
	if (first >= ptr_&&last <= ptr_ + this->count())
	for (; first != last; ++first) {
		destroy(&*first);
	}
}

template<typename T>
auto allocator<T>::swap(allocator & other)->void{
	std::swap(ptr_, other.ptr_);
	std::swap(size_, other.size_);
	std::swap(map_, other.map_);
	std::swap(count_, other.count_);
}

template <typename T>
class stack {
public:
	explicit stack(size_t size = 0);
	stack(stack const & other); /*strong*/
	auto operator =(stack const & other) /*strong*/ -> stack &;

	auto empty() const /*noexcept*/ -> bool;
	auto count() const /*noexcept*/ -> size_t;

	auto push(T const & value) /*strong*/ -> void;
	auto pop() /*strong*/ -> std::shared_ptr<T>;
	//auto top()const -> const T&;

private:
	allocator<T> allocator_;
	auto throw_is_empty()/*strong*/ const -> void;
	mutable std::mutex m;
};

template <typename T>
stack<T>::stack(size_t size) : allocator_(size), m() {};

template <typename T>
stack<T>::stack(stack const & other) : allocator_(0), m()
{
	std::lock_guard<std::mutex> locker2(other.m);
	allocator_.swap(allocator<T>(other.allocator_));
}

template <typename T>
auto stack<T>::operator=(const stack &other)->stack&
{
	if (this != &other)
	{
		std::lock(m, other.m);
		std::lock_guard<std::mutex> locker1(m, std::adopt_lock);
		std::lock_guard<std::mutex> locker2(other.m, std::adopt_lock);
		(allocator<T>(other.allocator_)).swap(allocator_);
	}
	return *this;
}

template<typename T>
auto stack<T>::empty() const->bool
{
	std::lock_guard<std::mutex> locker(m);
	return (allocator_.count() == 0);
}

template <typename T>
auto stack<T>::count() const ->size_t
{
	std::lock_guard<std::mutex> lockerk(m);
	return allocator_.count();
}

template <typename T>
auto stack<T>::push(T const &val)->void
{
	std::lock_guard<std::mutex> locker(m);
	if (allocator_.full())
	{
		allocator_.resize();
	}
	allocator_.construct(allocator_.get() + allocator_.count(), val);
}

template <typename T>
auto stack<T>::pop()->std::shared_ptr<T>
{
	std::lock_guard<std::mutex> locker(m);
	if (allocator_.count() == 0) throw_is_empty();
	std::shared_ptr<T> top_(std::make_shared<T>(std::move(allocator_.get()[allocator_.count() - 1])));
	allocator_.destroy(allocator_.get() + allocator_.count() - 1);
	return top_;
}

template <typename T>
auto stack<T>::throw_is_empty()const->void
{
	std::lock_guard<std::mutex> lk(m);
	throw("EMPTY!");
}

#endif
<|endoftext|>


<commit_before>#pragma warning(push)
#pragma warning(disable:4996)
#pragma warning(disable:4244)
#pragma warning(disable:4291)
#pragma warning(disable:4146)

#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/GraphWriter.h"

#pragma warning(pop)

#include <functional>

using namespace std;
using namespace clang;
using namespace clang::tooling;
using namespace llvm;

// ***************************************************************************
//          vvZbT̃R[obN
// ***************************************************************************

class cincluder : public PPCallbacks {
private:
    Preprocessor &PP;

	typedef ::std::hash< ::std::string > hash;
	typedef ::std::list< hash::result_type > hash_list;

	struct header
	{
		header() : angled(false) {}
		header(const ::std::string& n, bool angled_) : name(n), angled(angled_) {}
		::std::string name;
		bool angled;
		hash_list include;
	};
	typedef ::std::map< hash::result_type, header > Map;
	typedef ::std::map< hash::result_type, hash_list > Depend;
	Map m_includes;
	Depend m_depends;
	hash::result_type m_root;
	::std::string m_output;
public:
	cincluder(Preprocessor &pp) : PP(pp) {}
	cincluder(Preprocessor &pp, const ::std::string& output) : PP(pp), m_output(output) {}

	const header& getHeader(hash::result_type h)
	{
		return m_includes[h];
	}

	::std::string getFilePath(hash::result_type h)
	{
		return m_includes[h].name;
	}
	::std::string getFileName(hash::result_type h)
	{
		::std::string path = getFilePath(h);
		size_t dpos1 = path.rfind('\\');
		size_t dpos2 = path.rfind('/');
		if( dpos1 == ::std::string::npos ) dpos1 = 0;
		if( dpos2 == ::std::string::npos ) dpos2 = 0;
		const size_t dpos = (::std::max)(dpos1, dpos2) + 1;

		return path.substr( dpos );
	}
	::std::string getFileName(const header& h)
	{
		::std::string path = h.name;
		size_t dpos1 = path.rfind('\\');
		size_t dpos2 = path.rfind('/');
		if( dpos1 == ::std::string::npos ) dpos1 = 0;
		if( dpos2 == ::std::string::npos ) dpos2 = 0;
		const size_t dpos = (::std::max)(dpos1, dpos2) + 1;

		return path.substr(dpos);
	}

	void printRoot(hash::result_type h, int indent, bool expand)
	{
		if( indent > 2 ) return;
		for( int i = 0; i < indent; ++i ) errs() << "  ";
		if( expand ) errs() << "+ ";
		else errs() << "  ";
		errs() << getFileName(h) << "\n";

		if( m_depends.find(h) != m_depends.end() )
		{
			auto depend = m_depends[h];
			if( depend.size() > 1 ) ++indent;
			for( auto d : depend )
			{
				printRoot(d, indent, (depend.size() > 1));
			}
		}
	}

	void report()
	{
		for( auto h : m_depends )
		{
			if( h.second.size() > 1 )
			{
				errs() << getFileName(h.first) << " is already include by \n";
				for( auto d : h.second )
				{
					printRoot(d, 1, true);
				}
			}
		}
	}

	void writeID(raw_ostream& OS, hash::result_type h)
	{
		OS << "header_" << h;
	}

	void dot()
	{
		if( m_output.empty() ) return;
		std::error_code EC;
		llvm::raw_fd_ostream OS(m_output, EC, llvm::sys::fs::F_Text);
		if( EC )
		{
			PP.getDiagnostics().Report(diag::err_fe_error_opening) << m_output
				<< EC.message();
			return;
		}
		const char* endl = "\n";

		OS << "digraph \"dependencies\" {" << endl;

		for( auto inc : m_includes )
		{
			writeID(OS, inc.first);
			OS << " [ shape=\"box\", label=\"";
			OS << DOT::EscapeString(getFileName(inc.second));
			OS << "\"];" << endl;
		}

		for( auto h : m_depends )
		{
			for(auto depend : h.second)
			{
				writeID(OS, h.first);
				OS << " -> ";
				writeID(OS, depend);
				OS << endl;
			}
		}

		OS << "}" << endl;
	}

	void EndOfMainFile() override
	{
		report();
		dot();
	}

    void InclusionDirective(SourceLocation HashLoc,
                          const Token &IncludeTok,
                          llvm::StringRef FileName,
                          bool IsAngled,
                          CharSourceRange FilenameRange,
                          const FileEntry *File,
                          llvm::StringRef SearchPath,
                          llvm::StringRef RelativePath,
                          const Module *Imported) override
	{
		if( File == nullptr ) return;

		SourceManager& SM = PP.getSourceManager();
		const FileEntry* pFromFile = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
		if( pFromFile == nullptr ) return;

		const auto h = hash()(File->getName());
		const auto p = hash()(pFromFile->getName());
		{
			if( m_includes.find(h) == m_includes.end() )
			{
				m_includes.insert(::std::make_pair(h, header(File->getName(), IsAngled)));
			}

			auto it = m_includes.find(p);
			if( it == m_includes.end() )
			{
				m_root = p;
				m_includes.insert(::std::make_pair(p, header(pFromFile->getName(), false)));
			}
			if( it != m_includes.end() )
			{
				it->second.include.push_back(h);
			}
		}
		if( !IsAngled )
		{
			auto it = m_depends.find(h);
			if( it != m_depends.end() )
			{
				it->second.push_back(p);
			}
			else
			{
				hash_list a;
				a.push_back(p);
				m_depends.insert(::std::make_pair(h, a));
			}
		}

#if 0
        errs() << "InclusionDirective : ";
        if (File) {
            if (IsAngled)   errs() << "<" << File->getName() << ">\n";
            else            errs() << "\"" << File->getName() << "\"\n";
        } else {
            errs() << "not found file ";
            if (IsAngled)   errs() << "<" << FileName << ">\n";
            else            errs() << "\"" << FileName << "\"\n";
        }
#endif
    }
};

class ExampleASTConsumer : public ASTConsumer {
private:
public:
	explicit ExampleASTConsumer(CompilerInstance *CI) {
		// vvZbT̃R[obNo^
		Preprocessor &PP = CI->getPreprocessor();
		PP.addPPCallbacks(llvm::make_unique<cincluder>(PP, "test.dot"));
		//AttachDependencyGraphGen(PP, "test.dot", "");
	}
};

class ExampleFrontendAction : public SyntaxOnlyAction /*ASTFrontendAction*/ {
public:
	virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef file) {
		return llvm::make_unique<ExampleASTConsumer>(&CI); // pass CI pointer to ASTConsumer
	}
};

static cl::OptionCategory MyToolCategory("cincluder");
int main(int argc, const char** argv)
{
	CommonOptionsParser op(argc, argv, MyToolCategory);
	ClangTool Tool(op.getCompilations(), op.getSourcePathList());
	return Tool.run(newFrontendActionFactory<ExampleFrontendAction>().get());
}

<commit_msg>write hex<commit_after>#pragma warning(push)
#pragma warning(disable:4996)
#pragma warning(disable:4244)
#pragma warning(disable:4291)
#pragma warning(disable:4146)

#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/GraphWriter.h"

#pragma warning(pop)

#include <functional>

using namespace std;
using namespace clang;
using namespace clang::tooling;
using namespace llvm;

// ***************************************************************************
//          vvZbT̃R[obN
// ***************************************************************************

class cincluder : public PPCallbacks {
private:
    Preprocessor &PP;

	typedef ::std::hash< ::std::string > hash;
	typedef ::std::list< hash::result_type > hash_list;

	struct header
	{
		header() : angled(false) {}
		header(const ::std::string& n, bool angled_) : name(n), angled(angled_) {}
		::std::string name;
		bool angled;
		hash_list include;
	};
	typedef ::std::map< hash::result_type, header > Map;
	typedef ::std::map< hash::result_type, hash_list > Depend;
	Map m_includes;
	Depend m_depends;
	hash::result_type m_root;
	::std::string m_output;
public:
	cincluder(Preprocessor &pp) : PP(pp) {}
	cincluder(Preprocessor &pp, const ::std::string& output) : PP(pp), m_output(output) {}

	const header& getHeader(hash::result_type h)
	{
		return m_includes[h];
	}

	::std::string getFilePath(hash::result_type h)
	{
		return m_includes[h].name;
	}
	::std::string getFileName(hash::result_type h)
	{
		::std::string path = getFilePath(h);
		size_t dpos1 = path.rfind('\\');
		size_t dpos2 = path.rfind('/');
		if( dpos1 == ::std::string::npos ) dpos1 = 0;
		if( dpos2 == ::std::string::npos ) dpos2 = 0;
		const size_t dpos = (::std::max)(dpos1, dpos2) + 1;

		return path.substr( dpos );
	}
	::std::string getFileName(const header& h)
	{
		::std::string path = h.name;
		size_t dpos1 = path.rfind('\\');
		size_t dpos2 = path.rfind('/');
		if( dpos1 == ::std::string::npos ) dpos1 = 0;
		if( dpos2 == ::std::string::npos ) dpos2 = 0;
		const size_t dpos = (::std::max)(dpos1, dpos2) + 1;

		return path.substr(dpos);
	}

	void printRoot(hash::result_type h, int indent, bool expand)
	{
		if( indent > 2 ) return;
		for( int i = 0; i < indent; ++i ) errs() << "  ";
		if( expand ) errs() << "+ ";
		else errs() << "  ";
		errs() << getFileName(h) << "\n";

		if( m_depends.find(h) != m_depends.end() )
		{
			auto depend = m_depends[h];
			if( depend.size() > 1 ) ++indent;
			for( auto d : depend )
			{
				printRoot(d, indent, (depend.size() > 1));
			}
		}
	}

	void report()
	{
		for( auto h : m_depends )
		{
			if( h.second.size() > 1 )
			{
				errs() << getFileName(h.first) << " is already include by \n";
				for( auto d : h.second )
				{
					printRoot(d, 1, true);
				}
			}
		}
	}

	void writeID(raw_ostream& OS, hash::result_type h)
	{
		OS << "header_";
		OS.write_hex(h);
	}

	void dot()
	{
		if( m_output.empty() ) return;
		std::error_code EC;
		llvm::raw_fd_ostream OS(m_output, EC, llvm::sys::fs::F_Text);
		if( EC )
		{
			PP.getDiagnostics().Report(diag::err_fe_error_opening) << m_output
				<< EC.message();
			return;
		}
		const char* endl = "\n";

		OS << "digraph \"dependencies\" {" << endl;

		for( auto inc : m_includes )
		{
			writeID(OS, inc.first);
			OS << " [ shape=\"box\", label=\"";
			OS << DOT::EscapeString(getFileName(inc.second));
			OS << "\"];" << endl;
		}

		for( auto h : m_depends )
		{
			for(auto depend : h.second)
			{
				writeID(OS, h.first);
				OS << " -> ";
				writeID(OS, depend);
				OS << endl;
			}
		}

		OS << "}" << endl;
	}

	void EndOfMainFile() override
	{
		report();
		dot();
	}

    void InclusionDirective(SourceLocation HashLoc,
                          const Token &IncludeTok,
                          llvm::StringRef FileName,
                          bool IsAngled,
                          CharSourceRange FilenameRange,
                          const FileEntry *File,
                          llvm::StringRef SearchPath,
                          llvm::StringRef RelativePath,
                          const Module *Imported) override
	{
		if( File == nullptr ) return;

		SourceManager& SM = PP.getSourceManager();
		const FileEntry* pFromFile = SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
		if( pFromFile == nullptr ) return;

		const auto h = hash()(File->getName());
		const auto p = hash()(pFromFile->getName());
		{
			if( m_includes.find(h) == m_includes.end() )
			{
				m_includes.insert(::std::make_pair(h, header(File->getName(), IsAngled)));
			}

			auto it = m_includes.find(p);
			if( it == m_includes.end() )
			{
				m_root = p;
				m_includes.insert(::std::make_pair(p, header(pFromFile->getName(), false)));
			}
			if( it != m_includes.end() )
			{
				it->second.include.push_back(h);
			}
		}
		if( !IsAngled )
		{
			auto it = m_depends.find(h);
			if( it != m_depends.end() )
			{
				it->second.push_back(p);
			}
			else
			{
				hash_list a;
				a.push_back(p);
				m_depends.insert(::std::make_pair(h, a));
			}
		}

#if 0
        errs() << "InclusionDirective : ";
        if (File) {
            if (IsAngled)   errs() << "<" << File->getName() << ">\n";
            else            errs() << "\"" << File->getName() << "\"\n";
        } else {
            errs() << "not found file ";
            if (IsAngled)   errs() << "<" << FileName << ">\n";
            else            errs() << "\"" << FileName << "\"\n";
        }
#endif
    }
};

class ExampleASTConsumer : public ASTConsumer {
private:
public:
	explicit ExampleASTConsumer(CompilerInstance *CI) {
		// vvZbT̃R[obNo^
		Preprocessor &PP = CI->getPreprocessor();
		PP.addPPCallbacks(llvm::make_unique<cincluder>(PP, "test.dot"));
		//AttachDependencyGraphGen(PP, "test.dot", "");
	}
};

class ExampleFrontendAction : public SyntaxOnlyAction /*ASTFrontendAction*/ {
public:
	virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef file) {
		return llvm::make_unique<ExampleASTConsumer>(&CI); // pass CI pointer to ASTConsumer
	}
};

static cl::OptionCategory MyToolCategory("cincluder");
int main(int argc, const char** argv)
{
	CommonOptionsParser op(argc, argv, MyToolCategory);
	ClangTool Tool(op.getCompilations(), op.getSourcePathList());
	return Tool.run(newFrontendActionFactory<ExampleFrontendAction>().get());
}

<|endoftext|>


<commit_before>/**
 * @file lars.cpp
 * @author Nishant Mehta (niche)
 *
 * Implementation of LARS and LASSO.
 */
#include "lars.hpp"

using namespace mlpack;
using namespace mlpack::regression;

LARS::LARS(const bool useCholesky,
           const double lambda1,
           const double lambda2,
           const double tolerance) :
    matGram(matGramInternal),
    useCholesky(useCholesky),
    lasso((lambda1 != 0)),
    lambda1(lambda1),
    elasticNet((lambda1 != 0) && (lambda2 != 0)),
    lambda2(lambda2),
    tolerance(tolerance)
{ /* Nothing left to do. */ }

LARS::LARS(const bool useCholesky,
           const arma::mat& gramMatrix,
           const double lambda1,
           const double lambda2,
           const double tolerance) :
    matGram(gramMatrix),
    useCholesky(useCholesky),
    lasso((lambda1 != 0)),
    lambda1(lambda1),
    elasticNet((lambda1 != 0) && (lambda2 != 0)),
    lambda2(lambda2),
    tolerance(tolerance)
{ /* Nothing left to do */ }

void LARS::Regress(const arma::mat& matX,
                   const arma::vec& y,
                   arma::vec& beta,
                   const bool rowMajor)
{
  Timer::Start("lars_regression");

  // This matrix may end up holding the transpose -- if necessary.
  arma::mat dataTrans;
  // dataRef is row-major.
  const arma::mat& dataRef = (rowMajor ? matX : dataTrans);
  if (!rowMajor)
    dataTrans = trans(matX);

  // Compute X' * y.
  arma::vec vecXTy = trans(dataRef) * y;

  // Set up active set variables.  In the beginning, the active set has size 0
  // (all dimensions are inactive).
  isActive.resize(dataRef.n_cols, false);

  // Initialize yHat and beta.
  beta = arma::zeros(dataRef.n_cols);
  arma::vec yHat = arma::zeros(dataRef.n_rows);
  arma::vec yHatDirection = arma::vec(dataRef.n_rows);

  bool lassocond = false;

  // Compute the initial maximum correlation among all dimensions.
  arma::vec corr = vecXTy;
  double maxCorr = 0;
  size_t changeInd = 0;
  for (size_t i = 0; i < vecXTy.n_elem; ++i)
  {
    if (fabs(corr(i)) > maxCorr)
    {
      maxCorr = fabs(corr(i));
      changeInd = i;
    }
  }

  betaPath.push_back(beta);
  lambdaPath.push_back(maxCorr);

  // If the maximum correlation is too small, there is no reason to continue.
  if (maxCorr < lambda1)
  {
    lambdaPath[0] = lambda1;
    return;
  }

  // Compute the Gram matrix.  If this is the elastic net problem, we will add
  // lambda2 * I_n to the matrix.
  if (matGram.n_elem == 0)
  {
    // In this case, matGram should reference matGramInternal.
    matGramInternal = trans(dataRef) * dataRef;

    if (elasticNet && !useCholesky)
      matGramInternal += lambda2 * arma::eye(dataRef.n_cols, dataRef.n_cols);
  }

  // Main loop.
  while ((activeSet.size() < dataRef.n_cols) && (maxCorr > tolerance))
  {
    // Compute the maximum correlation among inactive dimensions.
    maxCorr = 0;
    for (size_t i = 0; i < dataRef.n_cols; i++)
    {
      if ((!isActive[i]) && (fabs(corr(i)) > maxCorr))
      {
        maxCorr = fabs(corr(i));
        changeInd = i;
      }
    }

    if (!lassocond)
    {
      if (useCholesky)
      {
        // vec newGramCol = vec(activeSet.size());
        // for (size_t i = 0; i < activeSet.size(); i++)
        // {
        //   newGramCol[i] = dot(matX.col(activeSet[i]), matX.col(changeInd));
        // }
        // This is equivalent to the above 5 lines.
        arma::vec newGramCol = matGram.elem(changeInd * dataRef.n_cols +
            arma::conv_to<arma::uvec>::from(activeSet));

        CholeskyInsert(matGram(changeInd, changeInd), newGramCol);
      }

      // Add variable to active set.
      Activate(changeInd);
    }

    // Compute signs of correlations.
    arma::vec s = arma::vec(activeSet.size());
    for (size_t i = 0; i < activeSet.size(); i++)
      s(i) = corr(activeSet[i]) / fabs(corr(activeSet[i]));

    // Compute the "equiangular" direction in parameter space (betaDirection).
    // We use quotes because in the case of non-unit norm variables, this need
    // not be equiangular.
    arma::vec unnormalizedBetaDirection;
    double normalization;
    arma::vec betaDirection;
    if (useCholesky)
    {
      /**
       * Note that:
       * R^T R % S^T % S = (R % S)^T (R % S)
       * Now, for 1 the ones vector:
       * inv( (R % S)^T (R % S) ) 1
       *    = inv(R % S) inv((R % S)^T) 1
       *    = inv(R % S) Solve((R % S)^T, 1)
       *    = inv(R % S) Solve(R^T, s)
       *    = Solve(R % S, Solve(R^T, s)
       *    = s % Solve(R, Solve(R^T, s))
       */
      unnormalizedBetaDirection = solve(trimatu(matUtriCholFactor),
          solve(trimatl(trans(matUtriCholFactor)), s));

      normalization = 1.0 / sqrt(dot(s, unnormalizedBetaDirection));
      betaDirection = normalization * unnormalizedBetaDirection;
    }
    else
    {
      arma::mat matGramActive = arma::mat(activeSet.size(), activeSet.size());
      for (size_t i = 0; i < activeSet.size(); i++)
        for (size_t j = 0; j < activeSet.size(); j++)
          matGramActive(i, j) = matGram(activeSet[i], activeSet[j]);

      arma::mat matS = s * arma::ones<arma::mat>(1, activeSet.size());
      unnormalizedBetaDirection = solve(matGramActive % trans(matS) % matS,
          arma::ones<arma::mat>(activeSet.size(), 1));
      normalization = 1.0 / sqrt(sum(unnormalizedBetaDirection));
      betaDirection = normalization * unnormalizedBetaDirection % s;
    }

    // compute "equiangular" direction in output space
    ComputeYHatDirection(dataRef, betaDirection, yHatDirection);

    double gamma = maxCorr / normalization;

    // If not all variables are active.
    if (activeSet.size() < dataRef.n_cols)
    {
      // Compute correlations with direction.
      for (size_t ind = 0; ind < dataRef.n_cols; ind++)
      {
        if (isActive[ind])
          continue;

        double dirCorr = dot(dataRef.col(ind), yHatDirection);
        double val1 = (maxCorr - corr(ind)) / (normalization - dirCorr);
        double val2 = (maxCorr + corr(ind)) / (normalization + dirCorr);
        if ((val1 > 0) && (val1 < gamma))
          gamma = val1;
        if ((val2 > 0) && (val2 < gamma))
          gamma = val2;
      }
    }

    // Bound gamma according to LASSO.
    if (lasso)
    {
      lassocond = false;
      double lassoboundOnGamma = DBL_MAX;
      size_t activeIndToKickOut = -1;

      for (size_t i = 0; i < activeSet.size(); i++)
      {
        double val = -beta(activeSet[i]) / betaDirection(i);
        if ((val > 0) && (val < lassoboundOnGamma))
        {
          lassoboundOnGamma = val;
          activeIndToKickOut = i;
        }
      }

      if (lassoboundOnGamma < gamma)
      {
        gamma = lassoboundOnGamma;
        lassocond = true;
        changeInd = activeIndToKickOut;
      }
    }

    // Update the prediction.
    yHat += gamma * yHatDirection;

    // Update the estimator.
    for (size_t i = 0; i < activeSet.size(); i++)
    {
      beta(activeSet[i]) += gamma * betaDirection(i);
    }

    // Sanity check to make sure the kicked out dimension is actually zero.
    if (lassocond)
    {
      if (beta(activeSet[changeInd]) != 0)
        beta(activeSet[changeInd]) = 0;
    }

    betaPath.push_back(beta);

    if (lassocond)
    {
      // Index is in position changeInd in activeSet.
      if (useCholesky)
        CholeskyDelete(changeInd);

      Deactivate(changeInd);
    }

    corr = vecXTy - trans(dataRef) * yHat;
    if (elasticNet)
      corr -= lambda2 * beta;

    double curLambda = 0;
    for (size_t i = 0; i < activeSet.size(); i++)
      curLambda += fabs(corr(activeSet[i]));

    curLambda /= ((double) activeSet.size());

    lambdaPath.push_back(curLambda);

    // Time to stop for LASSO?
    if (lasso)
    {
      if (curLambda <= lambda1)
      {
        InterpolateBeta();
        break;
      }
    }
  }

  // Unfortunate copy...
  beta = betaPath.back();

  Timer::Stop("lars_regression");
}

// Private functions.
void LARS::Deactivate(const size_t activeVarInd)
{
  isActive[activeSet[activeVarInd]] = false;
  activeSet.erase(activeSet.begin() + activeVarInd);
}

void LARS::Activate(const size_t varInd)
{
  isActive[varInd] = true;
  activeSet.push_back(varInd);
}

void LARS::ComputeYHatDirection(const arma::mat& matX,
                                const arma::vec& betaDirection,
                                arma::vec& yHatDirection)
{
  yHatDirection.fill(0);
  for (size_t i = 0; i < activeSet.size(); i++)
    yHatDirection += betaDirection(i) * matX.col(activeSet[i]);
}

void LARS::InterpolateBeta()
{
  int pathLength = betaPath.size();

  // interpolate beta and stop
  double ultimateLambda = lambdaPath[pathLength - 1];
  double penultimateLambda = lambdaPath[pathLength - 2];
  double interp = (penultimateLambda - lambda1)
      / (penultimateLambda - ultimateLambda);

  betaPath[pathLength - 1] = (1 - interp) * (betaPath[pathLength - 2])
      + interp * betaPath[pathLength - 1];

  lambdaPath[pathLength - 1] = lambda1;
}

void LARS::CholeskyInsert(const arma::vec& newX, const arma::mat& X)
{
  if (matUtriCholFactor.n_rows == 0)
  {
    matUtriCholFactor = arma::mat(1, 1);

    if (elasticNet)
      matUtriCholFactor(0, 0) = sqrt(dot(newX, newX) + lambda2);
    else
      matUtriCholFactor(0, 0) = norm(newX, 2);
  }
  else
  {
    arma::vec newGramCol = trans(X) * newX;
    CholeskyInsert(dot(newX, newX), newGramCol);
  }
}

void LARS::CholeskyInsert(double sqNormNewX, const arma::vec& newGramCol)
{
  int n = matUtriCholFactor.n_rows;

  if (n == 0)
  {
    matUtriCholFactor = arma::mat(1, 1);

    if (elasticNet)
      matUtriCholFactor(0, 0) = sqrt(sqNormNewX + lambda2);
    else
      matUtriCholFactor(0, 0) = sqrt(sqNormNewX);
  }
  else
  {
    arma::mat matNewR = arma::mat(n + 1, n + 1);

    if (elasticNet)
      sqNormNewX += lambda2;

    arma::vec matUtriCholFactork = solve(trimatl(trans(matUtriCholFactor)),
        newGramCol);

    matNewR(arma::span(0, n - 1), arma::span(0, n - 1)) = matUtriCholFactor;
    matNewR(arma::span(0, n - 1), n) = matUtriCholFactork;
    matNewR(n, arma::span(0, n - 1)).fill(0.0);
    matNewR(n, n) = sqrt(sqNormNewX - dot(matUtriCholFactork,
                                          matUtriCholFactork));

    matUtriCholFactor = matNewR;
  }
}

void LARS::GivensRotate(const arma::vec::fixed<2>& x,
                        arma::vec::fixed<2>& rotatedX,
                        arma::mat& matG)
{
  if (x(1) == 0)
  {
    matG = arma::eye(2, 2);
    rotatedX = x;
  }
  else
  {
    double r = norm(x, 2);
    matG = arma::mat(2, 2);

    double scaledX1 = x(0) / r;
    double scaledX2 = x(1) / r;

    matG(0, 0) = scaledX1;
    matG(1, 0) = -scaledX2;
    matG(0, 1) = scaledX2;
    matG(1, 1) = scaledX1;

    rotatedX = arma::vec(2);
    rotatedX(0) = r;
    rotatedX(1) = 0;
  }
}

void LARS::CholeskyDelete(const size_t colToKill)
{
  size_t n = matUtriCholFactor.n_rows;

  if (colToKill == (n - 1))
  {
    matUtriCholFactor = matUtriCholFactor(arma::span(0, n - 2),
                                          arma::span(0, n - 2));
  }
  else
  {
    matUtriCholFactor.shed_col(colToKill); // remove column colToKill
    n--;

    for (size_t k = colToKill; k < n; k++)
    {
      arma::mat matG;
      arma::vec::fixed<2> rotatedVec;
      GivensRotate(matUtriCholFactor(arma::span(k, k + 1), k), rotatedVec,
          matG);
      matUtriCholFactor(arma::span(k, k + 1), k) = rotatedVec;
      if (k < n - 1)
      {
        matUtriCholFactor(arma::span(k, k + 1), arma::span(k + 1, n - 1)) =
            matG * matUtriCholFactor(arma::span(k, k + 1),
            arma::span(k + 1, n - 1));
      }
    }

    matUtriCholFactor.shed_row(n);
  }
}
<commit_msg>Stop timer for early exit.<commit_after>/**
 * @file lars.cpp
 * @author Nishant Mehta (niche)
 *
 * Implementation of LARS and LASSO.
 */
#include "lars.hpp"

using namespace mlpack;
using namespace mlpack::regression;

LARS::LARS(const bool useCholesky,
           const double lambda1,
           const double lambda2,
           const double tolerance) :
    matGram(matGramInternal),
    useCholesky(useCholesky),
    lasso((lambda1 != 0)),
    lambda1(lambda1),
    elasticNet((lambda1 != 0) && (lambda2 != 0)),
    lambda2(lambda2),
    tolerance(tolerance)
{ /* Nothing left to do. */ }

LARS::LARS(const bool useCholesky,
           const arma::mat& gramMatrix,
           const double lambda1,
           const double lambda2,
           const double tolerance) :
    matGram(gramMatrix),
    useCholesky(useCholesky),
    lasso((lambda1 != 0)),
    lambda1(lambda1),
    elasticNet((lambda1 != 0) && (lambda2 != 0)),
    lambda2(lambda2),
    tolerance(tolerance)
{ /* Nothing left to do */ }

void LARS::Regress(const arma::mat& matX,
                   const arma::vec& y,
                   arma::vec& beta,
                   const bool rowMajor)
{
  Timer::Start("lars_regression");

  // This matrix may end up holding the transpose -- if necessary.
  arma::mat dataTrans;
  // dataRef is row-major.
  const arma::mat& dataRef = (rowMajor ? matX : dataTrans);
  if (!rowMajor)
    dataTrans = trans(matX);

  // Compute X' * y.
  arma::vec vecXTy = trans(dataRef) * y;

  // Set up active set variables.  In the beginning, the active set has size 0
  // (all dimensions are inactive).
  isActive.resize(dataRef.n_cols, false);

  // Initialize yHat and beta.
  beta = arma::zeros(dataRef.n_cols);
  arma::vec yHat = arma::zeros(dataRef.n_rows);
  arma::vec yHatDirection = arma::vec(dataRef.n_rows);

  bool lassocond = false;

  // Compute the initial maximum correlation among all dimensions.
  arma::vec corr = vecXTy;
  double maxCorr = 0;
  size_t changeInd = 0;
  for (size_t i = 0; i < vecXTy.n_elem; ++i)
  {
    if (fabs(corr(i)) > maxCorr)
    {
      maxCorr = fabs(corr(i));
      changeInd = i;
    }
  }

  betaPath.push_back(beta);
  lambdaPath.push_back(maxCorr);

  // If the maximum correlation is too small, there is no reason to continue.
  if (maxCorr < lambda1)
  {
    lambdaPath[0] = lambda1;
    Timer::Stop("lars_regression");
    return;
  }

  // Compute the Gram matrix.  If this is the elastic net problem, we will add
  // lambda2 * I_n to the matrix.
  if (matGram.n_elem == 0)
  {
    // In this case, matGram should reference matGramInternal.
    matGramInternal = trans(dataRef) * dataRef;

    if (elasticNet && !useCholesky)
      matGramInternal += lambda2 * arma::eye(dataRef.n_cols, dataRef.n_cols);
  }

  // Main loop.
  while ((activeSet.size() < dataRef.n_cols) && (maxCorr > tolerance))
  {
    // Compute the maximum correlation among inactive dimensions.
    maxCorr = 0;
    for (size_t i = 0; i < dataRef.n_cols; i++)
    {
      if ((!isActive[i]) && (fabs(corr(i)) > maxCorr))
      {
        maxCorr = fabs(corr(i));
        changeInd = i;
      }
    }

    if (!lassocond)
    {
      if (useCholesky)
      {
        // vec newGramCol = vec(activeSet.size());
        // for (size_t i = 0; i < activeSet.size(); i++)
        // {
        //   newGramCol[i] = dot(matX.col(activeSet[i]), matX.col(changeInd));
        // }
        // This is equivalent to the above 5 lines.
        arma::vec newGramCol = matGram.elem(changeInd * dataRef.n_cols +
            arma::conv_to<arma::uvec>::from(activeSet));

        CholeskyInsert(matGram(changeInd, changeInd), newGramCol);
      }

      // Add variable to active set.
      Activate(changeInd);
    }

    // Compute signs of correlations.
    arma::vec s = arma::vec(activeSet.size());
    for (size_t i = 0; i < activeSet.size(); i++)
      s(i) = corr(activeSet[i]) / fabs(corr(activeSet[i]));

    // Compute the "equiangular" direction in parameter space (betaDirection).
    // We use quotes because in the case of non-unit norm variables, this need
    // not be equiangular.
    arma::vec unnormalizedBetaDirection;
    double normalization;
    arma::vec betaDirection;
    if (useCholesky)
    {
      /**
       * Note that:
       * R^T R % S^T % S = (R % S)^T (R % S)
       * Now, for 1 the ones vector:
       * inv( (R % S)^T (R % S) ) 1
       *    = inv(R % S) inv((R % S)^T) 1
       *    = inv(R % S) Solve((R % S)^T, 1)
       *    = inv(R % S) Solve(R^T, s)
       *    = Solve(R % S, Solve(R^T, s)
       *    = s % Solve(R, Solve(R^T, s))
       */
      unnormalizedBetaDirection = solve(trimatu(matUtriCholFactor),
          solve(trimatl(trans(matUtriCholFactor)), s));

      normalization = 1.0 / sqrt(dot(s, unnormalizedBetaDirection));
      betaDirection = normalization * unnormalizedBetaDirection;
    }
    else
    {
      arma::mat matGramActive = arma::mat(activeSet.size(), activeSet.size());
      for (size_t i = 0; i < activeSet.size(); i++)
        for (size_t j = 0; j < activeSet.size(); j++)
          matGramActive(i, j) = matGram(activeSet[i], activeSet[j]);

      arma::mat matS = s * arma::ones<arma::mat>(1, activeSet.size());
      unnormalizedBetaDirection = solve(matGramActive % trans(matS) % matS,
          arma::ones<arma::mat>(activeSet.size(), 1));
      normalization = 1.0 / sqrt(sum(unnormalizedBetaDirection));
      betaDirection = normalization * unnormalizedBetaDirection % s;
    }

    // compute "equiangular" direction in output space
    ComputeYHatDirection(dataRef, betaDirection, yHatDirection);

    double gamma = maxCorr / normalization;

    // If not all variables are active.
    if (activeSet.size() < dataRef.n_cols)
    {
      // Compute correlations with direction.
      for (size_t ind = 0; ind < dataRef.n_cols; ind++)
      {
        if (isActive[ind])
          continue;

        double dirCorr = dot(dataRef.col(ind), yHatDirection);
        double val1 = (maxCorr - corr(ind)) / (normalization - dirCorr);
        double val2 = (maxCorr + corr(ind)) / (normalization + dirCorr);
        if ((val1 > 0) && (val1 < gamma))
          gamma = val1;
        if ((val2 > 0) && (val2 < gamma))
          gamma = val2;
      }
    }

    // Bound gamma according to LASSO.
    if (lasso)
    {
      lassocond = false;
      double lassoboundOnGamma = DBL_MAX;
      size_t activeIndToKickOut = -1;

      for (size_t i = 0; i < activeSet.size(); i++)
      {
        double val = -beta(activeSet[i]) / betaDirection(i);
        if ((val > 0) && (val < lassoboundOnGamma))
        {
          lassoboundOnGamma = val;
          activeIndToKickOut = i;
        }
      }

      if (lassoboundOnGamma < gamma)
      {
        gamma = lassoboundOnGamma;
        lassocond = true;
        changeInd = activeIndToKickOut;
      }
    }

    // Update the prediction.
    yHat += gamma * yHatDirection;

    // Update the estimator.
    for (size_t i = 0; i < activeSet.size(); i++)
    {
      beta(activeSet[i]) += gamma * betaDirection(i);
    }

    // Sanity check to make sure the kicked out dimension is actually zero.
    if (lassocond)
    {
      if (beta(activeSet[changeInd]) != 0)
        beta(activeSet[changeInd]) = 0;
    }

    betaPath.push_back(beta);

    if (lassocond)
    {
      // Index is in position changeInd in activeSet.
      if (useCholesky)
        CholeskyDelete(changeInd);

      Deactivate(changeInd);
    }

    corr = vecXTy - trans(dataRef) * yHat;
    if (elasticNet)
      corr -= lambda2 * beta;

    double curLambda = 0;
    for (size_t i = 0; i < activeSet.size(); i++)
      curLambda += fabs(corr(activeSet[i]));

    curLambda /= ((double) activeSet.size());

    lambdaPath.push_back(curLambda);

    // Time to stop for LASSO?
    if (lasso)
    {
      if (curLambda <= lambda1)
      {
        InterpolateBeta();
        break;
      }
    }
  }

  // Unfortunate copy...
  beta = betaPath.back();

  Timer::Stop("lars_regression");
}

// Private functions.
void LARS::Deactivate(const size_t activeVarInd)
{
  isActive[activeSet[activeVarInd]] = false;
  activeSet.erase(activeSet.begin() + activeVarInd);
}

void LARS::Activate(const size_t varInd)
{
  isActive[varInd] = true;
  activeSet.push_back(varInd);
}

void LARS::ComputeYHatDirection(const arma::mat& matX,
                                const arma::vec& betaDirection,
                                arma::vec& yHatDirection)
{
  yHatDirection.fill(0);
  for (size_t i = 0; i < activeSet.size(); i++)
    yHatDirection += betaDirection(i) * matX.col(activeSet[i]);
}

void LARS::InterpolateBeta()
{
  int pathLength = betaPath.size();

  // interpolate beta and stop
  double ultimateLambda = lambdaPath[pathLength - 1];
  double penultimateLambda = lambdaPath[pathLength - 2];
  double interp = (penultimateLambda - lambda1)
      / (penultimateLambda - ultimateLambda);

  betaPath[pathLength - 1] = (1 - interp) * (betaPath[pathLength - 2])
      + interp * betaPath[pathLength - 1];

  lambdaPath[pathLength - 1] = lambda1;
}

void LARS::CholeskyInsert(const arma::vec& newX, const arma::mat& X)
{
  if (matUtriCholFactor.n_rows == 0)
  {
    matUtriCholFactor = arma::mat(1, 1);

    if (elasticNet)
      matUtriCholFactor(0, 0) = sqrt(dot(newX, newX) + lambda2);
    else
      matUtriCholFactor(0, 0) = norm(newX, 2);
  }
  else
  {
    arma::vec newGramCol = trans(X) * newX;
    CholeskyInsert(dot(newX, newX), newGramCol);
  }
}

void LARS::CholeskyInsert(double sqNormNewX, const arma::vec& newGramCol)
{
  int n = matUtriCholFactor.n_rows;

  if (n == 0)
  {
    matUtriCholFactor = arma::mat(1, 1);

    if (elasticNet)
      matUtriCholFactor(0, 0) = sqrt(sqNormNewX + lambda2);
    else
      matUtriCholFactor(0, 0) = sqrt(sqNormNewX);
  }
  else
  {
    arma::mat matNewR = arma::mat(n + 1, n + 1);

    if (elasticNet)
      sqNormNewX += lambda2;

    arma::vec matUtriCholFactork = solve(trimatl(trans(matUtriCholFactor)),
        newGramCol);

    matNewR(arma::span(0, n - 1), arma::span(0, n - 1)) = matUtriCholFactor;
    matNewR(arma::span(0, n - 1), n) = matUtriCholFactork;
    matNewR(n, arma::span(0, n - 1)).fill(0.0);
    matNewR(n, n) = sqrt(sqNormNewX - dot(matUtriCholFactork,
                                          matUtriCholFactork));

    matUtriCholFactor = matNewR;
  }
}

void LARS::GivensRotate(const arma::vec::fixed<2>& x,
                        arma::vec::fixed<2>& rotatedX,
                        arma::mat& matG)
{
  if (x(1) == 0)
  {
    matG = arma::eye(2, 2);
    rotatedX = x;
  }
  else
  {
    double r = norm(x, 2);
    matG = arma::mat(2, 2);

    double scaledX1 = x(0) / r;
    double scaledX2 = x(1) / r;

    matG(0, 0) = scaledX1;
    matG(1, 0) = -scaledX2;
    matG(0, 1) = scaledX2;
    matG(1, 1) = scaledX1;

    rotatedX = arma::vec(2);
    rotatedX(0) = r;
    rotatedX(1) = 0;
  }
}

void LARS::CholeskyDelete(const size_t colToKill)
{
  size_t n = matUtriCholFactor.n_rows;

  if (colToKill == (n - 1))
  {
    matUtriCholFactor = matUtriCholFactor(arma::span(0, n - 2),
                                          arma::span(0, n - 2));
  }
  else
  {
    matUtriCholFactor.shed_col(colToKill); // remove column colToKill
    n--;

    for (size_t k = colToKill; k < n; k++)
    {
      arma::mat matG;
      arma::vec::fixed<2> rotatedVec;
      GivensRotate(matUtriCholFactor(arma::span(k, k + 1), k), rotatedVec,
          matG);
      matUtriCholFactor(arma::span(k, k + 1), k) = rotatedVec;
      if (k < n - 1)
      {
        matUtriCholFactor(arma::span(k, k + 1), arma::span(k + 1, n - 1)) =
            matG * matUtriCholFactor(arma::span(k, k + 1),
            arma::span(k + 1, n - 1));
      }
    }

    matUtriCholFactor.shed_row(n);
  }
}
<|endoftext|>