<commit_before>//
//  JdThread.hpp
//  Jigidesign
//
//  Created b1y Steven Massey on 11/10/12.
//  Copyright (c) 2012 Jigidesign. All rights reserved.
//

#ifndef __Jigidesign__JdThread__
#define __Jigidesign__JdThread__

#include "Epilog.hpp"
#include "Epigram.hpp"
#include "JdSemaphore.hpp"
#include "JdEnum.hpp"
#include <thread>
#include <pthread.h>

//#define d_epilogLibBuild 0

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

 How to use:

 1. Derive from IJdThread
 2A. Implement Run ().  Use IsAlive () to test whether the thread loop should continue executing.  Or:
 2B. Implement Break () if necessary to signal your Run () loop that it should return.
 3. Optionally, implement Terminated () for any post-Run () cleanup

 IsAlive () is the default "signaling" method, but does no good if the thread run loop blocks on a semaphore.  So, alternatively,
 	a. use a timed semaphore
 	b. send the proper escape signal/message to Run() in the Break() override.

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

d_jdEnum_ (ThreadState, pending, initializing, running, quiting, quit, zombie);

/*
 	TODO: maybe refactor like the Fiber classes

 	Create IJdThread.

 	Then, to implement a thread:
		1) implement PortHandler protocol, with macro helpers
 		2) implement IJdThread while also inheriting from PortHandler.  Fill in port PortHandler methods.

 	And, instatiate like so:
 	JdThread <MyThread, PortHandlers> thread (128, "name");
 	thread.Start();

	 JdThread <MyThread, PortHandlers>::producer_t producer = thread.CreateProducer ();
	producer.SetSomething (8838);

 	thread.Stop();

 */

//FIX: make m_state atomic with CAS : not necessary..?

const u8 c_jdThread_defaultPriority = 0;

struct IJdThread
{
    struct Info
    {
        virtual bool                IsAlive         () = 0;
		virtual cstr_t				GetName			() const = 0;
    };

    virtual ~                       IJdThread       () { };
    virtual JdResult                Setup           () 												{ return c_jdNoErr; }		// Setup happens in creator thread (which is probably main)
    virtual JdResult                Run             (EpigramRef i_args, IJdThread::Info & i_info)	= 0;
    virtual JdResult                Break           () 												{ return c_jdNoErr; }
	virtual JdResult                Finalize        (const JdResult &i_runResult) 					{ return i_runResult; }		// Finalize happens in-thread
    virtual JdResult                Teardown        (const JdResult &i_runResult)					{ return i_runResult; }		// Teardown happens in creator thread (which is probably main)
};

template <typename t_thread>
class JdThreadT
{
    static void Runner (JdThreadT * i_owner, IJdThread * i_implementation, u8 i_priority)
    {
		pthread_setname_np (i_owner->m_threadName.c_str ());

		// set thread priority
		if (i_priority != c_jdThread_defaultPriority)
		{
			i32 policy;
//			policy = SCHED_OTHER;
//			policy = SCHED_RR;
			policy = SCHED_FIFO;

			// TODO: read this. https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/scheduler/scheduler.html#//apple_ref/doc/uid/TP30000905-CH211-TPXREF109

			// these don't seem to be correct. returns max of 47. can set to 127 without failure
//			i_priority = min ((u8) sched_get_priority_max (policy), i_priority);
//			i_priority = max ((u8) sched_get_priority_min (policy), i_priority);

			sched_param sp = {};
			sp.sched_priority = i_priority;

			if (pthread_setschedparam (pthread_self (), policy, &sp))
			{
				#ifndef d_epilogLibBuild
					epilog_func (detail, "set priority of @ failed for '@'", (u32) sp.sched_priority, i_owner->m_threadName);
				#endif
			}
			else
			{
				#ifndef d_epilogLibBuild
					epilog_func (detail, "'@' set to priority: @", i_owner->m_threadName, (u32) i_priority);
				#endif
			}
		}

		if (false)
		{
//			cout << "min: " << sched_get_priority_min (SCHED_OTHER) << " max: " << sched_get_priority_max (SCHED_OTHER) << endl;

			struct sched_param sp;
			int policy;
			pthread_getschedparam (pthread_self (), &policy, & sp);

			cout << "policy: " << policy << " priority: " << sp.sched_priority << endl;
		}

//		i_owner->m_state = c_jdThreadState::running;

		struct ThreadInfo : IJdThread::Info
		{
			ThreadInfo (EJdThreadState &i_state, cstr_t i_name)
			: m_state (i_state), m_name (i_name)												{ }

			virtual bool				IsAlive ()
			{
				// TODO: could sleep here for paused threads

				return m_state == c_jdThreadState::running;
			}

			virtual cstr_t				GetName () const
			{
				return m_name;
			}

			EJdThreadState &			m_state;
			cstr_t						m_name;
		}
		info (i_owner->m_state, i_owner->m_threadName.c_str ());

		JdResult runResult;

		i_owner->m_threadReady.Signal();

		runResult = i_implementation->Run (i_owner->m_args, info);
		runResult = i_implementation->Finalize (runResult);
		i_owner->Exited (runResult);
    }

    public:

    JdThreadT                   (cstr_t i_threadName = "unnamed", u8 i_priority = c_jdThread_defaultPriority /* 0-63 */)
    :
	m_priority					(i_priority),
	m_threadName				(i_threadName)
	{
        m_implementation = new t_thread;
	}

    void                    SetPriority     (u8 i_priority)
    {
		if (i_priority > 0 && i_priority < 100)
			m_priority = i_priority;
    }

	virtual 				~JdThreadT ()
	{
		Stop ();
		d_jdAssert (m_state == c_jdThreadState::pending || m_state == c_jdThreadState::quit, "thread wasn't quit");

        delete m_implementation;
	}

	JdResult				Reset		()
	{
		JdResult result;

		if (m_state != c_jdThreadState::pending)
		{
			result = Stop ();

			if (not result)
			{
				if (m_state == c_jdThreadState::quit)
				{
					delete m_implementation;

					m_implementation = new t_thread;
					m_state = c_jdThreadState::pending;
					m_exited = false;
					m_runResult = c_jdNoErr;
				}
				else result = d_jdError ("can't reset a thread not quit");
			}
		}

		return result;
	}

	JdResult				Start		(EpigramRef i_args = Epigram ())
	{
        d_jdAssert (m_implementation, "thread impl is null");

		m_args = i_args;

        JdResult result = m_implementation->Setup ();
        if (result) return result;

		if (m_state == c_jdThreadState::pending)
		{
//			m_state = c_jdThreadState::initializing;

			#ifndef d_epilogLibBuild
				epilog (detail, "start: '@'", m_threadName);
			#endif

			m_state = c_jdThreadState::running;

			m_stdThread = std::thread (Runner, this, m_implementation, m_priority);
			m_threadReady.Wait ();	// NOTE: don't remember why i needed this, exactly. i guess it doesn't hurt
		}
		else
		{
			d_jdThrow ("Attempting to start thread '@' which is already in state: @", m_threadName, Jd::ToString (m_state));
		}

		return c_jdNoErr;
	}

    t_thread *				operator -> ()
    {
        return static_cast <t_thread *> (m_implementation);
    }

	t_thread *				Get ()
    {
        return static_cast <t_thread *> (m_implementation);
    }

	bool					IsRunning ()
	{
		return (m_state == c_jdThreadState::running and not m_exited);
	}

	bool					DidExit ()
	{
		if (m_exited)
		{

		}

		return m_exited;
	}

	JdResult				Stop ()
	{
		JdResult result;

        if (m_state != c_jdThreadState::running)
			return d_jdError1 ("Thread not running.");

        m_state = c_jdThreadState::quiting;

        u32 breakAttempts = 0;
        while (not DidExit () and breakAttempts++ < 30)
        {
			auto p = static_cast <IJdThread *> (m_implementation);
            result = p->Break ();
            if (result)
				break;

			std::this_thread::sleep_for (std::chrono::microseconds (10000));
        }

        if (not result)
		{
			m_stdThread.join ();   // FIX: could use do_try_join_until () then report zombie if fail
			m_state = c_jdThreadState::quit;

			result = m_implementation->Teardown (m_runResult);
		}
		else m_state = c_jdThreadState::zombie;

		return result;
	}

    private: // internals ---------------------------------------------------------------------------------------
	void					Exited (const JdResult &i_runResult)
	{
		m_runResult = i_runResult;
		m_exited = true;

		#ifndef d_epilogLibBuild
			epilog (detail, "'@' exited", m_threadName);
		#endif
	}

    t_thread *          m_implementation		= nullptr;
	std::thread			m_stdThread;
	u32					m_priority;

	EJdThreadState		m_state					= c_jdThreadState::pending;
	JdResult			m_runResult;
	bool				m_exited				= false;

	string				m_threadName;
	JdSemaphore			m_threadReady;
	Epigram				m_args;
};

template <typename t_thread>
class JdThreadPool
{
	public:

	virtual						~ JdThreadPool				()
	{
		for (auto thread : m_threads)
		{
			thread->Stop ();
			delete thread;
		}
	}

	JdThreadT <t_thread> *		CreateThread				(stringRef_t i_name = "")
	{
		GroomDeadThreads ();

		auto thread = new JdThreadT <t_thread> (i_name.c_str ());

		m_threads.insert (thread);

		return thread;
	}

	JdResult					StopAllThreads				()
	{
		JdResult result;

		for (auto thread : m_threads)
		{
			result |= thread->Stop ();
		}

		return result;
	}

	protected:

	JdResult					GroomDeadThreads			()
	{
		for (auto i = m_threads.begin(), e = m_threads.end (); i != e;)
		{
			auto thread = *i;

			if (thread->DidExit ())
			{
				#ifndef d_epilogLibBuild
					epilog (normal, "purging dead thread");
				#endif
				thread->Stop ();
				delete thread;
				i = m_threads.erase (i);
			}
			else ++i;
		}

		return c_jdNoErr;
	}

	set <JdThreadT <t_thread> *>		m_threads;
};

class JdSingleThreadEnforcer
{
	public:

	void						Enforce						()
	{
		if (m_id == std::thread::id	())
		{
			m_id = std::this_thread::get_id ();
		}
		else
		{
			if (m_id != std::this_thread::get_id())
			{
				d_jdThrow ("can't call this code from multiple threads. thank you, come again.");
			}
		}
	}

	bool						IsEnforcedThread			()
	{
		d_jdAssert (m_id != std::thread::id	(), "Enforce () should be called at least once prior to IsEnforcedThread ()");

		return  (m_id == std::this_thread::get_id());
	}

	protected:
	std::thread::id				m_id;
};

namespace Jd
{
	void			EnforceMainThread		();
}

#endif /* defined(__Jigidesign__JdThread__) */
<commit_msg>pthread_setname_np platform diff<commit_after>//
//  JdThread.hpp
//  Jigidesign
//
//  Created b1y Steven Massey on 11/10/12.
//  Copyright (c) 2012 Jigidesign. All rights reserved.
//

#ifndef __Jigidesign__JdThread__
#define __Jigidesign__JdThread__

#include "Epilog.hpp"
#include "Epigram.hpp"
#include "JdSemaphore.hpp"
#include "JdEnum.hpp"
#include <thread>
#include <pthread.h>

//#define d_epilogLibBuild 0

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

 How to use:

 1. Derive from IJdThread
 2A. Implement Run ().  Use IsAlive () to test whether the thread loop should continue executing.  Or:
 2B. Implement Break () if necessary to signal your Run () loop that it should return.
 3. Optionally, implement Terminated () for any post-Run () cleanup

 IsAlive () is the default "signaling" method, but does no good if the thread run loop blocks on a semaphore.  So, alternatively,
 	a. use a timed semaphore
 	b. send the proper escape signal/message to Run() in the Break() override.

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

d_jdEnum_ (ThreadState, pending, initializing, running, quiting, quit, zombie);

/*
 	TODO: maybe refactor like the Fiber classes

 	Create IJdThread.

 	Then, to implement a thread:
		1) implement PortHandler protocol, with macro helpers
 		2) implement IJdThread while also inheriting from PortHandler.  Fill in port PortHandler methods.

 	And, instatiate like so:
 	JdThread <MyThread, PortHandlers> thread (128, "name");
 	thread.Start();

	 JdThread <MyThread, PortHandlers>::producer_t producer = thread.CreateProducer ();
	producer.SetSomething (8838);

 	thread.Stop();

 */

//FIX: make m_state atomic with CAS : not necessary..?

const u8 c_jdThread_defaultPriority = 0;

struct IJdThread
{
    struct Info
    {
        virtual bool                IsAlive         () = 0;
		virtual cstr_t				GetName			() const = 0;
    };

    virtual ~                       IJdThread       () { };
    virtual JdResult                Setup           () 												{ return c_jdNoErr; }		// Setup happens in creator thread (which is probably main)
    virtual JdResult                Run             (EpigramRef i_args, IJdThread::Info & i_info)	= 0;
    virtual JdResult                Break           () 												{ return c_jdNoErr; }
	virtual JdResult                Finalize        (const JdResult &i_runResult) 					{ return i_runResult; }		// Finalize happens in-thread
    virtual JdResult                Teardown        (const JdResult &i_runResult)					{ return i_runResult; }		// Teardown happens in creator thread (which is probably main)
};

template <typename t_thread>
class JdThreadT
{
    static void Runner (JdThreadT * i_owner, IJdThread * i_implementation, u8 i_priority)
    {
#		if __APPLE__
			pthread_setname_np (i_owner->m_threadName.c_str ());
#		else
			pthread_setname_np (pthread_self (), i_owner->m_threadName.c_str ());
#		endif

		// set thread priority
		if (i_priority != c_jdThread_defaultPriority)
		{
			i32 policy;
//			policy = SCHED_OTHER;
//			policy = SCHED_RR;
			policy = SCHED_FIFO;

			// TODO: read this. https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/scheduler/scheduler.html#//apple_ref/doc/uid/TP30000905-CH211-TPXREF109

			// these don't seem to be correct. returns max of 47. can set to 127 without failure
//			i_priority = min ((u8) sched_get_priority_max (policy), i_priority);
//			i_priority = max ((u8) sched_get_priority_min (policy), i_priority);

			sched_param sp = {};
			sp.sched_priority = i_priority;

			if (pthread_setschedparam (pthread_self (), policy, &sp))
			{
				#ifndef d_epilogLibBuild
					epilog_func (detail, "set priority of @ failed for '@'", (u32) sp.sched_priority, i_owner->m_threadName);
				#endif
			}
			else
			{
				#ifndef d_epilogLibBuild
					epilog_func (detail, "'@' set to priority: @", i_owner->m_threadName, (u32) i_priority);
				#endif
			}
		}

		if (false)
		{
//			cout << "min: " << sched_get_priority_min (SCHED_OTHER) << " max: " << sched_get_priority_max (SCHED_OTHER) << endl;

			struct sched_param sp;
			int policy;
			pthread_getschedparam (pthread_self (), &policy, & sp);

			cout << "policy: " << policy << " priority: " << sp.sched_priority << endl;
		}

//		i_owner->m_state = c_jdThreadState::running;

		struct ThreadInfo : IJdThread::Info
		{
			ThreadInfo (EJdThreadState &i_state, cstr_t i_name)
			: m_state (i_state), m_name (i_name)												{ }

			virtual bool				IsAlive ()
			{
				// TODO: could sleep here for paused threads

				return m_state == c_jdThreadState::running;
			}

			virtual cstr_t				GetName () const
			{
				return m_name;
			}

			EJdThreadState &			m_state;
			cstr_t						m_name;
		}
		info (i_owner->m_state, i_owner->m_threadName.c_str ());

		JdResult runResult;

		i_owner->m_threadReady.Signal();

		runResult = i_implementation->Run (i_owner->m_args, info);
		runResult = i_implementation->Finalize (runResult);
		i_owner->Exited (runResult);
    }

    public:

    JdThreadT                   (cstr_t i_threadName = "unnamed", u8 i_priority = c_jdThread_defaultPriority /* 0-63 */)
    :
	m_priority					(i_priority),
	m_threadName				(i_threadName)
	{
        m_implementation = new t_thread;
	}

    void                    SetPriority     (u8 i_priority)
    {
		if (i_priority > 0 && i_priority < 100)
			m_priority = i_priority;
    }

	virtual 				~JdThreadT ()
	{
		Stop ();
		d_jdAssert (m_state == c_jdThreadState::pending || m_state == c_jdThreadState::quit, "thread wasn't quit");

        delete m_implementation;
	}

	JdResult				Reset		()
	{
		JdResult result;

		if (m_state != c_jdThreadState::pending)
		{
			result = Stop ();

			if (not result)
			{
				if (m_state == c_jdThreadState::quit)
				{
					delete m_implementation;

					m_implementation = new t_thread;
					m_state = c_jdThreadState::pending;
					m_exited = false;
					m_runResult = c_jdNoErr;
				}
				else result = d_jdError ("can't reset a thread not quit");
			}
		}

		return result;
	}

	JdResult				Start		(EpigramRef i_args = Epigram ())
	{
        d_jdAssert (m_implementation, "thread impl is null");

		m_args = i_args;

        JdResult result = m_implementation->Setup ();
        if (result) return result;

		if (m_state == c_jdThreadState::pending)
		{
//			m_state = c_jdThreadState::initializing;

			#ifndef d_epilogLibBuild
				epilog (detail, "start: '@'", m_threadName);
			#endif

			m_state = c_jdThreadState::running;

			m_stdThread = std::thread (Runner, this, m_implementation, m_priority);
			m_threadReady.Wait ();	// NOTE: don't remember why i needed this, exactly. i guess it doesn't hurt
		}
		else
		{
			d_jdThrow ("Attempting to start thread '@' which is already in state: @", m_threadName, Jd::ToString (m_state));
		}

		return c_jdNoErr;
	}

    t_thread *				operator -> ()
    {
        return static_cast <t_thread *> (m_implementation);
    }

	t_thread *				Get ()
    {
        return static_cast <t_thread *> (m_implementation);
    }

	bool					IsRunning ()
	{
		return (m_state == c_jdThreadState::running and not m_exited);
	}

	bool					DidExit ()
	{
		if (m_exited)
		{

		}

		return m_exited;
	}

	JdResult				Stop ()
	{
		JdResult result;

        if (m_state != c_jdThreadState::running)
			return d_jdError1 ("Thread not running.");

        m_state = c_jdThreadState::quiting;

        u32 breakAttempts = 0;
        while (not DidExit () and breakAttempts++ < 30)
        {
			auto p = static_cast <IJdThread *> (m_implementation);
            result = p->Break ();
            if (result)
				break;

			std::this_thread::sleep_for (std::chrono::microseconds (10000));
        }

        if (not result)
		{
			m_stdThread.join ();   // FIX: could use do_try_join_until () then report zombie if fail
			m_state = c_jdThreadState::quit;

			result = m_implementation->Teardown (m_runResult);
		}
		else m_state = c_jdThreadState::zombie;

		return result;
	}

    private: // internals ---------------------------------------------------------------------------------------
	void					Exited (const JdResult &i_runResult)
	{
		m_runResult = i_runResult;
		m_exited = true;

		#ifndef d_epilogLibBuild
			epilog (detail, "'@' exited", m_threadName);
		#endif
	}

    t_thread *          m_implementation		= nullptr;
	std::thread			m_stdThread;
	u32					m_priority;

	EJdThreadState		m_state					= c_jdThreadState::pending;
	JdResult			m_runResult;
	bool				m_exited				= false;

	string				m_threadName;
	JdSemaphore			m_threadReady;
	Epigram				m_args;
};

template <typename t_thread>
class JdThreadPool
{
	public:

	virtual						~ JdThreadPool				()
	{
		for (auto thread : m_threads)
		{
			thread->Stop ();
			delete thread;
		}
	}

	JdThreadT <t_thread> *		CreateThread				(stringRef_t i_name = "")
	{
		GroomDeadThreads ();

		auto thread = new JdThreadT <t_thread> (i_name.c_str ());

		m_threads.insert (thread);

		return thread;
	}

	JdResult					StopAllThreads				()
	{
		JdResult result;

		for (auto thread : m_threads)
		{
			result |= thread->Stop ();
		}

		return result;
	}

	protected:

	JdResult					GroomDeadThreads			()
	{
		for (auto i = m_threads.begin(), e = m_threads.end (); i != e;)
		{
			auto thread = *i;

			if (thread->DidExit ())
			{
				#ifndef d_epilogLibBuild
					epilog (normal, "purging dead thread");
				#endif
				thread->Stop ();
				delete thread;
				i = m_threads.erase (i);
			}
			else ++i;
		}

		return c_jdNoErr;
	}

	set <JdThreadT <t_thread> *>		m_threads;
};

class JdSingleThreadEnforcer
{
	public:

	void						Enforce						()
	{
		if (m_id == std::thread::id	())
		{
			m_id = std::this_thread::get_id ();
		}
		else
		{
			if (m_id != std::this_thread::get_id())
			{
				d_jdThrow ("can't call this code from multiple threads. thank you, come again.");
			}
		}
	}

	bool						IsEnforcedThread			()
	{
		d_jdAssert (m_id != std::thread::id	(), "Enforce () should be called at least once prior to IsEnforcedThread ()");

		return  (m_id == std::this_thread::get_id());
	}

	protected:
	std::thread::id				m_id;
};

namespace Jd
{
	void			EnforceMainThread		();
}

#endif /* defined(__Jigidesign__JdThread__) */
<|endoftext|>


<commit_before>/*
   This file is part of the clazy static checker.

  Copyright (C) 2015 Sergio Martins <smartins@kde.org>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public License
  along with this library; see the file COPYING.LIB.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#include <llvm/Config/llvm-config.h>

#if !defined(IS_OLD_CLANG)

#include "missing-qobject-macro.h"

#include "Utils.h"
#include "QtUtils.h"
#include "checkmanager.h"
#include "StringUtils.h"

#include <clang/AST/AST.h>
#include <clang/Lex/Lexer.h>
#include <clang/Lex/MacroArgs.h>

using namespace clang;
using namespace std;

MissingQ_OBJECT::MissingQ_OBJECT(const std::string &name, const clang::CompilerInstance &ci)
    : CheckBase(name, ci)
{
    enablePreProcessorCallbacks();
}

void MissingQ_OBJECT::VisitMacroExpands(const clang::Token &MacroNameTok, const clang::SourceRange &range)
{
    IdentifierInfo *ii = MacroNameTok.getIdentifierInfo();
    if (ii && ii->getName() == "Q_OBJECT")
        registerQ_OBJECT(range.getBegin());
}

void MissingQ_OBJECT::VisitDecl(clang::Decl *decl)
{
    CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(decl);
    if (!record || !record->hasDefinition() || record->getDefinition() != record || !QtUtils::isQObject(record))
        return;

    if (record->getDescribedClassTemplate() != nullptr) // moc doesn't accept Q_OBJECT in templates
        return;

    const SourceLocation startLoc = decl->getLocStart();

    for (const SourceLocation &loc : m_qobjectMacroLocations) {
        if (sm().getFileID(loc) != sm().getFileID(startLoc))
            continue; // Different file

        if (sm().isBeforeInSLocAddrSpace(startLoc, loc) && sm().isBeforeInSLocAddrSpace(loc, decl->getLocEnd()))
            return; // We found a Q_OBJECT after start and before end, it's ours.
    }

    emitWarning(startLoc, record->getQualifiedNameAsString() + " is missing a Q_OBJECT macro");
}

void MissingQ_OBJECT::registerQ_OBJECT(SourceLocation loc)
{
    m_qobjectMacroLocations.push_back(loc);
}

REGISTER_CHECK_WITH_FLAGS("missing-qobject-macro", MissingQ_OBJECT, CheckLevel1)

#endif // clang >= 3.7
<commit_msg>missing-qobject-macro: Don't warn while building Qt bootstrap<commit_after>/*
   This file is part of the clazy static checker.

  Copyright (C) 2015 Sergio Martins <smartins@kde.org>

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public License
  along with this library; see the file COPYING.LIB.  If not, write to
  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#include <llvm/Config/llvm-config.h>

#if !defined(IS_OLD_CLANG)

#include "missing-qobject-macro.h"

#include "Utils.h"
#include "QtUtils.h"
#include "checkmanager.h"
#include "StringUtils.h"

#include <clang/AST/AST.h>
#include <clang/Lex/Lexer.h>
#include <clang/Lex/MacroArgs.h>

using namespace clang;
using namespace std;

MissingQ_OBJECT::MissingQ_OBJECT(const std::string &name, const clang::CompilerInstance &ci)
    : CheckBase(name, ci)
{
    enablePreProcessorCallbacks();
}

void MissingQ_OBJECT::VisitMacroExpands(const clang::Token &MacroNameTok, const clang::SourceRange &range)
{
    IdentifierInfo *ii = MacroNameTok.getIdentifierInfo();
    if (ii && ii->getName() == "Q_OBJECT")
        registerQ_OBJECT(range.getBegin());
}

void MissingQ_OBJECT::VisitDecl(clang::Decl *decl)
{
    CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(decl);
    if (!record || !record->hasDefinition() || record->getDefinition() != record || !QtUtils::isQObject(record))
        return;

    if (record->getDescribedClassTemplate() != nullptr) // moc doesn't accept Q_OBJECT in templates
        return;

    if (QtUtils::isBootstrapping(m_ci)) // avoid warnings when building bootstrap lib
        return;

    const SourceLocation startLoc = decl->getLocStart();

    for (const SourceLocation &loc : m_qobjectMacroLocations) {
        if (sm().getFileID(loc) != sm().getFileID(startLoc))
            continue; // Different file

        if (sm().isBeforeInSLocAddrSpace(startLoc, loc) && sm().isBeforeInSLocAddrSpace(loc, decl->getLocEnd()))
            return; // We found a Q_OBJECT after start and before end, it's ours.
    }

    emitWarning(startLoc, record->getQualifiedNameAsString() + " is missing a Q_OBJECT macro");
}

void MissingQ_OBJECT::registerQ_OBJECT(SourceLocation loc)
{
    m_qobjectMacroLocations.push_back(loc);
}

REGISTER_CHECK_WITH_FLAGS("missing-qobject-macro", MissingQ_OBJECT, CheckLevel1)

#endif // clang >= 3.7
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkOnce.h"
#include "SkOpts.h"

#define SK_OPTS_NS sk_default
#include "SkBlitMask_opts.h"
#include "SkBlitRow_opts.h"
#include "SkBlurImageFilter_opts.h"
#include "SkColorCubeFilter_opts.h"
#include "SkFloatingPoint_opts.h"
#include "SkMatrix_opts.h"
#include "SkMorphologyImageFilter_opts.h"
#include "SkTextureCompressor_opts.h"
#include "SkUtils_opts.h"
#include "SkXfermode_opts.h"

#if defined(SK_CPU_X86)
    #if defined(SK_BUILD_FOR_WIN32)
        #include <intrin.h>
        static void cpuid (uint32_t abcd[4]) { __cpuid  ((int*)abcd, 1);    }
        static void cpuid7(uint32_t abcd[4]) { __cpuidex((int*)abcd, 7, 0); }
        static uint64_t xgetbv(uint32_t xcr) { return _xgetbv(xcr); }
    #else
        #include <cpuid.h>
        #if !defined(__cpuid_count)  // Old Mac Clang doesn't have this defined.
            #define  __cpuid_count(eax, ecx, a, b, c, d) \
                __asm__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(eax), "2"(ecx))
        #endif
        static void cpuid (uint32_t abcd[4]) { __get_cpuid(1, abcd+0, abcd+1, abcd+2, abcd+3); }
        static void cpuid7(uint32_t abcd[4]) {
            __cpuid_count(7, 0, abcd[0], abcd[1], abcd[2], abcd[3]);
        }
        static uint64_t xgetbv(uint32_t xcr) {
            uint32_t eax, edx;
            __asm__ __volatile__ ( "xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
            return (uint64_t)(edx) << 32 | eax;
        }
    #endif
#elif !defined(SK_ARM_HAS_NEON)      && \
       defined(SK_CPU_ARM32)         && \
       defined(SK_BUILD_FOR_ANDROID) && \
      !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
    #include <cpu-features.h>
#endif

namespace SkOpts {
    // Define default function pointer values here...
    // If our global compile options are set high enough, these defaults might even be
    // CPU-specialized, e.g. a typical x86-64 machine might start with SSE2 defaults.
    // They'll still get a chance to be replaced with even better ones, e.g. using SSE4.1.
    decltype(rsqrt)                     rsqrt = sk_default::rsqrt;
    decltype(memset16)               memset16 = sk_default::memset16;
    decltype(memset32)               memset32 = sk_default::memset32;
    decltype(create_xfermode) create_xfermode = sk_default::create_xfermode;
    decltype(color_cube_filter_span) color_cube_filter_span = sk_default::color_cube_filter_span;

    decltype(box_blur_xx) box_blur_xx = sk_default::box_blur_xx;
    decltype(box_blur_xy) box_blur_xy = sk_default::box_blur_xy;
    decltype(box_blur_yx) box_blur_yx = sk_default::box_blur_yx;

    decltype(dilate_x) dilate_x = sk_default::dilate_x;
    decltype(dilate_y) dilate_y = sk_default::dilate_y;
    decltype( erode_x)  erode_x = sk_default::erode_x;
    decltype( erode_y)  erode_y = sk_default::erode_y;

    decltype(texture_compressor)       texture_compressor = sk_default::texture_compressor;
    decltype(fill_block_dimensions) fill_block_dimensions = sk_default::fill_block_dimensions;

    decltype(blit_mask_d32_a8) blit_mask_d32_a8 = sk_default::blit_mask_d32_a8;

    decltype(blit_row_color32) blit_row_color32 = sk_default::blit_row_color32;

    decltype(matrix_translate)       matrix_translate       = sk_default::matrix_translate;
    decltype(matrix_scale_translate) matrix_scale_translate = sk_default::matrix_scale_translate;
    decltype(matrix_affine)          matrix_affine          = sk_default::matrix_affine;

    // Each Init_foo() is defined in src/opts/SkOpts_foo.cpp.
    void Init_ssse3();
    void Init_sse41();
    void Init_sse42() {}
    void Init_avx();
    void Init_avx2() {}
    void Init_neon();

    static void init() {
        // TODO: Chrome's not linking _sse* opts on iOS simulator builds.  Bug or feature?
    #if defined(SK_CPU_X86) && !defined(SK_BUILD_FOR_IOS)
        uint32_t abcd[] = {0,0,0,0};
        cpuid(abcd);
        if (abcd[2] & (1<< 9)) { Init_ssse3(); }
        if (abcd[2] & (1<<19)) { Init_sse41(); }
        if (abcd[2] & (1<<20)) { Init_sse42(); }

        // AVX detection's kind of a pain.  This is cribbed from Chromium.
        if ( (  abcd[2] & (7<<26)) == (7<<26) &&    // Check bits 26-28 of ecx are all set,
             (xgetbv(0) & 6      ) == 6          ){ // and  check the OS supports XSAVE.
            Init_avx();

            // AVX2 additionally needs bit 5 set on ebx after calling cpuid(7).
            uint32_t abcd7[] = {0,0,0,0};
            cpuid7(abcd7);
            if (abcd7[1] & (1<<5)) { Init_avx2(); }
        }

    #elif !defined(SK_ARM_HAS_NEON)      && \
           defined(SK_CPU_ARM32)         && \
           defined(SK_BUILD_FOR_ANDROID) && \
          !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
        if (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) { Init_neon(); }
    #endif
    }

    SK_DECLARE_STATIC_ONCE(gInitOnce);
    void Init() { SkOnce(&gInitOnce, init); }

#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
    static struct AutoInit {
        AutoInit() { Init(); }
    } gAutoInit;
#endif
}
<commit_msg>Fix -Wunused-function warnings in chrome/ios builds.<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkOnce.h"
#include "SkOpts.h"

#define SK_OPTS_NS sk_default
#include "SkBlitMask_opts.h"
#include "SkBlitRow_opts.h"
#include "SkBlurImageFilter_opts.h"
#include "SkColorCubeFilter_opts.h"
#include "SkFloatingPoint_opts.h"
#include "SkMatrix_opts.h"
#include "SkMorphologyImageFilter_opts.h"
#include "SkTextureCompressor_opts.h"
#include "SkUtils_opts.h"
#include "SkXfermode_opts.h"

#if defined(SK_CPU_X86) && !defined(SK_BUILD_FOR_IOS)
    #if defined(SK_BUILD_FOR_WIN32)
        #include <intrin.h>
        static void cpuid (uint32_t abcd[4]) { __cpuid  ((int*)abcd, 1);    }
        static void cpuid7(uint32_t abcd[4]) { __cpuidex((int*)abcd, 7, 0); }
        static uint64_t xgetbv(uint32_t xcr) { return _xgetbv(xcr); }
    #else
        #include <cpuid.h>
        #if !defined(__cpuid_count)  // Old Mac Clang doesn't have this defined.
            #define  __cpuid_count(eax, ecx, a, b, c, d) \
                __asm__("cpuid" : "=a"(a), "=b"(b), "=c"(c), "=d"(d) : "0"(eax), "2"(ecx))
        #endif
        static void cpuid (uint32_t abcd[4]) { __get_cpuid(1, abcd+0, abcd+1, abcd+2, abcd+3); }
        static void cpuid7(uint32_t abcd[4]) {
            __cpuid_count(7, 0, abcd[0], abcd[1], abcd[2], abcd[3]);
        }
        static uint64_t xgetbv(uint32_t xcr) {
            uint32_t eax, edx;
            __asm__ __volatile__ ( "xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
            return (uint64_t)(edx) << 32 | eax;
        }
    #endif
#elif !defined(SK_ARM_HAS_NEON)      && \
       defined(SK_CPU_ARM32)         && \
       defined(SK_BUILD_FOR_ANDROID) && \
      !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
    #include <cpu-features.h>
#endif

namespace SkOpts {
    // Define default function pointer values here...
    // If our global compile options are set high enough, these defaults might even be
    // CPU-specialized, e.g. a typical x86-64 machine might start with SSE2 defaults.
    // They'll still get a chance to be replaced with even better ones, e.g. using SSE4.1.
    decltype(rsqrt)                     rsqrt = sk_default::rsqrt;
    decltype(memset16)               memset16 = sk_default::memset16;
    decltype(memset32)               memset32 = sk_default::memset32;
    decltype(create_xfermode) create_xfermode = sk_default::create_xfermode;
    decltype(color_cube_filter_span) color_cube_filter_span = sk_default::color_cube_filter_span;

    decltype(box_blur_xx) box_blur_xx = sk_default::box_blur_xx;
    decltype(box_blur_xy) box_blur_xy = sk_default::box_blur_xy;
    decltype(box_blur_yx) box_blur_yx = sk_default::box_blur_yx;

    decltype(dilate_x) dilate_x = sk_default::dilate_x;
    decltype(dilate_y) dilate_y = sk_default::dilate_y;
    decltype( erode_x)  erode_x = sk_default::erode_x;
    decltype( erode_y)  erode_y = sk_default::erode_y;

    decltype(texture_compressor)       texture_compressor = sk_default::texture_compressor;
    decltype(fill_block_dimensions) fill_block_dimensions = sk_default::fill_block_dimensions;

    decltype(blit_mask_d32_a8) blit_mask_d32_a8 = sk_default::blit_mask_d32_a8;

    decltype(blit_row_color32) blit_row_color32 = sk_default::blit_row_color32;

    decltype(matrix_translate)       matrix_translate       = sk_default::matrix_translate;
    decltype(matrix_scale_translate) matrix_scale_translate = sk_default::matrix_scale_translate;
    decltype(matrix_affine)          matrix_affine          = sk_default::matrix_affine;

    // Each Init_foo() is defined in src/opts/SkOpts_foo.cpp.
    void Init_ssse3();
    void Init_sse41();
    void Init_sse42() {}
    void Init_avx();
    void Init_avx2() {}
    void Init_neon();

    static void init() {
        // TODO: Chrome's not linking _sse* opts on iOS simulator builds.  Bug or feature?
    #if defined(SK_CPU_X86) && !defined(SK_BUILD_FOR_IOS)
        uint32_t abcd[] = {0,0,0,0};
        cpuid(abcd);
        if (abcd[2] & (1<< 9)) { Init_ssse3(); }
        if (abcd[2] & (1<<19)) { Init_sse41(); }
        if (abcd[2] & (1<<20)) { Init_sse42(); }

        // AVX detection's kind of a pain.  This is cribbed from Chromium.
        if ( (  abcd[2] & (7<<26)) == (7<<26) &&    // Check bits 26-28 of ecx are all set,
             (xgetbv(0) & 6      ) == 6          ){ // and  check the OS supports XSAVE.
            Init_avx();

            // AVX2 additionally needs bit 5 set on ebx after calling cpuid(7).
            uint32_t abcd7[] = {0,0,0,0};
            cpuid7(abcd7);
            if (abcd7[1] & (1<<5)) { Init_avx2(); }
        }

    #elif !defined(SK_ARM_HAS_NEON)      && \
           defined(SK_CPU_ARM32)         && \
           defined(SK_BUILD_FOR_ANDROID) && \
          !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
        if (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) { Init_neon(); }
    #endif
    }

    SK_DECLARE_STATIC_ONCE(gInitOnce);
    void Init() { SkOnce(&gInitOnce, init); }

#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
    static struct AutoInit {
        AutoInit() { Init(); }
    } gAutoInit;
#endif
}
<|endoftext|>


<commit_before>/*--------------------------------------------------------------------------
File   : i2c_spi_nrf52_irq.cpp

Author : Hoang Nguyen Hoan          July 20, 2018

Desc   : Shared IRQ handler for I2C, SPI

Copyright (c) 2018, I-SYST inc., all rights reserved

Permission to use, copy, modify, and distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright
notice and this permission notice appear in all copies, and none of the
names : I-SYST or its contributors may be used to endorse or
promote products derived from this software without specific prior written
permission.

For info or contributing contact : hnhoan at i-syst dot com

THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.

----------------------------------------------------------------------------
Modified by         Date            Description

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

#include "device_intrf.h"
#include "i2c_spi_nrf52_irq.h"

typedef struct {
	DEVINTRF *pDev;				// Device interface data
	IRQHANDLER Handler ;		// Device interface interrupt handler
} IRQDATA;

#define MAX_NB_DEV		2

static IRQDATA s_DevIrq[MAX_NB_DEV] = { {NULL, }, };

void SetI2cSpiIntHandler(int DevNo, DEVINTRF *pDev, IRQHANDLER Handler)
{
	if (DevNo < 0 || DevNo >= MAX_NB_DEV)
	{
		return;
	}

	s_DevIrq[DevNo].pDev = pDev;
	s_DevIrq[DevNo].Handler = Handler;
}

extern "C" void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void)
{
	if (s_DevIrq[0].pDev != NULL)
	{
		s_DevIrq[0].Handler(0, s_DevIrq[0].pDev);
	}
}

extern "C" void SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler(void)
{
	if (s_DevIrq[1].pDev != NULL)
	{
		s_DevIrq[1].Handler(1, s_DevIrq[1].pDev);
	}
}
<commit_msg>SPI2 interrupt<commit_after>/*--------------------------------------------------------------------------
File   : i2c_spi_nrf52_irq.cpp

Author : Hoang Nguyen Hoan          July 20, 2018

Desc   : Shared IRQ handler for I2C, SPI

Copyright (c) 2018, I-SYST inc., all rights reserved

Permission to use, copy, modify, and distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright
notice and this permission notice appear in all copies, and none of the
names : I-SYST or its contributors may be used to endorse or
promote products derived from this software without specific prior written
permission.

For info or contributing contact : hnhoan at i-syst dot com

THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.

----------------------------------------------------------------------------
Modified by         Date            Description

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

#include "device_intrf.h"
#include "i2c_spi_nrf52_irq.h"

typedef struct {
	DEVINTRF *pDev;				// Device interface data
	IRQHANDLER Handler ;		// Device interface interrupt handler
} IRQDATA;

#define MAX_NB_DEV		3

static IRQDATA s_DevIrq[MAX_NB_DEV] = { {NULL, }, };

void SetI2cSpiIntHandler(int DevNo, DEVINTRF *pDev, IRQHANDLER Handler)
{
	if (DevNo < 0 || DevNo >= MAX_NB_DEV)
	{
		return;
	}

	s_DevIrq[DevNo].pDev = pDev;
	s_DevIrq[DevNo].Handler = Handler;
}

extern "C" void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void)
{
	if (s_DevIrq[0].pDev != NULL)
	{
		s_DevIrq[0].Handler(0, s_DevIrq[0].pDev);
	}
}

extern "C" void SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler(void)
{
	if (s_DevIrq[1].pDev != NULL)
	{
		s_DevIrq[1].Handler(1, s_DevIrq[1].pDev);
	}
}

extern "C" void SPIM2_SPIS2_SPI2_IRQHandler(void)
{
    if (s_DevIrq[2].pDev != NULL)
    {
        s_DevIrq[2].Handler(2, s_DevIrq[1].pDev);
    }
}
<|endoftext|>


<commit_before>//                       MFEM Example 3 - Parallel Version
//
// Compile with: make ex3p
//
// Sample runs:  mpirun -np 4 ex3p -m ../data/star.mesh
//               mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
//               mpirun -np 4 ex3p -m ../data/beam-tet.mesh
//               mpirun -np 4 ex3p -m ../data/beam-hex.mesh
//               mpirun -np 4 ex3p -m ../data/escher.mesh
//               mpirun -np 4 ex3p -m ../data/escher.mesh -o 2
//               mpirun -np 4 ex3p -m ../data/fichera.mesh
//               mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
//               mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
//               mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
//               mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
//               mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
//               mpirun -np 4 ex3p -m ../data/amr-hex.mesh
//               mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
//               mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
//               mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
//
// Description:  This example code solves a simple electromagnetic diffusion
//               problem corresponding to the second order definite Maxwell
//               equation curl curl E + E = f with boundary condition
//               E x n = <given tangential field>. Here, we use a given exact
//               solution E and compute the corresponding r.h.s. f.
//               We discretize with Nedelec finite elements in 2D or 3D.
//
//               The example demonstrates the use of H(curl) finite element
//               spaces with the curl-curl and the (vector finite element) mass
//               bilinear form, as well as the computation of discretization
//               error when the exact solution is known. Static condensation is
//               also illustrated.
//
//               We recommend viewing examples 1-2 before viewing this example.

#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace std;
using namespace mfem;

// Exact solution, E, and r.h.s., f. See below for implementation.
void E_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
double freq = 1.0, kappa;
int dim;

int main(int argc, char *argv[])
{
   // 1. Initialize MPI.
   int num_procs, myid;
   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
   MPI_Comm_rank(MPI_COMM_WORLD, &myid);

   // 2. Parse command-line options.
   const char *mesh_file = "../data/beam-tet.mesh";
   int order = 1;
   bool static_cond = false;
   bool visualization = 1;

   OptionsParser args(argc, argv);
   args.AddOption(&mesh_file, "-m", "--mesh",
                  "Mesh file to use.");
   args.AddOption(&order, "-o", "--order",
                  "Finite element order (polynomial degree).");
   args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
                  " solution.");
   args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
                  "--no-static-condensation", "Enable static condensation.");
   args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
                  "--no-visualization",
                  "Enable or disable GLVis visualization.");

   args.Parse();
   if (!args.Good())
   {
      if (myid == 0)
      {
         args.PrintUsage(cout);
      }
      MPI_Finalize();
      return 1;
   }
   if (myid == 0)
   {
      args.PrintOptions(cout);
   }
   kappa = freq * M_PI;

   // 3. Read the (serial) mesh from the given mesh file on all processors.  We
   //    can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
   //    and volume meshes with the same code.
   Mesh *mesh = new Mesh(mesh_file, 1, 1);
   dim = mesh->Dimension();
   int sdim = mesh->SpaceDimension();

   // 4. Refine the serial mesh on all processors to increase the resolution. In
   //    this example we do 'ref_levels' of uniform refinement. We choose
   //    'ref_levels' to be the largest number that gives a final mesh with no
   //    more than 1,000 elements.
   {
      int ref_levels = 1;
      // (int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
      for (int l = 0; l < ref_levels; l++)
      {
         mesh->UniformRefinement();
      }
   }

   // 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
   //    this mesh further in parallel to increase the resolution. Once the
   //    parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
   //    meshes need to be reoriented before we can define high-order Nedelec
   //    spaces on them.
   ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
   delete mesh;
   {
      int par_ref_levels = 1;
      for (int l = 0; l < par_ref_levels; l++)
      {
         pmesh->UniformRefinement();
      }
   }
   // pmesh->ReorientTetMesh();

   // 6. Define a parallel finite element space on the parallel mesh. Here we
   //    use the Nedelec finite elements of the specified order.
   FiniteElementCollection *fec = new ND_FECollection(order, dim);
   ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
   HYPRE_Int size = fespace->GlobalTrueVSize();
   if (myid == 0)
   {
      cout << "Number of finite element unknowns: " << size << endl;
   }

   // 7. Determine the list of true (i.e. parallel conforming) essential
   //    boundary dofs. In this example, the boundary conditions are defined
   //    by marking all the boundary attributes from the mesh as essential
   //    (Dirichlet) and converting them to a list of true dofs.
   Array<int> ess_tdof_list;
   if (pmesh->bdr_attributes.Size())
   {
      Array<int> ess_bdr(pmesh->bdr_attributes.Max());
      ess_bdr = 1;
      fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
   }

   // 8. Set up the parallel linear form b(.) which corresponds to the
   //    right-hand side of the FEM linear system, which in this case is
   //    (f,phi_i) where f is given by the function f_exact and phi_i are the
   //    basis functions in the finite element fespace.
   VectorFunctionCoefficient f(sdim, f_exact);
   ParLinearForm *b = new ParLinearForm(fespace);
   b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
   b->Assemble();

   // 9. Define the solution vector x as a parallel finite element grid function
   //    corresponding to fespace. Initialize x by projecting the exact
   //    solution. Note that only values from the boundary edges will be used
   //    when eliminating the non-homogeneous boundary condition to modify the
   //    r.h.s. vector b.
   ParGridFunction x(fespace);
   VectorFunctionCoefficient E(sdim, E_exact);
   x.ProjectCoefficient(E);

   // 10. Set up the parallel bilinear form corresponding to the EM diffusion
   //     operator curl muinv curl + sigma I, by adding the curl-curl and the
   //     mass domain integrators.
   Coefficient *muinv = new ConstantCoefficient(1.0);
   Coefficient *sigma = new ConstantCoefficient(1.0);
   ParBilinearForm *a = new ParBilinearForm(fespace);
   a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
   a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));

   // 11. Assemble the parallel bilinear form and the corresponding linear
   //     system, applying any necessary transformations such as: parallel
   //     assembly, eliminating boundary conditions, applying conforming
   //     constraints for non-conforming AMR, static condensation, etc.
   if (static_cond) { a->EnableStaticCondensation(); }
   a->Assemble();

   HypreParMatrix A;
   Vector B, X;
   a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);

   if (myid == 0)
   {
      cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
   }

   // 12. Define and apply a parallel PCG solver for AX=B with the AMS
   //     preconditioner from hypre.
   ParFiniteElementSpace *prec_fespace =
      (a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
   HypreSolver *ams = new HypreAMS(A, prec_fespace);
   HyprePCG *pcg = new HyprePCG(A);
   pcg->SetTol(1e-12);
   pcg->SetMaxIter(500);
   pcg->SetPrintLevel(2);
   pcg->SetPreconditioner(*ams);
   pcg->Mult(B, X);

   // 13. Recover the parallel grid function corresponding to X. This is the
   //     local finite element solution on each processor.
   a->RecoverFEMSolution(X, *b, x);

   // 14. Compute and print the L^2 norm of the error.
   {
      double err = x.ComputeL2Error(E);
      if (myid == 0)
      {
         cout << "\n|| E_h - E ||_{L^2} = " << err << '\n' << endl;
      }
   }

   // 15. Save the refined mesh and the solution in parallel. This output can
   //     be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
   {
      ostringstream mesh_name, sol_name;
      mesh_name << "mesh." << setfill('0') << setw(6) << myid;
      sol_name << "sol." << setfill('0') << setw(6) << myid;

      ofstream mesh_ofs(mesh_name.str().c_str());
      mesh_ofs.precision(8);
      pmesh->Print(mesh_ofs);

      ofstream sol_ofs(sol_name.str().c_str());
      sol_ofs.precision(8);
      x.Save(sol_ofs);
   }

   // 16. Send the solution by socket to a GLVis server.
   if (visualization)
   {
      char vishost[] = "localhost";
      int  visport   = 19916;
      socketstream sol_sock(vishost, visport);
      sol_sock << "parallel " << num_procs << " " << myid << "\n";
      sol_sock.precision(8);
      sol_sock << "solution\n" << *pmesh << x << flush;
   }

   // 17. Free the used memory.
   delete pcg;
   delete ams;
   delete a;
   delete sigma;
   delete muinv;
   delete b;
   delete fespace;
   delete fec;
   delete pmesh;

   MPI_Finalize();

   return 0;
}

void E_exact(const Vector &x, Vector &E)
{
   if (dim == 3)
   {
      E(0) = sin(kappa * x(1));
      E(1) = sin(kappa * x(2));
      E(2) = sin(kappa * x(0));
   }
   else
   {
      E(0) = sin(kappa * x(1));
      E(1) = sin(kappa * x(0));
      if (x.Size() == 3) { E(2) = 0.0; }
   }
}

void f_exact(const Vector &x, Vector &f)
{
   if (dim == 3)
   {
      f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
      f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
      f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
   }
   else
   {
      f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
      f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
      if (x.Size() == 3) { f(2) = 0.0; }
   }
}
<commit_msg>Adding refinement control to ex3p<commit_after>//                       MFEM Example 3 - Parallel Version
//
// Compile with: make ex3p
//
// Sample runs:  mpirun -np 4 ex3p -m ../data/star.mesh
//               mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
//               mpirun -np 4 ex3p -m ../data/beam-tet.mesh
//               mpirun -np 4 ex3p -m ../data/beam-hex.mesh
//               mpirun -np 4 ex3p -m ../data/escher.mesh
//               mpirun -np 4 ex3p -m ../data/escher.mesh -o 2
//               mpirun -np 4 ex3p -m ../data/fichera.mesh
//               mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
//               mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
//               mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
//               mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
//               mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
//               mpirun -np 4 ex3p -m ../data/amr-hex.mesh
//               mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
//               mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
//               mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
//
// Description:  This example code solves a simple electromagnetic diffusion
//               problem corresponding to the second order definite Maxwell
//               equation curl curl E + E = f with boundary condition
//               E x n = <given tangential field>. Here, we use a given exact
//               solution E and compute the corresponding r.h.s. f.
//               We discretize with Nedelec finite elements in 2D or 3D.
//
//               The example demonstrates the use of H(curl) finite element
//               spaces with the curl-curl and the (vector finite element) mass
//               bilinear form, as well as the computation of discretization
//               error when the exact solution is known. Static condensation is
//               also illustrated.
//
//               We recommend viewing examples 1-2 before viewing this example.

#include "mfem.hpp"
#include <fstream>
#include <iostream>

using namespace std;
using namespace mfem;

// Exact solution, E, and r.h.s., f. See below for implementation.
void E_exact(const Vector &, Vector &);
void f_exact(const Vector &, Vector &);
double freq = 1.0, kappa;
int dim;

int main(int argc, char *argv[])
{
   // 1. Initialize MPI.
   int num_procs, myid;
   MPI_Init(&argc, &argv);
   MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
   MPI_Comm_rank(MPI_COMM_WORLD, &myid);

   // 2. Parse command-line options.
   const char *mesh_file = "../data/beam-tet.mesh";
   int ser_ref_levels = -1;
   int par_ref_levels = 1;
   int order = 1;
   bool static_cond = false;
   bool visualization = 1;

   OptionsParser args(argc, argv);
   args.AddOption(&mesh_file, "-m", "--mesh",
                  "Mesh file to use.");
   args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
                  "Number of times to refine the mesh uniformly in serial.");
   args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
                  "Number of times to refine the mesh uniformly in parallel.");
   args.AddOption(&order, "-o", "--order",
                  "Finite element order (polynomial degree).");
   args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
                  " solution.");
   args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
                  "--no-static-condensation", "Enable static condensation.");
   args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
                  "--no-visualization",
                  "Enable or disable GLVis visualization.");

   args.Parse();
   if (!args.Good())
   {
      if (myid == 0)
      {
         args.PrintUsage(cout);
      }
      MPI_Finalize();
      return 1;
   }
   if (myid == 0)
   {
      args.PrintOptions(cout);
   }
   kappa = freq * M_PI;

   // 3. Read the (serial) mesh from the given mesh file on all processors.  We
   //    can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
   //    and volume meshes with the same code.
   Mesh *mesh = new Mesh(mesh_file, 1, 1);
   dim = mesh->Dimension();
   int sdim = mesh->SpaceDimension();

   // 4. Refine the serial mesh on all processors to increase the resolution. In
   //    this example we do 'ref_levels' of uniform refinement. We choose
   //    'ref_levels' to be the largest number that gives a final mesh with no
   //    more than 1,000 elements.
   {
      int ref_levels = (ser_ref_levels >= 0) ? ser_ref_levels :
                       (int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
      for (int l = 0; l < ref_levels; l++)
      {
         mesh->UniformRefinement();
      }
   }

   // 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
   //    this mesh further in parallel to increase the resolution. Once the
   //    parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
   //    meshes need to be reoriented before we can define high-order Nedelec
   //    spaces on them.
   ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
   delete mesh;
   {
      for (int l = 0; l < par_ref_levels; l++)
      {
         pmesh->UniformRefinement();
      }
   }
   // pmesh->ReorientTetMesh();

   // 6. Define a parallel finite element space on the parallel mesh. Here we
   //    use the Nedelec finite elements of the specified order.
   FiniteElementCollection *fec = new ND_FECollection(order, dim);
   ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
   HYPRE_Int size = fespace->GlobalTrueVSize();
   if (myid == 0)
   {
      cout << "Number of finite element unknowns: " << size << endl;
   }

   // 7. Determine the list of true (i.e. parallel conforming) essential
   //    boundary dofs. In this example, the boundary conditions are defined
   //    by marking all the boundary attributes from the mesh as essential
   //    (Dirichlet) and converting them to a list of true dofs.
   Array<int> ess_tdof_list;
   if (pmesh->bdr_attributes.Size())
   {
      Array<int> ess_bdr(pmesh->bdr_attributes.Max());
      ess_bdr = 1;
      fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
   }

   // 8. Set up the parallel linear form b(.) which corresponds to the
   //    right-hand side of the FEM linear system, which in this case is
   //    (f,phi_i) where f is given by the function f_exact and phi_i are the
   //    basis functions in the finite element fespace.
   VectorFunctionCoefficient f(sdim, f_exact);
   ParLinearForm *b = new ParLinearForm(fespace);
   b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
   b->Assemble();

   // 9. Define the solution vector x as a parallel finite element grid function
   //    corresponding to fespace. Initialize x by projecting the exact
   //    solution. Note that only values from the boundary edges will be used
   //    when eliminating the non-homogeneous boundary condition to modify the
   //    r.h.s. vector b.
   ParGridFunction x(fespace);
   VectorFunctionCoefficient E(sdim, E_exact);
   x.ProjectCoefficient(E);

   // 10. Set up the parallel bilinear form corresponding to the EM diffusion
   //     operator curl muinv curl + sigma I, by adding the curl-curl and the
   //     mass domain integrators.
   Coefficient *muinv = new ConstantCoefficient(1.0);
   Coefficient *sigma = new ConstantCoefficient(1.0);
   ParBilinearForm *a = new ParBilinearForm(fespace);
   a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
   a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));

   // 11. Assemble the parallel bilinear form and the corresponding linear
   //     system, applying any necessary transformations such as: parallel
   //     assembly, eliminating boundary conditions, applying conforming
   //     constraints for non-conforming AMR, static condensation, etc.
   if (static_cond) { a->EnableStaticCondensation(); }
   a->Assemble();

   HypreParMatrix A;
   Vector B, X;
   a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);

   if (myid == 0)
   {
      cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
   }

   // 12. Define and apply a parallel PCG solver for AX=B with the AMS
   //     preconditioner from hypre.
   ParFiniteElementSpace *prec_fespace =
      (a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
   HypreSolver *ams = new HypreAMS(A, prec_fespace);
   HyprePCG *pcg = new HyprePCG(A);
   pcg->SetTol(1e-12);
   pcg->SetMaxIter(500);
   pcg->SetPrintLevel(2);
   pcg->SetPreconditioner(*ams);
   pcg->Mult(B, X);

   // 13. Recover the parallel grid function corresponding to X. This is the
   //     local finite element solution on each processor.
   a->RecoverFEMSolution(X, *b, x);

   // 14. Compute and print the L^2 norm of the error.
   {
      double err = x.ComputeL2Error(E);
      if (myid == 0)
      {
         cout << "\n|| E_h - E ||_{L^2} = " << err << '\n' << endl;
      }
   }

   // 15. Save the refined mesh and the solution in parallel. This output can
   //     be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
   {
      ostringstream mesh_name, sol_name;
      mesh_name << "mesh." << setfill('0') << setw(6) << myid;
      sol_name << "sol." << setfill('0') << setw(6) << myid;

      ofstream mesh_ofs(mesh_name.str().c_str());
      mesh_ofs.precision(8);
      pmesh->Print(mesh_ofs);

      ofstream sol_ofs(sol_name.str().c_str());
      sol_ofs.precision(8);
      x.Save(sol_ofs);
   }

   // 16. Send the solution by socket to a GLVis server.
   if (visualization)
   {
      char vishost[] = "localhost";
      int  visport   = 19916;
      socketstream sol_sock(vishost, visport);
      sol_sock << "parallel " << num_procs << " " << myid << "\n";
      sol_sock.precision(8);
      sol_sock << "solution\n" << *pmesh << x << flush;
   }

   // 17. Free the used memory.
   delete pcg;
   delete ams;
   delete a;
   delete sigma;
   delete muinv;
   delete b;
   delete fespace;
   delete fec;
   delete pmesh;

   MPI_Finalize();

   return 0;
}

void E_exact(const Vector &x, Vector &E)
{
   if (dim == 3)
   {
      E(0) = sin(kappa * x(1));
      E(1) = sin(kappa * x(2));
      E(2) = sin(kappa * x(0));
   }
   else
   {
      E(0) = sin(kappa * x(1));
      E(1) = sin(kappa * x(0));
      if (x.Size() == 3) { E(2) = 0.0; }
   }
}

void f_exact(const Vector &x, Vector &f)
{
   if (dim == 3)
   {
      f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
      f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
      f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
   }
   else
   {
      f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
      f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
      if (x.Size() == 3) { f(2) = 0.0; }
   }
}
<|endoftext|>


<commit_before>#include <iostream>

#include "utils.h"
#include "numgrind.h"
#include "solvers/GradientDescentSolver.h"
#include "solvers/StochasticGradientDescentSolver.h"
#include "solvers/checkgradient.h"
#include "mnist.h"

float sigmoid(float z) {
    return (float) (1.0f / (1.0f + exp(-z)));
}

float sigmoidDer(float z) {
    const float sigZ = sigmoid(z);
    return sigZ * (1.0f - sigZ);
}

void logisticRegressionOperatorAndExample02() {
    using namespace NumGrind;
    using namespace NumGrind::SymbolicGraph;

    GraphManager gm;

    Eigen::MatrixXf data(4, 2);
    Eigen::VectorXf targets(4);
    data << 0, 0,
            0, 1,
            1, 0,
            1, 1;
    targets << 0, 0, 0, 1;

    auto X = gm.constant(data);
    auto y = gm.constant(targets);
    auto w = gm.variable(2, 1, 0);
    auto b = gm.variable(0);
    auto f = apply<sigmoid, sigmoidDer>(matmult(X, w) + b);
    auto residual = f - y;
    auto err = dot(residual, residual);

    auto vars = gm.initializeVariables();

    solvers::SolverSettings settings;
    settings.nMaxIterations = 20;
    solvers::gradientDescent(settings, 0.1, gm.funcFromNode(&err), gm.gradFromNode(&err), vars);
    f.node()->forwardPass(vars);
    std::cout << "Function result" << std::endl;
    std::cout << f.value() << std::endl;
    std::cout << "W:" << std::endl;
    std::cout << w.value() << std::endl;
    std::cout << "b:" << std::endl;
    std::cout << b.value() << std::endl;
}

void mlpOperatorOrExample01() {
    using namespace NumGrind::SymbolicGraph;
    NumGrind::GraphManager gm;

    Eigen::MatrixXf data(4, 2);
    Eigen::VectorXf targets(4);
    data << 0, 0,
            0, 1,
            1, 0,
            1, 1;
    targets << 0, 1, 1, 0;

    std::default_random_engine generator;
    generator.seed(42);

    auto X = gm.constant(data);
    auto y = gm.constant(targets);

    auto W1 = gm.variable(NumGrind::utils::gaussf(2, 2, 0.0, 0.5, generator));
    auto b1 = gm.variable(NumGrind::utils::gaussf(1, 2, 0.0, 0.5, generator));
    auto W2 = gm.variable(NumGrind::utils::gaussf(2, 1, 0.0, 0.01, generator));
    auto b2 = gm.variable(NumGrind::utils::gaussf(0.0f, 0.01f, generator));
    auto f1 = apply<sigmoid, sigmoidDer>(matmult(X, W1) + b1);
    auto f2 = apply<sigmoid, sigmoidDer>(matmult(f1, W2) + b2);
    auto residual = f2 - y;
    auto err = dot(residual, residual);

    auto vars = gm.initializeVariables();

    NumGrind::solvers::SolverSettings settings;
    settings.nMaxIterations = 40;

    std::cout << "is gradient ok? "
              << NumGrind::solvers::isGradientOk(gm.funcFromNode(&err), gm.gradFromNode(&err), vars) << std::endl;

    NumGrind::solvers::gradientDescent(settings, 2.0, gm.funcFromNode(&err), gm.gradFromNode(&err), vars);
    f2.node()->forwardPass(vars);
    std::cout << "Function result" << std::endl << f2.value() << std::endl;
    std::cout << "W1:" << std::endl << W1.value() << std::endl;
    std::cout << "W2:" << std::endl << W2.value() << std::endl;
    std::cout << "b2:" << std::endl << b2.value() << std::endl;
}

void mlpOperatorOrExample02() {
    using namespace NumGrind::SymbolicGraph;
    NumGrind::GraphManager gm;

    Eigen::MatrixXf data(4, 2);
    Eigen::VectorXf targets(4);
    data << 0, 0,
            0, 1,
            1, 0,
            1, 1;
    targets << 0, 1, 1, 0;

    std::default_random_engine generator;
    generator.seed(42);

    auto X = gm.constant(data);
    auto y = gm.constant(targets);

    auto W1 = gm.variable(NumGrind::utils::gaussf(2, 2, 0.0, 0.5, generator));
    auto b1 = gm.variable(NumGrind::utils::gaussf(1, 2, 0.0, 0.5, generator));
    auto W2 = gm.variable(NumGrind::utils::gaussf(2, 1, 0.0, 0.01, generator));
    auto b2 = gm.variable(NumGrind::utils::gaussf(0.0f, 0.01f, generator));
    auto f1 = apply<sigmoid, sigmoidDer>(matmult(X, W1) + b1);
    auto f2 = apply<sigmoid, sigmoidDer>(matmult(f1, W2) + b2);
    auto err = sumOfSquares(f2 - y);

    auto vars = gm.initializeVariables();

    NumGrind::solvers::SolverSettings settings;
    settings.nMaxIterations = 500;
    NumGrind::solvers::StochasticGradientDescentSolver solver(settings, 1.0);

    std::cout << "is gradient ok? "
              << NumGrind::solvers::isGradientOk(gm.funcFromNode(&err), gm.gradFromNode(&err), vars)
              << std::endl;

    const int nIters = 100;
    std::uniform_int_distribution<int> dist(0, data.rows() - 1);
    for (int iter = 0; iter < nIters; ++iter) {
        const int index = dist(generator);
        const Eigen::MatrixXf sample = data.row(index);
        const Eigen::MatrixXf label = targets.row(index);
        X.setValue(sample);
        y.setValue(label);
        solver.makeStep(gm.funcFromNode(&err), gm.gradFromNode(&err), vars);
    }

    X.setValue(data);
    y.setValue(targets);
    f2.node()->forwardPass(vars);
    std::cout << "Function result" << std::endl << f2.value() << std::endl;
    std::cout << "W1:" << std::endl << W1.value() << std::endl;
    std::cout << "W2:" << std::endl << W2.value() << std::endl;
    std::cout << "b2:" << std::endl << b2.value() << std::endl;
}

void mlpOperatorOrAndExample03() {
    using namespace NumGrind::SymbolicGraph;
    NumGrind::GraphManager gm;

    Eigen::MatrixXf data(4, 2);
    Eigen::MatrixXf targets(4, 3);
    data << 0, 0,
            0, 1,
            1, 0,
            1, 1;
    targets << 0, 0, 0,
               1, 0, 1,
               1, 0, 1,
               0, 1, 1;

    std::default_random_engine generator;
    generator.seed(42);

    auto X = gm.constant(data);
    auto y = gm.constant(targets);

    auto W1 = gm.variable(NumGrind::utils::gaussf(2, 2, 0.0, 0.5, generator));
    auto b1 = gm.variable(NumGrind::utils::gaussf(1, 2, 0.0, 0.5, generator));
    auto W2 = gm.variable(NumGrind::utils::gaussf(2, 3, 0.0, 0.01, generator));
    auto b2 = gm.variable(NumGrind::utils::gaussf(1, 3, 0.0f, 0.01f, generator));
    //auto b2 = gm.variable(NumGrind::utils::gaussf(0.0f, 0.01f, generator));
    auto f1 = apply<sigmoid, sigmoidDer>(matmult(X, W1) + b1);
    auto f2 = apply<sigmoid, sigmoidDer>(matmult(f1, W2) + b2);
    auto err = sumOfSquares(f2 - y);

    auto vars = gm.initializeVariables();

    NumGrind::solvers::SolverSettings settings;
    settings.nMaxIterations = 500;
    NumGrind::solvers::StochasticGradientDescentSolver solver(settings, 4.0);

    std::cout << "is gradient ok? "
              << NumGrind::solvers::isGradientOk(gm.funcFromNode(&err), gm.gradFromNode(&err), vars)
              << std::endl;

    const int nIters = 100;
    std::uniform_int_distribution<int> dist(0, data.rows() - 1);
    for (int iter = 0; iter < nIters; ++iter) {
        const int index = dist(generator);
        const Eigen::MatrixXf sample = data.row(index);
        const Eigen::MatrixXf label = targets.row(index);
        X.setValue(data);
        y.setValue(targets);
        solver.makeStep(gm.funcFromNode(&err), gm.gradFromNode(&err), vars);
    }

    f2.node()->forwardPass(vars);
    std::cout << "Function result" << std::endl << f2.value() << std::endl;
    std::cout << "W1:" << std::endl << W1.value() << std::endl;
    std::cout << "W2:" << std::endl << W2.value() << std::endl;
    std::cout << "b1:" << std::endl << b1.value() << std::endl;
    std::cout << "b2:" << std::endl << b2.value() << std::endl;
}

Eigen::MatrixXf labelsToMatrix(const Eigen::VectorXi &labels, const int nClasses)
{
    Eigen::MatrixXf trainLabels = Eigen::MatrixXf::Zero(labels.rows(), nClasses);
    for(int i = 0; i < trainLabels.rows(); ++i)
        trainLabels(i, labels[i]) = 1.0;
    return trainLabels;
}

Eigen::VectorXi argmaxRowwise(const Eigen::MatrixXf &mat){
    Eigen::VectorXi res = Eigen::VectorXi::Zero(mat.rows());
    for(int row = 0; row < mat.rows(); ++row){
        float maxVal = -10000;
        int maxInd = 0;
        for(int col = 0; col < mat.cols(); ++col){
            if(mat(row, col) > maxVal){
                maxVal = mat(row, col);
                maxInd = col;
            }
        }
        res[row] = maxInd;
    }
    return res;
}

void mnistTest01() {
    const std::string fnameMNISTDir = "/home/daiver/coding/data/mnist/";
    const std::string fnameImagesTrain = fnameMNISTDir + "train-images-idx3-ubyte";
    const std::string fnameLabelsTrain = fnameMNISTDir + "train-labels-idx1-ubyte";
    const std::string fnameImagesTest  = fnameMNISTDir + "t10k-images-idx3-ubyte";
    const std::string fnameLabelsTest  = fnameMNISTDir + "t10k-labels-idx1-ubyte";

    const Eigen::MatrixXf trainData   = mnist::readMNISTImages(fnameImagesTrain)/255.0;
    const Eigen::VectorXi trainLabelsPure = mnist::readMNISTLabels(fnameLabelsTrain);

    const Eigen::MatrixXf testData   = mnist::readMNISTImages(fnameImagesTest)/255.0;
    const Eigen::VectorXi testLabelsPure = mnist::readMNISTLabels(fnameLabelsTest);

    Eigen::MatrixXf trainLabels = labelsToMatrix(trainLabelsPure, 10);
    //Eigen::MatrixXf testLabels = labelsToMatrix(testLabelsPure, 10);

    std::default_random_engine generator;
    generator.seed(42);

    using namespace NumGrind::SymbolicGraph;
    NumGrind::GraphManager gm;

    auto X = gm.constant(trainData);
    auto y = gm.constant(trainLabels);

//    auto b1 = gm.variable(1, 10, 0);
    auto W1 = gm.variable(NumGrind::utils::gaussf(trainData.cols(), 100, 0.0, 0.05, generator));
    auto b1 = gm.variable(NumGrind::utils::gaussf(1, 100, 0.0, 0.05, generator));
    auto W2 = gm.variable(NumGrind::utils::gaussf(100, 10, 0.0, 0.01, generator));
    auto b2 = gm.variable(NumGrind::utils::gaussf(1, 10, 0.0f, 0.01f, generator));
    auto f1 = apply<sigmoid, sigmoidDer>(matmult(X, W1) + b1);
    auto f2 = apply<sigmoid, sigmoidDer>(matmult(f1, W2) + b2);
//    auto residual = f1 - y;
//    auto err = dot(residual, residual);
    //auto tmp = residual * residual;
    //auto err = reduceSum(residual);
    const int batchSize = 500;
    auto err = sumOfSquares(f2 - y);

    auto vars = gm.initializeVariables();

    NumGrind::solvers::SolverSettings settings;
    settings.nMaxIterations = 10;

    X.setValue(trainData.block(0, 0, batchSize, 28*28));
    y.setValue(trainLabels.block(0, 0, batchSize, 10));
    NumGrind::solvers::gradientDescent(settings, 0.0003, gm.funcFromNode(&err), gm.gradFromNode(&err), vars);
    settings.nMaxIterations = 5;
    for(int i = 0; i < 50; ++i){
        std::cout << "Epoch " << i << std::endl;
        X.setValue(trainData.block((i*batchSize) % trainData.rows(), 0, batchSize, 28*28));
        y.setValue(trainLabels.block((i*batchSize) % trainData.rows(), 0, batchSize, 10));
        NumGrind::solvers::gradientDescent(settings, 0.01, gm.funcFromNode(&err), gm.gradFromNode(&err), vars);
        if(i%10 == 0){
            X.setValue(testData);
            f2.node()->forwardPass(vars);
            auto res = f2.value();
            const auto colwiseMax = argmaxRowwise(res);
            int nErr = 0;
            for(int j = 0; j < colwiseMax.rows(); ++j){
                if(colwiseMax[j] != testLabelsPure[j])
                    nErr += 1;
            }
            std::cout << "err " << (float)nErr << " " << (float)nErr/testLabelsPure.rows()
                      << std::endl;
        }
    }
//    std::cout << trainLabelsPure << std::endl;
//    std::cout << W1.value() << std::endl;
//    std::cout << b1.value() << std::endl;
}

int main() {
//    logisticRegressionOperatorAndExample02();
//    mlpOperatorOrExample01();
//    mlpOperatorOrExample02();
//    mlpOperatorOrAndExample03();
    mnistTest01();
    return 0;
}

<commit_msg>MNIST/MLP/ReLU/SGD example. ~90% accuracy<commit_after>#include <iostream>

#include "utils.h"
#include "numgrind.h"
#include "solvers/GradientDescentSolver.h"
#include "solvers/StochasticGradientDescentSolver.h"
#include "solvers/checkgradient.h"
#include "mnist.h"

float sigmoid(float z)
{
    return (float) (1.0f / (1.0f + exp(-z)));
}

float sigmoidDer(float z)
{
    const float sigZ = sigmoid(z);
    return sigZ * (1.0f - sigZ);
}

float relu(float x)
{
    return std::max(0.0f, x);
}

float reluDer(float x)
{
    if(x < 0.0f)
        return 0.0f;
    return x;
}

void logisticRegressionOperatorAndExample02() {
    using namespace NumGrind;
    using namespace NumGrind::SymbolicGraph;

    GraphManager gm;

    Eigen::MatrixXf data(4, 2);
    Eigen::VectorXf targets(4);
    data << 0, 0,
            0, 1,
            1, 0,
            1, 1;
    targets << 0, 0, 0, 1;

    auto X = gm.constant(data);
    auto y = gm.constant(targets);
    auto w = gm.variable(2, 1, 0);
    auto b = gm.variable(0);
    auto f = apply<sigmoid, sigmoidDer>(matmult(X, w) + b);
    auto residual = f - y;
    auto err = dot(residual, residual);

    auto vars = gm.initializeVariables();

    solvers::SolverSettings settings;
    settings.nMaxIterations = 20;
    solvers::gradientDescent(settings, 0.1, gm.funcFromNode(&err), gm.gradFromNode(&err), vars);
    f.node()->forwardPass(vars);
    std::cout << "Function result" << std::endl;
    std::cout << f.value() << std::endl;
    std::cout << "W:" << std::endl;
    std::cout << w.value() << std::endl;
    std::cout << "b:" << std::endl;
    std::cout << b.value() << std::endl;
}

void mlpOperatorOrExample01() {
    using namespace NumGrind::SymbolicGraph;
    NumGrind::GraphManager gm;

    Eigen::MatrixXf data(4, 2);
    Eigen::VectorXf targets(4);
    data << 0, 0,
            0, 1,
            1, 0,
            1, 1;
    targets << 0, 1, 1, 0;

    std::default_random_engine generator;
    generator.seed(42);

    auto X = gm.constant(data);
    auto y = gm.constant(targets);

    auto W1 = gm.variable(NumGrind::utils::gaussf(2, 2, 0.0, 0.5, generator));
    auto b1 = gm.variable(NumGrind::utils::gaussf(1, 2, 0.0, 0.5, generator));
    auto W2 = gm.variable(NumGrind::utils::gaussf(2, 1, 0.0, 0.01, generator));
    auto b2 = gm.variable(NumGrind::utils::gaussf(0.0f, 0.01f, generator));
    auto f1 = apply<sigmoid, sigmoidDer>(matmult(X, W1) + b1);
    auto f2 = apply<sigmoid, sigmoidDer>(matmult(f1, W2) + b2);
    auto residual = f2 - y;
    auto err = dot(residual, residual);

    auto vars = gm.initializeVariables();

    NumGrind::solvers::SolverSettings settings;
    settings.nMaxIterations = 40;

    std::cout << "is gradient ok? "
              << NumGrind::solvers::isGradientOk(gm.funcFromNode(&err), gm.gradFromNode(&err), vars) << std::endl;

    NumGrind::solvers::gradientDescent(settings, 2.0, gm.funcFromNode(&err), gm.gradFromNode(&err), vars);
    f2.node()->forwardPass(vars);
    std::cout << "Function result" << std::endl << f2.value() << std::endl;
    std::cout << "W1:" << std::endl << W1.value() << std::endl;
    std::cout << "W2:" << std::endl << W2.value() << std::endl;
    std::cout << "b2:" << std::endl << b2.value() << std::endl;
}

void mlpOperatorOrExample02() {
    using namespace NumGrind::SymbolicGraph;
    NumGrind::GraphManager gm;

    Eigen::MatrixXf data(4, 2);
    Eigen::VectorXf targets(4);
    data << 0, 0,
            0, 1,
            1, 0,
            1, 1;
    targets << 0, 1, 1, 0;

    std::default_random_engine generator;
    generator.seed(42);

    auto X = gm.constant(data);
    auto y = gm.constant(targets);

    auto W1 = gm.variable(NumGrind::utils::gaussf(2, 2, 0.0, 0.5, generator));
    auto b1 = gm.variable(NumGrind::utils::gaussf(1, 2, 0.0, 0.5, generator));
    auto W2 = gm.variable(NumGrind::utils::gaussf(2, 1, 0.0, 0.01, generator));
    auto b2 = gm.variable(NumGrind::utils::gaussf(0.0f, 0.01f, generator));
    auto f1 = apply<sigmoid, sigmoidDer>(matmult(X, W1) + b1);
    auto f2 = apply<sigmoid, sigmoidDer>(matmult(f1, W2) + b2);
    auto err = sumOfSquares(f2 - y);

    auto vars = gm.initializeVariables();

    NumGrind::solvers::SolverSettings settings;
    settings.nMaxIterations = 500;
    NumGrind::solvers::StochasticGradientDescentSolver solver(settings, 1.0);

    std::cout << "is gradient ok? "
              << NumGrind::solvers::isGradientOk(gm.funcFromNode(&err), gm.gradFromNode(&err), vars)
              << std::endl;

    const int nIters = 100;
    std::uniform_int_distribution<int> dist(0, data.rows() - 1);
    for (int iter = 0; iter < nIters; ++iter) {
        const int index = dist(generator);
        const Eigen::MatrixXf sample = data.row(index);
        const Eigen::MatrixXf label = targets.row(index);
        X.setValue(sample);
        y.setValue(label);
        solver.makeStep(gm.funcFromNode(&err), gm.gradFromNode(&err), vars);
    }

    X.setValue(data);
    y.setValue(targets);
    f2.node()->forwardPass(vars);
    std::cout << "Function result" << std::endl << f2.value() << std::endl;
    std::cout << "W1:" << std::endl << W1.value() << std::endl;
    std::cout << "W2:" << std::endl << W2.value() << std::endl;
    std::cout << "b2:" << std::endl << b2.value() << std::endl;
}

void mlpOperatorOrAndExample03() {
    using namespace NumGrind::SymbolicGraph;
    NumGrind::GraphManager gm;

    Eigen::MatrixXf data(4, 2);
    Eigen::MatrixXf targets(4, 3);
    data << 0, 0,
            0, 1,
            1, 0,
            1, 1;
    targets << 0, 0, 0,
               1, 0, 1,
               1, 0, 1,
               0, 1, 1;

    std::default_random_engine generator;
    generator.seed(42);

    auto X = gm.constant(data);
    auto y = gm.constant(targets);

    auto W1 = gm.variable(NumGrind::utils::gaussf(2, 2, 0.0, 0.5, generator));
    auto b1 = gm.variable(NumGrind::utils::gaussf(1, 2, 0.0, 0.5, generator));
    auto W2 = gm.variable(NumGrind::utils::gaussf(2, 3, 0.0, 0.01, generator));
    auto b2 = gm.variable(NumGrind::utils::gaussf(1, 3, 0.0f, 0.01f, generator));
    //auto b2 = gm.variable(NumGrind::utils::gaussf(0.0f, 0.01f, generator));
    auto f1 = apply<sigmoid, sigmoidDer>(matmult(X, W1) + b1);
    auto f2 = apply<sigmoid, sigmoidDer>(matmult(f1, W2) + b2);
    auto err = sumOfSquares(f2 - y);

    auto vars = gm.initializeVariables();

    NumGrind::solvers::SolverSettings settings;
    settings.nMaxIterations = 500;
    NumGrind::solvers::StochasticGradientDescentSolver solver(settings, 4.0);

    std::cout << "is gradient ok? "
              << NumGrind::solvers::isGradientOk(gm.funcFromNode(&err), gm.gradFromNode(&err), vars)
              << std::endl;

    const int nIters = 100;
    std::uniform_int_distribution<int> dist(0, data.rows() - 1);
    for (int iter = 0; iter < nIters; ++iter) {
        const int index = dist(generator);
        const Eigen::MatrixXf sample = data.row(index);
        const Eigen::MatrixXf label = targets.row(index);
        X.setValue(data);
        y.setValue(targets);
        solver.makeStep(gm.funcFromNode(&err), gm.gradFromNode(&err), vars);
    }

    f2.node()->forwardPass(vars);
    std::cout << "Function result" << std::endl << f2.value() << std::endl;
    std::cout << "W1:" << std::endl << W1.value() << std::endl;
    std::cout << "W2:" << std::endl << W2.value() << std::endl;
    std::cout << "b1:" << std::endl << b1.value() << std::endl;
    std::cout << "b2:" << std::endl << b2.value() << std::endl;
}

Eigen::MatrixXf labelsToMatrix(const Eigen::VectorXi &labels, const int nClasses)
{
    Eigen::MatrixXf trainLabels = Eigen::MatrixXf::Zero(labels.rows(), nClasses);
    for(int i = 0; i < trainLabels.rows(); ++i)
        trainLabels(i, labels[i]) = 1.0;
    return trainLabels;
}

Eigen::VectorXi argmaxRowwise(const Eigen::MatrixXf &mat){
    Eigen::VectorXi res = Eigen::VectorXi::Zero(mat.rows());
    for(int row = 0; row < mat.rows(); ++row){
        float maxVal = -10000;
        int maxInd = 0;
        for(int col = 0; col < mat.cols(); ++col){
            if(mat(row, col) > maxVal){
                maxVal = mat(row, col);
                maxInd = col;
            }
        }
        res[row] = maxInd;
    }
    return res;
}

void mnistTest01() {
    const std::string fnameMNISTDir = "/home/daiver/coding/data/mnist/";
    const std::string fnameImagesTrain = fnameMNISTDir + "train-images-idx3-ubyte";
    const std::string fnameLabelsTrain = fnameMNISTDir + "train-labels-idx1-ubyte";
    const std::string fnameImagesTest  = fnameMNISTDir + "t10k-images-idx3-ubyte";
    const std::string fnameLabelsTest  = fnameMNISTDir + "t10k-labels-idx1-ubyte";

    const Eigen::MatrixXf trainData   = mnist::readMNISTImages(fnameImagesTrain)/255.0;
    const Eigen::VectorXi trainLabelsPure = mnist::readMNISTLabels(fnameLabelsTrain);

    const Eigen::MatrixXf testData   = mnist::readMNISTImages(fnameImagesTest)/255.0;
    const Eigen::VectorXi testLabelsPure = mnist::readMNISTLabels(fnameLabelsTest);

    Eigen::MatrixXf trainLabels = labelsToMatrix(trainLabelsPure, 10);
    //Eigen::MatrixXf testLabels = labelsToMatrix(testLabelsPure, 10);

    std::default_random_engine generator;
    generator.seed(42);

    using namespace NumGrind::SymbolicGraph;
    NumGrind::GraphManager gm;

    auto X = gm.constant(trainData);
    auto y = gm.constant(trainLabels);

//    auto b1 = gm.variable(1, 10, 0);
    auto W1 = gm.variable(NumGrind::utils::gaussf(trainData.cols(), 300, 0.0, 0.02, generator));
    auto b1 = gm.variable(NumGrind::utils::gaussf(1, 300, 0.0, 0.02, generator));
    auto W2 = gm.variable(NumGrind::utils::gaussf(300, 10, 0.0, 0.01, generator));
    auto b2 = gm.variable(NumGrind::utils::gaussf(1, 10, 0.0f, 0.01f, generator));
    //auto f1 = apply<sigmoid, sigmoidDer>(matmult(X, W1) + b1);
    auto f1 = apply<relu, reluDer>(matmult(X, W1) + b1);
    auto f2 = apply<sigmoid, sigmoidDer>(matmult(f1, W2) + b2);

    auto output = f2;
//    auto residual = f1 - y;
//    auto err = dot(residual, residual);
    //auto tmp = residual * residual;
    //auto err = reduceSum(residual);
    const int batchSize = 60;
    auto err = sumOfSquares(output - y);

    auto vars = gm.initializeVariables();

    NumGrind::solvers::SolverSettings settings;
    settings.nMaxIterations = 10;

    X.setValue(trainData.block(0, 0, batchSize, 28*28));
    y.setValue(trainLabels.block(0, 0, batchSize, 10));
    NumGrind::solvers::gradientDescent(settings, 0.0003, gm.funcFromNode(&err), gm.gradFromNode(&err), vars);
    settings.nMaxIterations = 2;
    for(int i = 0; i < 1001; ++i){
        std::cout << "Epoch " << i << std::endl;
        X.setValue(trainData.block((i*batchSize) % trainData.rows(), 0, batchSize, 28*28));
        y.setValue(trainLabels.block((i*batchSize) % trainData.rows(), 0, batchSize, 10));
        NumGrind::solvers::gradientDescent(settings, 0.025, gm.funcFromNode(&err), gm.gradFromNode(&err), vars);
        if(i%50 == 0){
            X.setValue(testData);
            output.node()->forwardPass(vars);
            auto res = f2.value();
            const auto colwiseMax = argmaxRowwise(res);
            int nErr = 0;
            for(int j = 0; j < colwiseMax.rows(); ++j){
                if(colwiseMax[j] != testLabelsPure[j])
                    nErr += 1;
            }
            float fErr = (float)nErr/testLabelsPure.rows();
            std::cout
                      << "Test error " << fErr << ", "
                      << "acc " << (1.0 - fErr) * 100 << "%, "
                      << "n errors " << (float)nErr << " "
                      << std::endl;
        }
    }
//    std::cout << trainLabelsPure << std::endl;
//    std::cout << W1.value() << std::endl;
//    std::cout << b1.value() << std::endl;
}

int main() {
//    logisticRegressionOperatorAndExample02();
//    mlpOperatorOrExample01();
//    mlpOperatorOrExample02();
//    mlpOperatorOrAndExample03();
    mnistTest01();
    return 0;
}

<|endoftext|>