<commit_before>#ifdef COMPONENT_LEXER_H
// do not include this file directly.
// use lexer.h instead.

/*********************************
* Implementation: Class Token   **
*********************************/

// constructors
Token::Token(String val, tokenType t, tokenType st, bufferIndex ln, bufferIndex in) {
	this->_value = val;
	this->_type = t;
	this->_subtype = st;
	this->_line = ln;
	this->_indent = in;
}
Token::Token(const Token& t) {
	this->_value = t._value;
	this->_type = t._type;
	this->_subtype = t._subtype;
	this->_line = t._line;
	this->_indent = t._indent;
}
Token Token::operator= (const Token& t) {
	this->_value = t._value;
	this->_type = t._type;
	this->_subtype = t._subtype;
	this->_line = t._line;
	this->_indent = t._indent;
	return *this;
}
// properties
tokenType Token::type() const { return this->_type; }
tokenType Token::subtype() const { return this->_subtype; }
bufferIndex Token::lineNumber() const { return this->_line; }
bufferIndex Token::indent() const { return this->_indent; }
String Token::value() const { return this->_value; }

// mutators
bool Token::setType(tokenType t) { this->_type = t; }
bool Token::setSubtype(tokenType st) { this->_subtype = st; }
bool Token::setLineNumber(bufferIndex ln) { this->_line = ln; }
bool Token::setIndent(bufferIndex in) { this->_indent = in; }
bool Token::setValue(String s) { this->_value = s; }
// end implementation: class Token

/****************************************
* Implementation: Class Lexer   **
****************************************/

// constructors, and dynamic data managers.
Lexer::Lexer (String data) {
	this->source.open(data.c_str());
	this->line = 1;
	this->indent = 0;
}
Lexer::~Lexer() {
	if (this->source) this->source.close();
	errors.clear();
	innerBuffer.clear();
}

/*** static members ***/

bool Lexer::isValidIdentifier(String val) {
	if (val.length() > MAX_ID_LENGTH) return false;
	if (!isalpha(val[0]) && val[0] != '_') return false;
	for (__SIZETYPE i = 0; i < val.length(); i++) if (!isalnum(val[i]) && val[i] != '_') return false;
	return true;
}
// maps a keyword to a corresponding operator.
// possible only if the keyword can be replaced by the operator in the code,
// without altering the flow of logic.
String Lexer::entityMap(String val) {
	if (val == "and") return "&&";
	if (val == "or") return "||";
	if (val == "not") return "!";
	if (val == "equals") return "==";
	return val;
}

// Converts a string into a token,
// assumes string to be somewhat valid.
Token Lexer::toToken(String val) {
	if (!val) return nullToken;
	if (val[0] == -1) return nullToken;

	val = entityMap(val);
	// string literal:
	if (val[0] == '\"' || val[0] == '\'') {
		return Token(val, LITERAL, STRING);
	}
	// numeric literal
	if (val[0] >= '0' && val[0] <= '9') {
		return Token(val, LITERAL, NUMBER);
	}
	// punctuator
	if (Punctuators.indexOf(val) >= 0) {
		return Token(val, PUNCTUATOR);
	}

	// keywords
	if (Keywords.indexOf(val) >= 0) {
		if (Constants.indexOf(val) >= 0) {
			if (val == "true" || val == "false") return Token(val, LITERAL, BOOLEAN);
			return Token(val, KEYWORD, CONSTANT);
		}

		return Token(val, KEYWORD);
	}

	// inbuilt functions
	if (InbuiltFunctions.indexOf(val) >= 0) return Token(val, IDENTIFIER, FUNCTION);

	// operators. assumes that the operator has been extracted properly.
	if (binaryOperators.indexOf(val) >= 0) {
		return Token(val, OPERATOR, BINARYOP);
	}
	if (unaryOperators.indexOf(val) >= 0) {
		return Token(val, OPERATOR, UNARYOP);
	}

	// identifier
	if (isValidIdentifier(val)) {
		return Token(val, IDENTIFIER);
	}

	return Token(val);
}

/*** Member functions: actual lexing procedures. ***/
// removes all leading spaces, and discard comments.
int Lexer::trim() {
	if (this->source.eof()) return -1;

	int sp = 0;
	while (this->source.peek() == ' ') {
		this->source.get();
		sp++;
	}
	if (this->source.peek() == '#') {
		while (this->source.get() != '\n' && !this->source.eof()) // ignore the rest of the line.
		this->endLine();
		return this->trim();
	}
	if (this->source.eof()) return -1;
	return sp;
}

// Increases the line number, and sets up the next line
// extracts the tabs from next line, sets the indent, and returns the number.
// assumes that the \n is already read from the buffer.
int Lexer::endLine() {
	this->innerBuffer.pushback(newlineToken);
	if (this->source.eof()) return -1;
	this->line++;
	// extract the indentation.
	int num = 0;
	while (this->source.peek() == '\t') {
		this->source.get();
		num++;
	}
	this->indent = num;
	return (num);
}

// extracts a string: as '...' or "..."
String Lexer::readString() {
	char st = this->source.get(),
		 tmp = 0;
	String ret = st;
	while (tmp != st) {
		tmp = this->source.get();
		if (tmp == '\n') {
			// error. string not terminated properly.
			this->errors.pushback(Error("l1", "", this->line));
			this->endLine();
			// return a null string.
			return "";
		}

		ret += tmp;
		if (tmp == '\\') {
			// escape: get the next character.
			tmp = this->source.get();
			if (tmp != '\n') ret += tmp;
			else this->endLine();
		}
	}
	return ret;
}

// reads a numeric value: can contain utmost one decimal point.
String Lexer::readNumber() {
	String num;
	bool isDeci = false;
	char ch = this->source.get();
	while ((ch >= '0' && ch <= '9') || ch == '.') {
		if (ch == '.') {
			if (!isDeci) {
				isDeci = true;
			} else {
				// error- too many decimal points
				this->errors.pushback(Error("l2", "", this->line));
				return "";
			}
		}
		num += ch;
		ch = this->source.get();
	}
	if (ch == '\n') {
		this->endLine();
	} else {
		if (!this->source.eof()) this->source.putback(ch);
	}
	return num;
}

// reads an identifier/keyword,
// assuming the starting character in the buffer is a alpha or underscore.
// does `not` check whether it is valid.
String Lexer::readIdentifier() {
	String ret;
	int len = 0;
	char ch = this->source.get();
	while (isalnum(ch) || ch == '_') {
		ret += ch;
		len++;
		ch = this->source.get();
	}
	if (!this->source.eof()) this->source.putback(ch);
	return ret;
}

// reads an operator, without touching any adjacent characters.
// this does not do a full check for all operators.
// note: some operators are 'decided' by the parser, because they depend on situation.
String Lexer::readOperator() {
	char ch = this->source.peek();
	if (Opstarts.indexOf(ch) == -1) return "";

	this->source.get();
	String ret = ch;

	// check whether can be followed by =
	static const idList eq(strsplit("+-*/%=!<>"));
	if (eq.indexOf(ch) >= 0 && this->source.peek() == '=') {
		ret += (this->source.get());
		// a second =
		if ((ch == '=' || ch == '!') && (this->source.peek() == '=')) {
			ret += this->source.get();
		}
	} else if (ch == '+' || ch == '-' || ch == '&' || ch == '|') { // operators ++ -- && ||
		if (this->source.peek() == ch) ret += (this->source.get());
	}

	return ret;
}

Token Lexer::getToken() {
	// check for a previously buffered token.
	if (!this->innerBuffer.empty()) {
		Token tmp;
		this->innerBuffer.popfront(tmp);
		return tmp;
	}

	this->trim();
	char ch = this->source.peek();
	if (this->source.eof()) return eofToken;

	String val;
	bufferIndex tline = this->line, tindent = this->indent;

	if (ch == '\n') {
		this->source.get();
		this->endLine();
		return this->getToken();
	}

	if (ch == '\'' || ch == '\"') {
		val = this->readString(); // string literal
	} else if (isalpha(ch) || ch == '_') {
		val = this->readIdentifier(); // identifier/keyword
	} else if (isdigit(ch)) {
		val = this->readNumber(); // numeric constant
	} else if (Punctuators.indexOf(ch) >= 0) {
		val = ch; // punctuator. keep it as it is.";
		this->source.get();
	} else if (Opstarts.indexOf(ch) >= 0) {
		val = this->readOperator();
	} else { // just ignore the character, as of now. This should flag an unknown character error.
		val = ch;
		this->source.get();
	}

	Token tok = toToken(val);
	tok.setLineNumber(tline);
	tok.setIndent(tindent);

	this->innerBuffer.pushback(tok);
	this->innerBuffer.popfront(tok);
	return tok;
}

bool Lexer::putbackToken(Token a) { this->innerBuffer.pushfront(a); return true; }

// extracts a single statement, from the current state of the lexer.
// Considers `newline` as the delimiter, unless found in paranthesis.
// returns a balanced expression.

Infix Lexer::getTokensTill(String delim) {
	Infix ret;
	Token tmp;
	while (!this->ended()) {
		tmp = this->getToken();
		if (tmp.type() == DIRECTIVE && tmp.value() == "@eof") return ret;
		if (tmp.value() == delim) return ret;
	}
}

Vector<Error> Lexer::getErrors() const { return this->errors; }

bool Lexer::ended() {
	return (this->source && this->source.eof() && this->innerBuffer.empty());
}

bool importLexerData() {
	Keywords = strsplit("var let typeof String Number Boolean Array and or not equals delete", ' ');
	InbuiltFunctions = strsplit("print input readNumber readString readLine get", ' ');
	Constants = strsplit("null infinity true false", ' ');
	Keywords.append(Constants);
	Punctuators = strsplit("()[]{},:;");
	// operators.
	binaryOperators = strsplit("+ += - -= * *= / /= % %= = == === != !== > >= < <= && || ? . []", ' ');
	unaryOperators = strsplit("! ++ --", ' ');
	Opstarts = strsplit("+-*/%=?&|<>!.");
	return true;
}

#endif
<commit_msg>add unable to open file to lexer error list<commit_after>#ifdef COMPONENT_LEXER_H
// do not include this file directly.
// use lexer.h instead.

/*********************************
* Implementation: Class Token   **
*********************************/

// constructors
Token::Token(String val, tokenType t, tokenType st, bufferIndex ln, bufferIndex in) {
	this->_value = val;
	this->_type = t;
	this->_subtype = st;
	this->_line = ln;
	this->_indent = in;
}
Token::Token(const Token& t) {
	this->_value = t._value;
	this->_type = t._type;
	this->_subtype = t._subtype;
	this->_line = t._line;
	this->_indent = t._indent;
}
Token Token::operator= (const Token& t) {
	this->_value = t._value;
	this->_type = t._type;
	this->_subtype = t._subtype;
	this->_line = t._line;
	this->_indent = t._indent;
	return *this;
}
// properties
tokenType Token::type() const { return this->_type; }
tokenType Token::subtype() const { return this->_subtype; }
bufferIndex Token::lineNumber() const { return this->_line; }
bufferIndex Token::indent() const { return this->_indent; }
String Token::value() const { return this->_value; }

// mutators
bool Token::setType(tokenType t) { this->_type = t; }
bool Token::setSubtype(tokenType st) { this->_subtype = st; }
bool Token::setLineNumber(bufferIndex ln) { this->_line = ln; }
bool Token::setIndent(bufferIndex in) { this->_indent = in; }
bool Token::setValue(String s) { this->_value = s; }
// end implementation: class Token

/****************************************
* Implementation: Class Lexer   **
****************************************/

// constructors, and dynamic data managers.
Lexer::Lexer (String data) {
	this->source.open(data.c_str());
	if (!this->source) this->errors.pushback(Error("l0", data));
	this->line = 1;
	this->indent = 0;
}
Lexer::~Lexer() {
	if (this->source) this->source.close();
	errors.clear();
	innerBuffer.clear();
}

/*** static members ***/

bool Lexer::isValidIdentifier(String val) {
	if (val.length() > MAX_ID_LENGTH) return false;
	if (!isalpha(val[0]) && val[0] != '_') return false;
	for (__SIZETYPE i = 0; i < val.length(); i++) if (!isalnum(val[i]) && val[i] != '_') return false;
	return true;
}
// maps a keyword to a corresponding operator.
// possible only if the keyword can be replaced by the operator in the code,
// without altering the flow of logic.
String Lexer::entityMap(String val) {
	if (val == "and") return "&&";
	if (val == "or") return "||";
	if (val == "not") return "!";
	if (val == "equals") return "==";
	return val;
}

// Converts a string into a token,
// assumes string to be somewhat valid.
Token Lexer::toToken(String val) {
	if (!val) return nullToken;
	if (val[0] == -1) return nullToken;

	val = entityMap(val);
	// string literal:
	if (val[0] == '\"' || val[0] == '\'') {
		return Token(val, LITERAL, STRING);
	}
	// numeric literal
	if (val[0] >= '0' && val[0] <= '9') {
		return Token(val, LITERAL, NUMBER);
	}
	// punctuator
	if (Punctuators.indexOf(val) >= 0) {
		return Token(val, PUNCTUATOR);
	}

	// keywords
	if (Keywords.indexOf(val) >= 0) {
		if (Constants.indexOf(val) >= 0) {
			if (val == "true" || val == "false") return Token(val, LITERAL, BOOLEAN);
			return Token(val, KEYWORD, CONSTANT);
		}

		return Token(val, KEYWORD);
	}

	// inbuilt functions
	if (InbuiltFunctions.indexOf(val) >= 0) return Token(val, IDENTIFIER, FUNCTION);

	// operators. assumes that the operator has been extracted properly.
	if (binaryOperators.indexOf(val) >= 0) {
		return Token(val, OPERATOR, BINARYOP);
	}
	if (unaryOperators.indexOf(val) >= 0) {
		return Token(val, OPERATOR, UNARYOP);
	}

	// identifier
	if (isValidIdentifier(val)) {
		return Token(val, IDENTIFIER);
	}

	return Token(val);
}

/*** Member functions: actual lexing procedures. ***/
// removes all leading spaces, and discard comments.
int Lexer::trim() {
	if (this->source.eof()) return -1;

	int sp = 0;
	while (this->source.peek() == ' ') {
		this->source.get();
		sp++;
	}
	if (this->source.peek() == '#') {
		while (this->source.get() != '\n' && !this->source.eof()) // ignore the rest of the line.
		this->endLine();
		return this->trim();
	}
	if (this->source.eof()) return -1;
	return sp;
}

// Increases the line number, and sets up the next line
// extracts the tabs from next line, sets the indent, and returns the number.
// assumes that the \n is already read from the buffer.
int Lexer::endLine() {
	this->innerBuffer.pushback(newlineToken);
	if (this->source.eof()) return -1;
	this->line++;
	// extract the indentation.
	int num = 0;
	while (this->source.peek() == '\t') {
		this->source.get();
		num++;
	}
	this->indent = num;
	return (num);
}

// extracts a string: as '...' or "..."
String Lexer::readString() {
	char st = this->source.get(),
		 tmp = 0;
	String ret = st;
	while (tmp != st) {
		tmp = this->source.get();
		if (tmp == '\n') {
			// error. string not terminated properly.
			this->errors.pushback(Error("l1", "", this->line));
			this->endLine();
			// return a null string.
			return "";
		}

		ret += tmp;
		if (tmp == '\\') {
			// escape: get the next character.
			tmp = this->source.get();
			if (tmp != '\n') ret += tmp;
			else this->endLine();
		}
	}
	return ret;
}

// reads a numeric value: can contain utmost one decimal point.
String Lexer::readNumber() {
	String num;
	bool isDeci = false;
	char ch = this->source.get();
	while ((ch >= '0' && ch <= '9') || ch == '.') {
		if (ch == '.') {
			if (!isDeci) {
				isDeci = true;
			} else {
				// error- too many decimal points
				this->errors.pushback(Error("l2", "", this->line));
				return "";
			}
		}
		num += ch;
		ch = this->source.get();
	}
	if (ch == '\n') {
		this->endLine();
	} else {
		if (!this->source.eof()) this->source.putback(ch);
	}
	return num;
}

// reads an identifier/keyword,
// assuming the starting character in the buffer is a alpha or underscore.
// does `not` check whether it is valid.
String Lexer::readIdentifier() {
	String ret;
	int len = 0;
	char ch = this->source.get();
	while (isalnum(ch) || ch == '_') {
		ret += ch;
		len++;
		ch = this->source.get();
	}
	if (!this->source.eof()) this->source.putback(ch);
	return ret;
}

// reads an operator, without touching any adjacent characters.
// this does not do a full check for all operators.
// note: some operators are 'decided' by the parser, because they depend on situation.
String Lexer::readOperator() {
	char ch = this->source.peek();
	if (Opstarts.indexOf(ch) == -1) return "";

	this->source.get();
	String ret = ch;

	// check whether can be followed by =
	static const idList eq(strsplit("+-*/%=!<>"));
	if (eq.indexOf(ch) >= 0 && this->source.peek() == '=') {
		ret += (this->source.get());
		// a second =
		if ((ch == '=' || ch == '!') && (this->source.peek() == '=')) {
			ret += this->source.get();
		}
	} else if (ch == '+' || ch == '-' || ch == '&' || ch == '|') { // operators ++ -- && ||
		if (this->source.peek() == ch) ret += (this->source.get());
	}

	return ret;
}

Token Lexer::getToken() {
	// check for a previously buffered token.
	if (!this->innerBuffer.empty()) {
		Token tmp;
		this->innerBuffer.popfront(tmp);
		return tmp;
	}

	this->trim();
	char ch = this->source.peek();
	if (this->source.eof()) return eofToken;

	String val;
	bufferIndex tline = this->line, tindent = this->indent;

	if (ch == '\n') {
		this->source.get();
		this->endLine();
		return this->getToken();
	}

	if (ch == '\'' || ch == '\"') {
		val = this->readString(); // string literal
	} else if (isalpha(ch) || ch == '_') {
		val = this->readIdentifier(); // identifier/keyword
	} else if (isdigit(ch)) {
		val = this->readNumber(); // numeric constant
	} else if (Punctuators.indexOf(ch) >= 0) {
		val = ch; // punctuator. keep it as it is.";
		this->source.get();
	} else if (Opstarts.indexOf(ch) >= 0) {
		val = this->readOperator();
	} else { // just ignore the character, as of now. This should flag an unknown character error.
		val = ch;
		this->source.get();
	}

	Token tok = toToken(val);
	tok.setLineNumber(tline);
	tok.setIndent(tindent);

	this->innerBuffer.pushback(tok);
	this->innerBuffer.popfront(tok);
	return tok;
}

bool Lexer::putbackToken(Token a) { this->innerBuffer.pushfront(a); return true; }

// extracts a single statement, from the current state of the lexer.
// Considers `newline` as the delimiter, unless found in paranthesis.
// returns a balanced expression.

Infix Lexer::getTokensTill(String delim) {
	Infix ret;
	Token tmp;
	while (!this->ended()) {
		tmp = this->getToken();
		if (tmp.type() == DIRECTIVE && tmp.value() == "@eof") return ret;
		if (tmp.value() == delim) return ret;
	}
}

Vector<Error> Lexer::getErrors() const { return this->errors; }

bool Lexer::ended() {
	return (this->source && this->source.eof() && this->innerBuffer.empty());
}

bool importLexerData() {
	Keywords = strsplit("var let typeof String Number Boolean Array and or not equals delete", ' ');
	InbuiltFunctions = strsplit("print input readNumber readString readLine get", ' ');
	Constants = strsplit("null infinity true false", ' ');
	Keywords.append(Constants);
	Punctuators = strsplit("()[]{},:;");
	// operators.
	binaryOperators = strsplit("+ += - -= * *= / /= % %= = == === != !== > >= < <= && || ? . []", ' ');
	unaryOperators = strsplit("! ++ --", ' ');
	Opstarts = strsplit("+-*/%=?&|<>!.");
	return true;
}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2009-2014 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 __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__
#define __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__

#include <exception>
#include <iostream>
#include <string>

#include "base/callback.hh"
#include "mem/protocol/AccessPermission.hh"
#include "mem/ruby/common/Address.hh"
#include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/common/DataBlock.hh"
#include "mem/ruby/common/Histogram.hh"
#include "mem/ruby/common/MachineID.hh"
#include "mem/ruby/network/MessageBuffer.hh"
#include "mem/ruby/network/Network.hh"
#include "mem/ruby/system/CacheRecorder.hh"
#include "mem/packet.hh"
#include "mem/qport.hh"
#include "params/RubyController.hh"
#include "mem/mem_object.hh"

class Network;

// used to communicate that an in_port peeked the wrong message type
class RejectException: public std::exception
{
    virtual const char* what() const throw()
    { return "Port rejected message based on type"; }
};

class AbstractController : public MemObject, public Consumer
{
  public:
    typedef RubyControllerParams Params;
    AbstractController(const Params *p);
    void init();
    const Params *params() const { return (const Params *)_params; }

    const NodeID getVersion() const { return m_machineID.getNum(); }
    const MachineType getType() const { return m_machineID.getType(); }

    void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }

    // return instance name
    void blockOnQueue(Addr, MessageBuffer*);
    void unblock(Addr);

    virtual MessageBuffer* getMandatoryQueue() const = 0;
    virtual MessageBuffer* getMemoryQueue() const = 0;
    virtual AccessPermission getAccessPermission(const Addr &addr) = 0;

    virtual void print(std::ostream & out) const = 0;
    virtual void wakeup() = 0;
    virtual void resetStats() = 0;
    virtual void regStats();

    virtual void recordCacheTrace(int cntrl, CacheRecorder* tr) = 0;
    virtual Sequencer* getSequencer() const = 0;

    //! These functions are used by ruby system to read/write the data blocks
    //! that exist with in the controller.
    virtual void functionalRead(const Addr &addr, PacketPtr) = 0;
    void functionalMemoryRead(PacketPtr);
    //! The return value indicates the number of messages written with the
    //! data from the packet.
    virtual int functionalWriteBuffers(PacketPtr&) = 0;
    virtual int functionalWrite(const Addr &addr, PacketPtr) = 0;
    int functionalMemoryWrite(PacketPtr);

    //! Function for enqueuing a prefetch request
    virtual void enqueuePrefetch(const Addr &, const RubyRequestType&)
    { fatal("Prefetches not implemented!");}

    //! Function for collating statistics from all the controllers of this
    //! particular type. This function should only be called from the
    //! version 0 of this controller type.
    virtual void collateStats()
    {fatal("collateStats() should be overridden!");}

    //! Initialize the message buffers.
    virtual void initNetQueues() = 0;

    /** A function used to return the port associated with this bus object. */
    BaseMasterPort& getMasterPort(const std::string& if_name,
                                  PortID idx = InvalidPortID);

    void queueMemoryRead(const MachineID &id, Addr addr, Cycles latency);
    void queueMemoryWrite(const MachineID &id, Addr addr, Cycles latency,
                          const DataBlock &block);
    void queueMemoryWritePartial(const MachineID &id, Addr addr, Cycles latency,
                                 const DataBlock &block, int size);
    void recvTimingResp(PacketPtr pkt);

  public:
    MachineID getMachineID() const { return m_machineID; }

    Stats::Histogram& getDelayHist() { return m_delayHistogram; }
    Stats::Histogram& getDelayVCHist(uint32_t index)
    { return *(m_delayVCHistogram[index]); }

  protected:
    //! Profiles original cache requests including PUTs
    void profileRequest(const std::string &request);
    //! Profiles the delay associated with messages.
    void profileMsgDelay(uint32_t virtualNetwork, Cycles delay);

    void stallBuffer(MessageBuffer* buf, Addr addr);
    void wakeUpBuffers(Addr addr);
    void wakeUpAllBuffers(Addr addr);
    void wakeUpAllBuffers();

  protected:
    NodeID m_version;
    MachineID m_machineID;
    NodeID m_clusterID;

    // MasterID used by some components of gem5.
    MasterID m_masterId;

    Network* m_net_ptr;
    bool m_is_blocking;
    std::map<Addr, MessageBuffer*> m_block_map;

    typedef std::vector<MessageBuffer*> MsgVecType;
    typedef std::set<MessageBuffer*> MsgBufType;
    typedef std::map<Addr, MsgVecType* > WaitingBufType;
    WaitingBufType m_waiting_buffers;

    unsigned int m_in_ports;
    unsigned int m_cur_in_port;
    int m_number_of_TBEs;
    int m_transitions_per_cycle;
    unsigned int m_buffer_size;
    Cycles m_recycle_latency;

    //! Counter for the number of cycles when the transitions carried out
    //! were equal to the maximum allowed
    Stats::Scalar m_fully_busy_cycles;

    //! Histogram for profiling delay for the messages this controller
    //! cares for
    Stats::Histogram m_delayHistogram;
    std::vector<Stats::Histogram *> m_delayVCHistogram;

    //! Callback class used for collating statistics from all the
    //! controller of this type.
    class StatsCallback : public Callback
    {
      private:
        AbstractController *ctr;

      public:
        virtual ~StatsCallback() {}
        StatsCallback(AbstractController *_ctr) : ctr(_ctr) {}
        void process() {ctr->collateStats();}
    };

    /**
     * Port that forwards requests and receives responses from the
     * memory controller.  It has a queue of packets not yet sent.
     */
    class MemoryPort : public QueuedMasterPort
    {
      private:
        // Packet queues used to store outgoing requests and snoop responses.
        ReqPacketQueue reqQueue;
        SnoopRespPacketQueue snoopRespQueue;

        // Controller that operates this port.
        AbstractController *controller;

      public:
        MemoryPort(const std::string &_name, AbstractController *_controller,
                   const std::string &_label);

        // Function for receiving a timing response from the peer port.
        // Currently the pkt is handed to the coherence controller
        // associated with this port.
        bool recvTimingResp(PacketPtr pkt);
    };

    /* Master port to the memory controller. */
    MemoryPort memoryPort;

    // State that is stored in packets sent to the memory controller.
    struct SenderState : public Packet::SenderState
    {
        // Id of the machine from which the request originated.
        MachineID id;

        SenderState(MachineID _id) : id(_id)
        {}
    };
};

#endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__
<commit_msg>ruby: abstract controller: mark some variables as const<commit_after>/*
 * Copyright (c) 2009-2014 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 __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__
#define __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__

#include <exception>
#include <iostream>
#include <string>

#include "base/callback.hh"
#include "mem/protocol/AccessPermission.hh"
#include "mem/ruby/common/Address.hh"
#include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/common/DataBlock.hh"
#include "mem/ruby/common/Histogram.hh"
#include "mem/ruby/common/MachineID.hh"
#include "mem/ruby/network/MessageBuffer.hh"
#include "mem/ruby/network/Network.hh"
#include "mem/ruby/system/CacheRecorder.hh"
#include "mem/packet.hh"
#include "mem/qport.hh"
#include "params/RubyController.hh"
#include "mem/mem_object.hh"

class Network;

// used to communicate that an in_port peeked the wrong message type
class RejectException: public std::exception
{
    virtual const char* what() const throw()
    { return "Port rejected message based on type"; }
};

class AbstractController : public MemObject, public Consumer
{
  public:
    typedef RubyControllerParams Params;
    AbstractController(const Params *p);
    void init();
    const Params *params() const { return (const Params *)_params; }

    const NodeID getVersion() const { return m_machineID.getNum(); }
    const MachineType getType() const { return m_machineID.getType(); }

    void initNetworkPtr(Network* net_ptr) { m_net_ptr = net_ptr; }

    // return instance name
    void blockOnQueue(Addr, MessageBuffer*);
    void unblock(Addr);

    virtual MessageBuffer* getMandatoryQueue() const = 0;
    virtual MessageBuffer* getMemoryQueue() const = 0;
    virtual AccessPermission getAccessPermission(const Addr &addr) = 0;

    virtual void print(std::ostream & out) const = 0;
    virtual void wakeup() = 0;
    virtual void resetStats() = 0;
    virtual void regStats();

    virtual void recordCacheTrace(int cntrl, CacheRecorder* tr) = 0;
    virtual Sequencer* getSequencer() const = 0;

    //! These functions are used by ruby system to read/write the data blocks
    //! that exist with in the controller.
    virtual void functionalRead(const Addr &addr, PacketPtr) = 0;
    void functionalMemoryRead(PacketPtr);
    //! The return value indicates the number of messages written with the
    //! data from the packet.
    virtual int functionalWriteBuffers(PacketPtr&) = 0;
    virtual int functionalWrite(const Addr &addr, PacketPtr) = 0;
    int functionalMemoryWrite(PacketPtr);

    //! Function for enqueuing a prefetch request
    virtual void enqueuePrefetch(const Addr &, const RubyRequestType&)
    { fatal("Prefetches not implemented!");}

    //! Function for collating statistics from all the controllers of this
    //! particular type. This function should only be called from the
    //! version 0 of this controller type.
    virtual void collateStats()
    {fatal("collateStats() should be overridden!");}

    //! Initialize the message buffers.
    virtual void initNetQueues() = 0;

    /** A function used to return the port associated with this bus object. */
    BaseMasterPort& getMasterPort(const std::string& if_name,
                                  PortID idx = InvalidPortID);

    void queueMemoryRead(const MachineID &id, Addr addr, Cycles latency);
    void queueMemoryWrite(const MachineID &id, Addr addr, Cycles latency,
                          const DataBlock &block);
    void queueMemoryWritePartial(const MachineID &id, Addr addr, Cycles latency,
                                 const DataBlock &block, int size);
    void recvTimingResp(PacketPtr pkt);

  public:
    MachineID getMachineID() const { return m_machineID; }

    Stats::Histogram& getDelayHist() { return m_delayHistogram; }
    Stats::Histogram& getDelayVCHist(uint32_t index)
    { return *(m_delayVCHistogram[index]); }

  protected:
    //! Profiles original cache requests including PUTs
    void profileRequest(const std::string &request);
    //! Profiles the delay associated with messages.
    void profileMsgDelay(uint32_t virtualNetwork, Cycles delay);

    void stallBuffer(MessageBuffer* buf, Addr addr);
    void wakeUpBuffers(Addr addr);
    void wakeUpAllBuffers(Addr addr);
    void wakeUpAllBuffers();

  protected:
    const NodeID m_version;
    MachineID m_machineID;
    const NodeID m_clusterID;

    // MasterID used by some components of gem5.
    const MasterID m_masterId;

    Network *m_net_ptr;
    bool m_is_blocking;
    std::map<Addr, MessageBuffer*> m_block_map;

    typedef std::vector<MessageBuffer*> MsgVecType;
    typedef std::set<MessageBuffer*> MsgBufType;
    typedef std::map<Addr, MsgVecType* > WaitingBufType;
    WaitingBufType m_waiting_buffers;

    unsigned int m_in_ports;
    unsigned int m_cur_in_port;
    const int m_number_of_TBEs;
    const int m_transitions_per_cycle;
    const unsigned int m_buffer_size;
    Cycles m_recycle_latency;

    //! Counter for the number of cycles when the transitions carried out
    //! were equal to the maximum allowed
    Stats::Scalar m_fully_busy_cycles;

    //! Histogram for profiling delay for the messages this controller
    //! cares for
    Stats::Histogram m_delayHistogram;
    std::vector<Stats::Histogram *> m_delayVCHistogram;

    //! Callback class used for collating statistics from all the
    //! controller of this type.
    class StatsCallback : public Callback
    {
      private:
        AbstractController *ctr;

      public:
        virtual ~StatsCallback() {}
        StatsCallback(AbstractController *_ctr) : ctr(_ctr) {}
        void process() {ctr->collateStats();}
    };

    /**
     * Port that forwards requests and receives responses from the
     * memory controller.  It has a queue of packets not yet sent.
     */
    class MemoryPort : public QueuedMasterPort
    {
      private:
        // Packet queues used to store outgoing requests and snoop responses.
        ReqPacketQueue reqQueue;
        SnoopRespPacketQueue snoopRespQueue;

        // Controller that operates this port.
        AbstractController *controller;

      public:
        MemoryPort(const std::string &_name, AbstractController *_controller,
                   const std::string &_label);

        // Function for receiving a timing response from the peer port.
        // Currently the pkt is handed to the coherence controller
        // associated with this port.
        bool recvTimingResp(PacketPtr pkt);
    };

    /* Master port to the memory controller. */
    MemoryPort memoryPort;

    // State that is stored in packets sent to the memory controller.
    struct SenderState : public Packet::SenderState
    {
        // Id of the machine from which the request originated.
        MachineID id;

        SenderState(MachineID _id) : id(_id)
        {}
    };
};

#endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Implements the particle generator
 * @remark Based on code from John Idarraga
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied
 * verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities
 * granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "GeneratorActionG4.hpp"

#include <limits>
#include <memory>

#include <G4Event.hh>
#include <G4GeneralParticleSource.hh>
#include <G4ParticleDefinition.hh>
#include <G4ParticleTable.hh>
#include <array>

#include "core/config/exceptions.h"
#include "core/utils/log.h"
#include "tools/geant4.h"

using namespace allpix;

GeneratorActionG4::GeneratorActionG4(const Configuration& config)
    : particle_source_(std::make_unique<G4GeneralParticleSource>()) {
    // Set verbosity of source to off
    particle_source_->SetVerbosity(0);

    // Get source specific parameters
    auto single_source = particle_source_->GetCurrentSource();
    auto source_type = config.get<std::string>("beam_source_type", "");

    // Find Geant4 particle
    auto pdg_table = G4ParticleTable::GetParticleTable();
    auto particle_type = config.get<std::string>("particle_type", "");
    std::transform(particle_type.begin(), particle_type.end(), particle_type.begin(), ::tolower);
    auto particle_code = config.get<int>("particle_code", 0);
    G4ParticleDefinition* particle = nullptr;

    if(source_type.empty() && !particle_type.empty() && particle_code != 0) {
        // if(!particle_type.empty() && particle_code != 0) {
        if(pdg_table->FindParticle(particle_type) == pdg_table->FindParticle(particle_code)) {
            LOG(WARNING) << "particle_type and particle_code given. Continuing because t    hey match.";
            particle = pdg_table->FindParticle(particle_code);
            if(particle == nullptr) {
                throw InvalidValueError(config, "particle_code", "particle code does not exist.");
            }
        } else {
            throw InvalidValueError(
                config, "particle_type", "Given particle_type does not match particle_code. Please remove one of them.");
        }
    } else if(source_type.empty() && particle_type.empty() && particle_code == 0) {
        throw InvalidValueError(config, "particle_code", "Please set particle_code or particle_type.");
    } else if(source_type.empty() && particle_code != 0) {
        particle = pdg_table->FindParticle(particle_code);
        if(particle == nullptr) {
            throw InvalidValueError(config, "particle_code", "particle code does not exist.");
        }
    } else if(source_type.empty() && !particle_type.empty()) {
        particle = pdg_table->FindParticle(particle_type);
        if(particle == nullptr) {
            throw InvalidValueError(config, "particle_type", "particle type does not exist.");
        }
    } else {
        if(source_type.empty()) {
            throw InvalidValueError(config, "source_type", "Please set source type.");
        }
    }

    LOG(DEBUG) << "Using particle " << particle->GetParticleName() << " (ID " << particle->GetPDGEncoding() << ").";

    // Set global parameters of the source
    if(!particle_type.empty() || particle_code != 0) {
        single_source->SetNumberOfParticles(1);
        single_source->SetParticleDefinition(particle);
        // Set the primary track's start time in for the current event to zero:
        single_source->SetParticleTime(0.0);
    }

    // Set position parameters
    single_source->GetPosDist()->SetPosDisType("Beam");
    single_source->GetPosDist()->SetBeamSigmaInR(config.get<double>("beam_size", 0));
    single_source->GetPosDist()->SetCentreCoords(config.get<G4ThreeVector>("beam_position"));

    // Set angle distribution parameters
    single_source->GetAngDist()->SetAngDistType("beam2d");
    single_source->GetAngDist()->DefineAngRefAxes("angref1", G4ThreeVector(-1., 0, 0));
    G4TwoVector divergence = config.get<G4TwoVector>("beam_divergence", G4TwoVector(0., 0.));
    single_source->GetAngDist()->SetBeamSigmaInAngX(divergence.x());
    single_source->GetAngDist()->SetBeamSigmaInAngY(divergence.y());
    G4ThreeVector direction = config.get<G4ThreeVector>("beam_direction");
    if(fabs(direction.mag() - 1.0) > std::numeric_limits<double>::epsilon()) {
        LOG(WARNING) << "Momentum direction is not a unit vector: magnitude is ignored";
    }
    if(!particle_type.empty() || particle_code != 0) {
        single_source->GetAngDist()->SetParticleMomentumDirection(direction);
    }

    // Set energy parameters
    auto energy_type = config.get<std::string>("beam_energy_type", "");
    if(energy_type == "User") {
        single_source->GetEneDist()->SetEnergyDisType(energy_type);
        auto beam_hist_point = config.getArray<G4ThreeVector>("beam_hist_point");
        for(auto& hist_point : beam_hist_point) {
            single_source->GetEneDist()->UserEnergyHisto(hist_point);
        }
    } else if(source_type == "Iron-55") {
        std::stringstream ss;
        ss << "gamma";
        particle_type.assign(ss.str());
        std::transform(particle_type.begin(), particle_type.end(), particle_type.begin(), ::tolower);
        particle = pdg_table->FindParticle(particle_type);
        single_source->SetNumberOfParticles(1);
        single_source->SetParticleDefinition(particle);
        single_source->SetParticleTime(0.0);
        single_source->GetAngDist()->SetParticleMomentumDirection(direction);
        single_source->GetEneDist()->SetEnergyDisType("User");
        G4ThreeVector hist_point1(0.0059, 28., 0.1), hist_point2(0.00649, 2.85, 0.1);
        std::array<G4ThreeVector, 2> beam_hist_point = {{hist_point1, hist_point2}};
        for(auto& hist_point : beam_hist_point) {
            single_source->GetEneDist()->UserEnergyHisto(hist_point);
        }
    } else {
        single_source->GetEneDist()->SetEnergyDisType("Gauss");
        single_source->GetEneDist()->SetMonoEnergy(config.get<double>("beam_energy"));
    }
    single_source->GetEneDist()->SetBeamSigmaInE(config.get<double>("beam_energy_spread", 0.));
}

/**
 * Called automatically for every event
 */
void GeneratorActionG4::GeneratePrimaries(G4Event* event) {
    particle_source_->GeneratePrimaryVertex(event);
}
<commit_msg>Add a new way to generate particles: using energy spectra with energy spread<commit_after>/**
 * @file
 * @brief Implements the particle generator
 * @remark Based on code from John Idarraga
 * @copyright Copyright (c) 2017 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied
 * verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities
 * granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "GeneratorActionG4.hpp"

#include <limits>
#include <memory>

#include <G4Event.hh>
#include <G4GeneralParticleSource.hh>
#include <G4ParticleDefinition.hh>
#include <G4ParticleTable.hh>
#include <Randomize.hh>
#include <array>

#include "core/config/exceptions.h"
#include "core/utils/log.h"
#include "tools/geant4.h"

using namespace allpix;

GeneratorActionG4::GeneratorActionG4(const Configuration& config)
    : particle_source_(std::make_unique<G4GeneralParticleSource>()) {
    // Set verbosity of source to off
    particle_source_->SetVerbosity(0);

    // Get source specific parameters
    auto single_source = particle_source_->GetCurrentSource();
    auto source_type = config.get<std::string>("beam_source_type", "");

    // Find Geant4 particle
    auto pdg_table = G4ParticleTable::GetParticleTable();
    auto particle_type = config.get<std::string>("particle_type", "");
    std::transform(particle_type.begin(), particle_type.end(), particle_type.begin(), ::tolower);
    auto particle_code = config.get<int>("particle_code", 0);
    G4ParticleDefinition* particle = nullptr;

    if(source_type.empty() && !particle_type.empty() && particle_code != 0) {
        // if(!particle_type.empty() && particle_code != 0) {
        if(pdg_table->FindParticle(particle_type) == pdg_table->FindParticle(particle_code)) {
            LOG(WARNING) << "particle_type and particle_code given. Continuing because t    hey match.";
            particle = pdg_table->FindParticle(particle_code);
            if(particle == nullptr) {
                throw InvalidValueError(config, "particle_code", "particle code does not exist.");
            }
        } else {
            throw InvalidValueError(
                config, "particle_type", "Given particle_type does not match particle_code. Please remove one of them.");
        }
    } else if(source_type.empty() && particle_type.empty() && particle_code == 0) {
        throw InvalidValueError(config, "particle_code", "Please set particle_code or particle_type.");
    } else if(source_type.empty() && particle_code != 0) {
        particle = pdg_table->FindParticle(particle_code);
        if(particle == nullptr) {
            throw InvalidValueError(config, "particle_code", "particle code does not exist.");
        }
    } else if(source_type.empty() && !particle_type.empty()) {
        particle = pdg_table->FindParticle(particle_type);
        if(particle == nullptr) {
            throw InvalidValueError(config, "particle_type", "particle type does not exist.");
        }
    } else {
        if(source_type.empty()) {
            throw InvalidValueError(config, "source_type", "Please set source type.");
        }
    }

    LOG(DEBUG) << "Using particle " << particle->GetParticleName() << " (ID " << particle->GetPDGEncoding() << ").";

    // Set global parameters of the source
    if(!particle_type.empty() || particle_code != 0) {
        single_source->SetNumberOfParticles(1);
        single_source->SetParticleDefinition(particle);
        // Set the primary track's start time in for the current event to zero:
        single_source->SetParticleTime(0.0);
    }

    // Set position parameters
    single_source->GetPosDist()->SetPosDisType("Beam");
    single_source->GetPosDist()->SetBeamSigmaInR(config.get<double>("beam_size", 0));
    single_source->GetPosDist()->SetCentreCoords(config.get<G4ThreeVector>("beam_position"));

    // Set angle distribution parameters
    single_source->GetAngDist()->SetAngDistType("beam2d");
    single_source->GetAngDist()->DefineAngRefAxes("angref1", G4ThreeVector(-1., 0, 0));
    G4TwoVector divergence = config.get<G4TwoVector>("beam_divergence", G4TwoVector(0., 0.));
    single_source->GetAngDist()->SetBeamSigmaInAngX(divergence.x());
    single_source->GetAngDist()->SetBeamSigmaInAngY(divergence.y());
    G4ThreeVector direction = config.get<G4ThreeVector>("beam_direction");
    if(fabs(direction.mag() - 1.0) > std::numeric_limits<double>::epsilon()) {
        LOG(WARNING) << "Momentum direction is not a unit vector: magnitude is ignored";
    }
    if(!particle_type.empty() || particle_code != 0) {
        single_source->GetAngDist()->SetParticleMomentumDirection(direction);
    }

    // Set energy parameters
    auto energy_type = config.get<std::string>("beam_energy_type", "");
    if(energy_type == "User") {
        single_source->GetEneDist()->SetEnergyDisType(energy_type);
        auto beam_hist_point = config.getArray<G4ThreeVector>("beam_hist_point");
        for(auto& hist_point : beam_hist_point) {
            single_source->GetEneDist()->UserEnergyHisto(hist_point);
        }
    } else if(source_type == "Iron-55") {
        std::stringstream ss;
        ss << "gamma";
        particle_type.assign(ss.str());
        std::transform(particle_type.begin(), particle_type.end(), particle_type.begin(), ::tolower);
        particle = pdg_table->FindParticle(particle_type);
        single_source->SetNumberOfParticles(1);
        single_source->SetParticleDefinition(particle);
        single_source->SetParticleTime(0.0);
        single_source->GetAngDist()->SetParticleMomentumDirection(direction);
        single_source->GetEneDist()->SetEnergyDisType("User");
        G4double energy_hist_1[10];
        G4double intensity_hist_1[10];
        for(G4int i = 0; i < 10; i++) {
            energy_hist_1[i] = 0.0059 + 0.0001 * (1 - 2 * G4UniformRand());
            intensity_hist_1[i] = 28. + 0.1 * (1 - 2 * G4UniformRand());
            single_source->GetEneDist()->UserEnergyHisto(G4ThreeVector(energy_hist_1[i], intensity_hist_1[i], 0.));
        }
        G4double energy_hist_2[10];
        G4double intensity_hist_2[10];
        for(G4int i = 0; i < 10; i++) {
            energy_hist_2[i] = 0.00649 + 0.0001 * (1 - 2 * G4UniformRand());
            intensity_hist_2[i] = 2.85 + 0.01 * (1 - 2 * G4UniformRand());
            single_source->GetEneDist()->UserEnergyHisto(G4ThreeVector(energy_hist_2[i], intensity_hist_2[i], 0.));
        }
    } else {
        single_source->GetEneDist()->SetEnergyDisType("Gauss");
        single_source->GetEneDist()->SetMonoEnergy(config.get<double>("beam_energy"));
    }
    single_source->GetEneDist()->SetBeamSigmaInE(config.get<double>("beam_energy_spread", 0.));
}

/**
 * Called automatically for every event
 */
void GeneratorActionG4::GeneratePrimaries(G4Event* event) {
    particle_source_->GeneratePrimaryVertex(event);
}
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Implements the particle generator
 * @remark Based on code from John Idarraga
 * @copyright MIT License
 */

#include "GeneratorActionG4.hpp"

#include <limits>
#include <memory>

#include <G4Event.hh>
#include <G4GeneralParticleSource.hh>
#include <G4ParticleDefinition.hh>
#include <G4ParticleTable.hh>

#include "core/config/exceptions.h"
#include "core/utils/log.h"
#include "tools/geant4.h"

using namespace allpix;

GeneratorActionG4::GeneratorActionG4(const Configuration& config)
    : particle_source_(std::make_unique<G4GeneralParticleSource>()) {
    // Set verbosity of source to off
    particle_source_->SetVerbosity(0);

    // Get source specific parameters
    auto single_source = particle_source_->GetCurrentSource();

    // Find Geant4 particle
    G4ParticleDefinition* particle =
        G4ParticleTable::GetParticleTable()->FindParticle(config.get<std::string>("particle_type"));
    if(particle == nullptr) {
        // FIXME more information about available particle
        throw InvalidValueError(config, "particle_type", "particle type does not exist");
    }

    // Set global parameters of the source
    // FIXME keep number of particles always at one?
    single_source->SetNumberOfParticles(1);
    single_source->SetParticleDefinition(particle);
    // FIXME What is this time
    single_source->SetParticleTime(0.0);

    // Set position parameters
    single_source->GetPosDist()->SetPosDisType("Beam");
    single_source->GetPosDist()->SetBeamSigmaInR(config.get<double>("particle_radius_sigma", 0));
    single_source->GetPosDist()->SetCentreCoords(config.get<G4ThreeVector>("particle_position"));

    // Set angle distribution parameters
    single_source->GetAngDist()->SetAngDistType("beam2d");
    single_source->GetAngDist()->DefineAngRefAxes("angref1", G4ThreeVector(-1., 0, 0));
    G4TwoVector divergence = config.get<G4TwoVector>("particle_divergence_xy", G4TwoVector(0., 0.));
    single_source->GetAngDist()->SetBeamSigmaInAngX(divergence.x());
    single_source->GetAngDist()->SetBeamSigmaInAngY(divergence.y());
    G4ThreeVector direction = config.get<G4ThreeVector>("particle_direction");
    if(fabs(direction.mag() - 1.0) > std::numeric_limits<double>::epsilon()) {
        LOG(WARNING) << "Momentum direction is not a unit vector: magnitude is ignored";
    }
    single_source->GetAngDist()->SetParticleMomentumDirection(direction);

    // Set energy parameters
    single_source->GetEneDist()->SetEnergyDisType("Mono");
    single_source->GetEneDist()->SetMonoEnergy(config.get<double>("particle_energy"));
}

/**
 * Called automatically for every event
 */
void GeneratorActionG4::GeneratePrimaries(G4Event* event) {
    particle_source_->GeneratePrimaryVertex(event);
}
<commit_msg>Implement energy spread. Using parameter particle_energy_spread<commit_after>/**
 * @file
 * @brief Implements the particle generator
 * @remark Based on code from John Idarraga
 * @copyright MIT License
 */

#include "GeneratorActionG4.hpp"

#include <limits>
#include <memory>

#include <G4Event.hh>
#include <G4GeneralParticleSource.hh>
#include <G4ParticleDefinition.hh>
#include <G4ParticleTable.hh>

#include "core/config/exceptions.h"
#include "core/utils/log.h"
#include "tools/geant4.h"

using namespace allpix;

GeneratorActionG4::GeneratorActionG4(const Configuration& config)
    : particle_source_(std::make_unique<G4GeneralParticleSource>()) {
    // Set verbosity of source to off
    particle_source_->SetVerbosity(0);

    // Get source specific parameters
    auto single_source = particle_source_->GetCurrentSource();

    // Find Geant4 particle
    G4ParticleDefinition* particle =
        G4ParticleTable::GetParticleTable()->FindParticle(config.get<std::string>("particle_type"));
    if(particle == nullptr) {
        // FIXME more information about available particle
        throw InvalidValueError(config, "particle_type", "particle type does not exist");
    }

    // Set global parameters of the source
    // FIXME keep number of particles always at one?
    single_source->SetNumberOfParticles(1);
    single_source->SetParticleDefinition(particle);
    // FIXME What is this time
    single_source->SetParticleTime(0.0);

    // Set position parameters
    single_source->GetPosDist()->SetPosDisType("Beam");
    single_source->GetPosDist()->SetBeamSigmaInR(config.get<double>("particle_radius_sigma", 0));
    single_source->GetPosDist()->SetCentreCoords(config.get<G4ThreeVector>("particle_position"));

    // Set angle distribution parameters
    single_source->GetAngDist()->SetAngDistType("beam2d");
    single_source->GetAngDist()->DefineAngRefAxes("angref1", G4ThreeVector(-1., 0, 0));
    G4TwoVector divergence = config.get<G4TwoVector>("particle_divergence_xy", G4TwoVector(0., 0.));
    single_source->GetAngDist()->SetBeamSigmaInAngX(divergence.x());
    single_source->GetAngDist()->SetBeamSigmaInAngY(divergence.y());
    G4ThreeVector direction = config.get<G4ThreeVector>("particle_direction");
    if(fabs(direction.mag() - 1.0) > std::numeric_limits<double>::epsilon()) {
        LOG(WARNING) << "Momentum direction is not a unit vector: magnitude is ignored";
    }
    single_source->GetAngDist()->SetParticleMomentumDirection(direction);

    // Set energy parameters
    single_source->GetEneDist()->SetEnergyDisType("Gauss");
    single_source->GetEneDist()->SetMonoEnergy(config.get<double>("particle_energy"));
    single_source->GetEneDist()->SetBeamSigmaInE(config.get<double>("particle_energy_spread", 0.));
}

/**
 * Called automatically for every event
 */
void GeneratorActionG4::GeneratePrimaries(G4Event* event) {
    particle_source_->GeneratePrimaryVertex(event);
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2010-2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

// This class
#include "grins_config.h"
#include "grins/boussinesq_buoyancy_adjoint_stab.h"

// GRINS
#include "grins/assembly_context.h"

// libMesh
#include "libmesh/getpot.h"
#include "libmesh/string_to_enum.h"
#include "libmesh/fem_system.h"
#include "libmesh/quadrature.h"

namespace GRINS
{

  BoussinesqBuoyancyAdjointStabilization::BoussinesqBuoyancyAdjointStabilization( const std::string& physics_name, const GetPot& input )
    : BoussinesqBuoyancyBase(physics_name,input),
      /* \todo Do we want to have these come from a BoussinesqBuoyancyAdjointStabilization section instead? */
      _rho( input("Physics/"+incompressible_navier_stokes+"/rho", 1.0) ),
      _mu( input("Physics/"+incompressible_navier_stokes+"/mu", 1.0) ),
      _stab_helper( input ),
      _p_var_name( input("Physics/VariableNames/pressure", p_var_name_default ) ),
      _P_FE_family( libMesh::Utility::string_to_enum<libMeshEnums::FEFamily>( input("Physics/"+incompressible_navier_stokes+"/FE_family", "LAGRANGE") ) ),
      _P_order( libMesh::Utility::string_to_enum<libMeshEnums::Order>( input("Physics/"+incompressible_navier_stokes+"/P_order", "FIRST") ) )
  {
    return;
  }

  BoussinesqBuoyancyAdjointStabilization::~BoussinesqBuoyancyAdjointStabilization()
  {
    return;
  }

  void BoussinesqBuoyancyAdjointStabilization::init_context( AssemblyContext& context )
  {
    context.get_element_fe(this->_p_var)->get_dphi();

    context.get_element_fe(this->_u_var)->get_dphi();
    context.get_element_fe(this->_u_var)->get_d2phi();

    return;
  }

  void BoussinesqBuoyancyAdjointStabilization::init_variables( libMesh::FEMSystem* system )
  {
    // First call base class
    BoussinesqBuoyancyBase::init_variables(system);

    _p_var = system->add_variable( _p_var_name, this->_P_order, _P_FE_family);

    return;
  }

  void BoussinesqBuoyancyAdjointStabilization::element_time_derivative( bool compute_jacobian,
                                                                        AssemblyContext& context,
                                                                        CachedValues& /*cache*/ )
  {
#ifdef GRINS_USE_GRVY_TIMERS
    this->_timer->BeginTimer("BoussinesqBuoyancyAdjointStabilization::element_time_derivative");
#endif

    // The number of local degrees of freedom in each variable.
    const unsigned int n_u_dofs = context.get_dof_indices(_u_var).size();
    const unsigned int n_p_dofs = context.get_dof_indices(_p_var).size();

    // Element Jacobian * quadrature weights for interior integration.
    const std::vector<libMesh::Real> &JxW =
      context.get_element_fe(_u_var)->get_JxW();

    const std::vector<std::vector<libMesh::RealGradient> >& u_gradphi =
      context.get_element_fe(this->_u_var)->get_dphi();

    const std::vector<std::vector<libMesh::RealTensor> >& u_hessphi =
      context.get_element_fe(this->_u_var)->get_d2phi();

    const std::vector<std::vector<libMesh::RealGradient> >& p_dphi =
      context.get_element_fe(this->_p_var)->get_dphi();

    // Get residuals
    libMesh::DenseSubVector<libMesh::Number> &Fu = context.get_elem_residual(_u_var); // R_{u}
    libMesh::DenseSubVector<libMesh::Number> &Fv = context.get_elem_residual(_v_var); // R_{v}
    libMesh::DenseSubVector<libMesh::Number> *Fw = NULL;
    if(this->_dim == 3)
      Fw = &context.get_elem_residual(this->_w_var); // R_{w}

    libMesh::DenseSubVector<libMesh::Number> &Fp = context.get_elem_residual(this->_p_var); // R_{p}

    // Now we will build the element Jacobian and residual.
    // Constructing the residual requires the solution and its
    // gradient from the previous timestep.  This must be
    // calculated at each quadrature point by summing the
    // solution degree-of-freedom values by the appropriate
    // weight functions.
    unsigned int n_qpoints = context.get_element_qrule().n_points();

    libMesh::FEBase* fe = context.get_element_fe(this->_u_var);

    for (unsigned int qp=0; qp != n_qpoints; qp++)
      {
        libMesh::RealGradient g = this->_stab_helper.compute_g( fe, context, qp );
	libMesh::RealTensor G = this->_stab_helper.compute_G( fe, context, qp );

	libMesh::RealGradient U( context.interior_value( this->_u_var, qp ),
				 context.interior_value( this->_v_var, qp ) );
	if( this->_dim == 3 )
          {
            U(2) = context.interior_value( this->_w_var, qp );
          }

        libMesh::Real tau_M = this->_stab_helper.compute_tau_momentum( context, qp, g, G, this->_rho, U, this->_mu, this->_is_steady );

	// Compute the solution & its gradient at the old Newton iterate.
	libMesh::Number T;
	T = context.interior_value(_T_var, qp);

        libMesh::RealGradient residual = -_rho_ref*_beta_T*(T-_T_ref)*_g;

	// First, an i-loop over the velocity degrees of freedom.
	// We know that n_u_dofs == n_v_dofs so we can compute contributions
	// for both at the same time.
        for (unsigned int i=0; i != n_p_dofs; i++)
	  {
	    Fp(i) += tau_M*residual*p_dphi[i][qp]*JxW[qp];
	  }

	for (unsigned int i=0; i != n_u_dofs; i++)
	  {
	    Fu(i) += ( this->_rho*U*u_gradphi[i][qp]
		       + this->_mu*( u_hessphi[i][qp](0,0) + u_hessphi[i][qp](1,1) + u_hessphi[i][qp](2,2) ) )*tau_M*residual(0)*JxW[qp];

	    Fv(i) += ( this->_rho*U*u_gradphi[i][qp]
		       + this->_mu*( u_hessphi[i][qp](0,0) + u_hessphi[i][qp](1,1) + u_hessphi[i][qp](2,2) ) )*tau_M*residual(1)*JxW[qp];

	    if (_dim == 3)
              {
                (*Fw)(i) += ( this->_rho*U*u_gradphi[i][qp]
                              + this->_mu*( u_hessphi[i][qp](0,0) + u_hessphi[i][qp](1,1) + u_hessphi[i][qp](2,2) ) )*tau_M*residual(2)*JxW[qp];
              }

	    if (compute_jacobian)
	      {
                libmesh_not_implemented();
	      } // End compute_jacobian check

	  } // End i dof loop
      } // End quadrature loop

#ifdef GRINS_USE_GRVY_TIMERS
    this->_timer->EndTimer("BoussinesqBuoyancyAdjointStabilization::element_time_derivative");
#endif

    return;
  }

} // namespace GRINS
<commit_msg>untabify<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// GRINS - General Reacting Incompressible Navier-Stokes
//
// Copyright (C) 2010-2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

// This class
#include "grins_config.h"
#include "grins/boussinesq_buoyancy_adjoint_stab.h"

// GRINS
#include "grins/assembly_context.h"

// libMesh
#include "libmesh/getpot.h"
#include "libmesh/string_to_enum.h"
#include "libmesh/fem_system.h"
#include "libmesh/quadrature.h"

namespace GRINS
{

  BoussinesqBuoyancyAdjointStabilization::BoussinesqBuoyancyAdjointStabilization( const std::string& physics_name, const GetPot& input )
    : BoussinesqBuoyancyBase(physics_name,input),
      /* \todo Do we want to have these come from a BoussinesqBuoyancyAdjointStabilization section instead? */
      _rho( input("Physics/"+incompressible_navier_stokes+"/rho", 1.0) ),
      _mu( input("Physics/"+incompressible_navier_stokes+"/mu", 1.0) ),
      _stab_helper( input ),
      _p_var_name( input("Physics/VariableNames/pressure", p_var_name_default ) ),
      _P_FE_family( libMesh::Utility::string_to_enum<libMeshEnums::FEFamily>( input("Physics/"+incompressible_navier_stokes+"/FE_family", "LAGRANGE") ) ),
      _P_order( libMesh::Utility::string_to_enum<libMeshEnums::Order>( input("Physics/"+incompressible_navier_stokes+"/P_order", "FIRST") ) )
  {
    return;
  }

  BoussinesqBuoyancyAdjointStabilization::~BoussinesqBuoyancyAdjointStabilization()
  {
    return;
  }

  void BoussinesqBuoyancyAdjointStabilization::init_context( AssemblyContext& context )
  {
    context.get_element_fe(this->_p_var)->get_dphi();

    context.get_element_fe(this->_u_var)->get_dphi();
    context.get_element_fe(this->_u_var)->get_d2phi();

    return;
  }

  void BoussinesqBuoyancyAdjointStabilization::init_variables( libMesh::FEMSystem* system )
  {
    // First call base class
    BoussinesqBuoyancyBase::init_variables(system);

    _p_var = system->add_variable( _p_var_name, this->_P_order, _P_FE_family);

    return;
  }

  void BoussinesqBuoyancyAdjointStabilization::element_time_derivative( bool compute_jacobian,
                                                                        AssemblyContext& context,
                                                                        CachedValues& /*cache*/ )
  {
#ifdef GRINS_USE_GRVY_TIMERS
    this->_timer->BeginTimer("BoussinesqBuoyancyAdjointStabilization::element_time_derivative");
#endif

    // The number of local degrees of freedom in each variable.
    const unsigned int n_u_dofs = context.get_dof_indices(_u_var).size();
    const unsigned int n_p_dofs = context.get_dof_indices(_p_var).size();

    // Element Jacobian * quadrature weights for interior integration.
    const std::vector<libMesh::Real> &JxW =
      context.get_element_fe(_u_var)->get_JxW();

    const std::vector<std::vector<libMesh::RealGradient> >& u_gradphi =
      context.get_element_fe(this->_u_var)->get_dphi();

    const std::vector<std::vector<libMesh::RealTensor> >& u_hessphi =
      context.get_element_fe(this->_u_var)->get_d2phi();

    const std::vector<std::vector<libMesh::RealGradient> >& p_dphi =
      context.get_element_fe(this->_p_var)->get_dphi();

    // Get residuals
    libMesh::DenseSubVector<libMesh::Number> &Fu = context.get_elem_residual(_u_var); // R_{u}
    libMesh::DenseSubVector<libMesh::Number> &Fv = context.get_elem_residual(_v_var); // R_{v}
    libMesh::DenseSubVector<libMesh::Number> *Fw = NULL;
    if(this->_dim == 3)
      Fw = &context.get_elem_residual(this->_w_var); // R_{w}

    libMesh::DenseSubVector<libMesh::Number> &Fp = context.get_elem_residual(this->_p_var); // R_{p}

    // Now we will build the element Jacobian and residual.
    // Constructing the residual requires the solution and its
    // gradient from the previous timestep.  This must be
    // calculated at each quadrature point by summing the
    // solution degree-of-freedom values by the appropriate
    // weight functions.
    unsigned int n_qpoints = context.get_element_qrule().n_points();

    libMesh::FEBase* fe = context.get_element_fe(this->_u_var);

    for (unsigned int qp=0; qp != n_qpoints; qp++)
      {
        libMesh::RealGradient g = this->_stab_helper.compute_g( fe, context, qp );
        libMesh::RealTensor G = this->_stab_helper.compute_G( fe, context, qp );

        libMesh::RealGradient U( context.interior_value( this->_u_var, qp ),
                                 context.interior_value( this->_v_var, qp ) );
        if( this->_dim == 3 )
          {
            U(2) = context.interior_value( this->_w_var, qp );
          }

        libMesh::Real tau_M = this->_stab_helper.compute_tau_momentum( context, qp, g, G, this->_rho, U, this->_mu, this->_is_steady );

        // Compute the solution & its gradient at the old Newton iterate.
        libMesh::Number T;
        T = context.interior_value(_T_var, qp);

        libMesh::RealGradient residual = -_rho_ref*_beta_T*(T-_T_ref)*_g;

        // First, an i-loop over the velocity degrees of freedom.
        // We know that n_u_dofs == n_v_dofs so we can compute contributions
        // for both at the same time.
        for (unsigned int i=0; i != n_p_dofs; i++)
          {
            Fp(i) += tau_M*residual*p_dphi[i][qp]*JxW[qp];
          }

        for (unsigned int i=0; i != n_u_dofs; i++)
          {
            Fu(i) += ( this->_rho*U*u_gradphi[i][qp]
                       + this->_mu*( u_hessphi[i][qp](0,0) + u_hessphi[i][qp](1,1) + u_hessphi[i][qp](2,2) ) )*tau_M*residual(0)*JxW[qp];

            Fv(i) += ( this->_rho*U*u_gradphi[i][qp]
                       + this->_mu*( u_hessphi[i][qp](0,0) + u_hessphi[i][qp](1,1) + u_hessphi[i][qp](2,2) ) )*tau_M*residual(1)*JxW[qp];

            if (_dim == 3)
              {
                (*Fw)(i) += ( this->_rho*U*u_gradphi[i][qp]
                              + this->_mu*( u_hessphi[i][qp](0,0) + u_hessphi[i][qp](1,1) + u_hessphi[i][qp](2,2) ) )*tau_M*residual(2)*JxW[qp];
              }

            if (compute_jacobian)
              {
                libmesh_not_implemented();
              } // End compute_jacobian check

          } // End i dof loop
      } // End quadrature loop

#ifdef GRINS_USE_GRVY_TIMERS
    this->_timer->EndTimer("BoussinesqBuoyancyAdjointStabilization::element_time_derivative");
#endif

    return;
  }

} // namespace GRINS
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include <QtGui/qevent.h>
#include <QtGui/qmenu.h>
#include <QtGui/qaction.h>

#include <QInputDialog>

#include <QDebug>

#include <private/qdeclarativedebug_p.h>

#include "objecttree.h"
#include "inspectorcontext.h"

namespace Qml {
namespace Internal {

ObjectTree::ObjectTree(QDeclarativeEngineDebug *client, QWidget *parent)
    : QTreeWidget(parent),
      m_client(client),
      m_query(0)
{
    setFrameStyle(QFrame::NoFrame);
    setHeaderHidden(true);
    setMinimumWidth(250);
    setExpandsOnDoubleClick(false);

    connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
            SLOT(currentItemChanged(QTreeWidgetItem *)));
    connect(this, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
            SLOT(activated(QTreeWidgetItem *)));
    connect(this, SIGNAL(itemSelectionChanged()), SLOT(selectionChanged()));
}

void ObjectTree::setEngineDebug(QDeclarativeEngineDebug *client)
{
    m_client = client;
}

void ObjectTree::selectionChanged()
{
    if (selectedItems().isEmpty())
        return;

    QTreeWidgetItem *item = selectedItems().first();
    if (item)
        emit contextHelpIdChanged(InspectorContext::contextHelpIdForItem(item->text(0)));
}

void ObjectTree::reload(int objectDebugId)
{
    if (!m_client)
        return;

    if (m_query) {
        delete m_query;
        m_query = 0;
    }

    m_query = m_client->queryObjectRecursive(QDeclarativeDebugObjectReference(objectDebugId), this);
    if (!m_query->isWaiting())
        objectFetched();
    else
        QObject::connect(m_query, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
                         this, SLOT(objectFetched()));
}

void ObjectTree::setCurrentObject(int debugId)
{
    QTreeWidgetItem *item = findItemByObjectId(debugId);
    if (item) {
        setCurrentItem(item);
        scrollToItem(item);
        item->setExpanded(true);
    }

}

void ObjectTree::objectFetched()
{
    //dump(m_query->object(), 0);
    buildTree(m_query->object(), 0);
    setCurrentItem(topLevelItem(0));

    delete m_query;
    m_query = 0;
}

void ObjectTree::currentItemChanged(QTreeWidgetItem *item)
{
    if (!item)
        return;

    QDeclarativeDebugObjectReference obj = item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
    if (obj.debugId() >= 0)
        emit currentObjectChanged(obj);
}

void ObjectTree::activated(QTreeWidgetItem *item)
{
    if (!item)
        return;

    QDeclarativeDebugObjectReference obj = item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
    if (obj.debugId() >= 0)
        emit activated(obj);
}

void ObjectTree::buildTree(const QDeclarativeDebugObjectReference &obj, QTreeWidgetItem *parent)
{
    if (!parent)
        clear();

    QTreeWidgetItem *item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(this);
    if (obj.idString().isEmpty())
        item->setText(0, obj.className());
    else
        item->setText(0, obj.idString());
    item->setData(0, Qt::UserRole, qVariantFromValue(obj));

    if (parent && obj.contextDebugId() >= 0
            && obj.contextDebugId() != parent->data(0, Qt::UserRole
                    ).value<QDeclarativeDebugObjectReference>().contextDebugId()) {
        QDeclarativeDebugFileReference source = obj.source();
        if (!source.url().isEmpty()) {
            QString toolTipString = QLatin1String("URL: ") + source.url().toString();
            item->setToolTip(0, toolTipString);
        }
        item->setForeground(0, QColor("orange"));
    } else {
        item->setExpanded(true);
    }

    if (obj.contextDebugId() < 0)
    {
        item->setForeground(0, Qt::lightGray);
    }

    for (int ii = 0; ii < obj.children().count(); ++ii)
        buildTree(obj.children().at(ii), item);
}

void ObjectTree::dump(const QDeclarativeDebugContextReference &ctxt, int ind)
{
    QByteArray indent(ind * 4, ' ');
    qWarning().nospace() << indent.constData() << ctxt.debugId() << " "
                         << qPrintable(ctxt.name());

    for (int ii = 0; ii < ctxt.contexts().count(); ++ii)
        dump(ctxt.contexts().at(ii), ind + 1);

    for (int ii = 0; ii < ctxt.objects().count(); ++ii)
        dump(ctxt.objects().at(ii), ind);
}

void ObjectTree::dump(const QDeclarativeDebugObjectReference &obj, int ind)
{
    QByteArray indent(ind * 4, ' ');
    qWarning().nospace() << indent.constData() << qPrintable(obj.className())
                         << " " << qPrintable(obj.idString()) << " "
                         << obj.debugId();

    for (int ii = 0; ii < obj.children().count(); ++ii)
        dump(obj.children().at(ii), ind + 1);
}

QTreeWidgetItem *ObjectTree::findItemByObjectId(int debugId) const
{
    for (int i=0; i<topLevelItemCount(); ++i) {
        QTreeWidgetItem *item = findItem(topLevelItem(i), debugId);
        if (item)
            return item;
    }

    return 0;
}

QTreeWidgetItem *ObjectTree::findItem(QTreeWidgetItem *item, int debugId) const
{
    if (item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>().debugId() == debugId)
        return item;

    QTreeWidgetItem *child;
    for (int i=0; i<item->childCount(); ++i) {
        child = findItem(item->child(i), debugId);
        if (child)
            return child;
    }

    return 0;
}

void ObjectTree::mousePressEvent(QMouseEvent *me)
{
    QTreeWidget::mousePressEvent(me);
    if (!currentItem())
        return;
    if(me->button()  == Qt::RightButton && me->type() == QEvent::MouseButtonPress) {
        QAction action(tr("Add watch..."), 0);
        QList<QAction *> actions;
        actions << &action;
        QDeclarativeDebugObjectReference obj =
                currentItem()->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
        if (QMenu::exec(actions, me->globalPos())) {
            bool ok = false;
            QString watch = QInputDialog::getText(this, tr("Watch expression"),
                    tr("Expression:"), QLineEdit::Normal, QString(), &ok);
            if (ok && !watch.isEmpty())
                emit expressionWatchRequested(obj, watch);
        }
    }
}

}
}
<commit_msg>QmlInspector: Anonymous items' types displayed with special characters in object tree<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include <QtGui/qevent.h>
#include <QtGui/qmenu.h>
#include <QtGui/qaction.h>

#include <QInputDialog>

#include <QDebug>

#include <private/qdeclarativedebug_p.h>

#include "objecttree.h"
#include "inspectorcontext.h"

namespace Qml {
namespace Internal {

ObjectTree::ObjectTree(QDeclarativeEngineDebug *client, QWidget *parent)
    : QTreeWidget(parent),
      m_client(client),
      m_query(0)
{
    setFrameStyle(QFrame::NoFrame);
    setHeaderHidden(true);
    setMinimumWidth(250);
    setExpandsOnDoubleClick(false);

    connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
            SLOT(currentItemChanged(QTreeWidgetItem *)));
    connect(this, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
            SLOT(activated(QTreeWidgetItem *)));
    connect(this, SIGNAL(itemSelectionChanged()), SLOT(selectionChanged()));
}

void ObjectTree::setEngineDebug(QDeclarativeEngineDebug *client)
{
    m_client = client;
}

void ObjectTree::selectionChanged()
{
    if (selectedItems().isEmpty())
        return;

    QTreeWidgetItem *item = selectedItems().first();
    if (item)
        emit contextHelpIdChanged(InspectorContext::contextHelpIdForItem(item->text(0)));
}

void ObjectTree::reload(int objectDebugId)
{
    if (!m_client)
        return;

    if (m_query) {
        delete m_query;
        m_query = 0;
    }

    m_query = m_client->queryObjectRecursive(QDeclarativeDebugObjectReference(objectDebugId), this);
    if (!m_query->isWaiting())
        objectFetched();
    else
        QObject::connect(m_query, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
                         this, SLOT(objectFetched()));
}

void ObjectTree::setCurrentObject(int debugId)
{
    QTreeWidgetItem *item = findItemByObjectId(debugId);
    if (item) {
        setCurrentItem(item);
        scrollToItem(item);
        item->setExpanded(true);
    }

}

void ObjectTree::objectFetched()
{
    //dump(m_query->object(), 0);
    buildTree(m_query->object(), 0);
    setCurrentItem(topLevelItem(0));

    delete m_query;
    m_query = 0;
}

void ObjectTree::currentItemChanged(QTreeWidgetItem *item)
{
    if (!item)
        return;

    QDeclarativeDebugObjectReference obj = item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
    if (obj.debugId() >= 0)
        emit currentObjectChanged(obj);
}

void ObjectTree::activated(QTreeWidgetItem *item)
{
    if (!item)
        return;

    QDeclarativeDebugObjectReference obj = item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
    if (obj.debugId() >= 0)
        emit activated(obj);
}

void ObjectTree::buildTree(const QDeclarativeDebugObjectReference &obj, QTreeWidgetItem *parent)
{
    if (!parent)
        clear();

    QTreeWidgetItem *item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(this);
    if (obj.idString().isEmpty())
        item->setText(0, QLatin1String("<")+obj.className()+QLatin1String(">"));
    else
        item->setText(0, obj.idString());
    item->setData(0, Qt::UserRole, qVariantFromValue(obj));

    if (parent && obj.contextDebugId() >= 0
            && obj.contextDebugId() != parent->data(0, Qt::UserRole
                    ).value<QDeclarativeDebugObjectReference>().contextDebugId()) {
        QDeclarativeDebugFileReference source = obj.source();
        if (!source.url().isEmpty()) {
            QString toolTipString = QLatin1String("URL: ") + source.url().toString();
            item->setToolTip(0, toolTipString);
        }
        item->setForeground(0, QColor("orange"));
    } else {
        item->setExpanded(true);
    }

    if (obj.contextDebugId() < 0)
    {
        item->setForeground(0, Qt::lightGray);
    }

    for (int ii = 0; ii < obj.children().count(); ++ii)
        buildTree(obj.children().at(ii), item);
}

void ObjectTree::dump(const QDeclarativeDebugContextReference &ctxt, int ind)
{
    QByteArray indent(ind * 4, ' ');
    qWarning().nospace() << indent.constData() << ctxt.debugId() << " "
                         << qPrintable(ctxt.name());

    for (int ii = 0; ii < ctxt.contexts().count(); ++ii)
        dump(ctxt.contexts().at(ii), ind + 1);

    for (int ii = 0; ii < ctxt.objects().count(); ++ii)
        dump(ctxt.objects().at(ii), ind);
}

void ObjectTree::dump(const QDeclarativeDebugObjectReference &obj, int ind)
{
    QByteArray indent(ind * 4, ' ');
    qWarning().nospace() << indent.constData() << qPrintable(obj.className())
                         << " " << qPrintable(obj.idString()) << " "
                         << obj.debugId();

    for (int ii = 0; ii < obj.children().count(); ++ii)
        dump(obj.children().at(ii), ind + 1);
}

QTreeWidgetItem *ObjectTree::findItemByObjectId(int debugId) const
{
    for (int i=0; i<topLevelItemCount(); ++i) {
        QTreeWidgetItem *item = findItem(topLevelItem(i), debugId);
        if (item)
            return item;
    }

    return 0;
}

QTreeWidgetItem *ObjectTree::findItem(QTreeWidgetItem *item, int debugId) const
{
    if (item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>().debugId() == debugId)
        return item;

    QTreeWidgetItem *child;
    for (int i=0; i<item->childCount(); ++i) {
        child = findItem(item->child(i), debugId);
        if (child)
            return child;
    }

    return 0;
}

void ObjectTree::mousePressEvent(QMouseEvent *me)
{
    QTreeWidget::mousePressEvent(me);
    if (!currentItem())
        return;
    if(me->button()  == Qt::RightButton && me->type() == QEvent::MouseButtonPress) {
        QAction action(tr("Add watch..."), 0);
        QList<QAction *> actions;
        actions << &action;
        QDeclarativeDebugObjectReference obj =
                currentItem()->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
        if (QMenu::exec(actions, me->globalPos())) {
            bool ok = false;
            QString watch = QInputDialog::getText(this, tr("Watch expression"),
                    tr("Expression:"), QLineEdit::Normal, QString(), &ok);
            if (ok && !watch.isEmpty())
                emit expressionWatchRequested(obj, watch);
        }
    }
}

}
}
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2013 Heiko Strathmann
 */

#include <shogun/statistics/MMDKernelSelectionMedian.h>
#include <shogun/statistics/LinearTimeMMD.h>
#include <shogun/features/streaming/StreamingFeatures.h>
#include <shogun/statistics/QuadraticTimeMMD.h>
#include <shogun/distance/EuclideanDistance.h>
#include <shogun/kernel/GaussianKernel.h>
#include <shogun/kernel/CombinedKernel.h>
#include <shogun/mathematics/Statistics.h>

using namespace shogun;

CMMDKernelSelectionMedian::CMMDKernelSelectionMedian() :
		CMMDKernelSelection()
{
	init();
}

CMMDKernelSelectionMedian::CMMDKernelSelectionMedian(
		CKernelTwoSampleTestStatistic* mmd, index_t num_data_distance) :
		CMMDKernelSelection(mmd)
{
	/* assert that a combined kernel is used */
	CKernel* kernel=mmd->get_kernel();
	CFeatures* lhs=kernel->get_lhs();
	CFeatures* rhs=kernel->get_rhs();
	REQUIRE(kernel, "%s::%s(): No kernel set!\n", get_name(), get_name());
	REQUIRE(kernel->get_kernel_type()==K_COMBINED, "%s::%s(): Requires "
			"CombinedKernel as kernel. Yours is %s", get_name(), get_name(),
			kernel->get_name());

	/* assert that all subkernels are Gaussian kernels */
	CCombinedKernel* combined=(CCombinedKernel*)kernel;
	CKernel* subkernel=combined->get_first_kernel();
	index_t i=0;
	while (subkernel)
	{
		REQUIRE(kernel, "%s::%s(): Subkernel (i) of current kernel is not"
				" of type GaussianKernel\n", get_name(), get_name(), i);
		SG_UNREF(subkernel);
		subkernel=combined->get_next_kernel();
		i++;
	}

	/* assert 64 bit dense features since EuclideanDistance can only handle
	 * those */
	if (m_mmd->get_statistic_type()==S_QUADRATIC_TIME_MMD)
	{
		CFeatures* features=((CQuadraticTimeMMD*)m_mmd)->get_p_and_q();
		REQUIRE(features->get_feature_class()==C_DENSE &&
				features->get_feature_type()==F_DREAL, "%s::select_kernel(): "
				"Only 64 bit float dense features allowed, these are \"%s\""
				" and of type %d\n",
				get_name(), features->get_name(), features->get_feature_type());
		SG_UNREF(features);
	}
	else if (m_mmd->get_statistic_type()==S_LINEAR_TIME_MMD)
	{
		CStreamingFeatures* p=((CLinearTimeMMD*)m_mmd)->get_streaming_p();
		CStreamingFeatures* q=((CLinearTimeMMD*)m_mmd)->get_streaming_q();
		REQUIRE(p->get_feature_class()==C_STREAMING_DENSE &&
				p->get_feature_type()==F_DREAL, "%s::select_kernel(): "
				"Only 64 bit float streaming dense features allowed, these (p) "
				"are \"%s\" and of type %d\n",
				get_name(), p->get_name(), p->get_feature_type());

		REQUIRE(p->get_feature_class()==C_STREAMING_DENSE &&
				p->get_feature_type()==F_DREAL, "%s::select_kernel(): "
				"Only 64 bit float streaming dense features allowed, these (q) "
				"are \"%s\" and of type %d\n",
				get_name(), q->get_name(), q->get_feature_type());
	}

	SG_UNREF(kernel);
	SG_UNREF(lhs);
	SG_UNREF(rhs);

	init();

	m_num_data_distance=num_data_distance;
}

CMMDKernelSelectionMedian::~CMMDKernelSelectionMedian()
{
}

void CMMDKernelSelectionMedian::init()
{
	SG_WARNING("register params!\n")

	/* this is a sensible value */
	m_num_data_distance=1000;
}

SGVector<float64_t> CMMDKernelSelectionMedian::compute_measures()
{
	SG_ERROR("%s::compute_measures(): Not implemented. Use select_kernel() "
	"method!\n", get_name());
	return SGVector<float64_t>();
}

CKernel* CMMDKernelSelectionMedian::select_kernel()
{
	/* number of data for distace */
	index_t num_data=CMath::min(m_num_data_distance, m_mmd->get_m());

	SGMatrix<float64_t> dists;

	/* compute all pairwise distances, depends which mmd statistic is used */
	if (m_mmd->get_statistic_type()==S_QUADRATIC_TIME_MMD)
	{
		/* fixed data, create merged copy of a random subset */

		/* create vector with that correspond to the num_data first points of
		 * each distribution, remember data is stored jointly */
		SGVector<index_t> subset(num_data*2);
		index_t m=m_mmd->get_m();
		for (index_t i=0; i<num_data; ++i)
		{
			/* num_data samples from each half of joint sample */
			subset[i]=i;
			subset[i+num_data]=i+m;
		}

		/* add subset and compute pairwise distances */
		CQuadraticTimeMMD* quad_mmd=(CQuadraticTimeMMD*)m_mmd;
		CFeatures* features=quad_mmd->get_p_and_q();
		features->add_subset(subset);

		/* cast is safe, see constructor */
		CDenseFeatures<float64_t>* dense_features=
				(CDenseFeatures<float64_t>*) features;

		dense_features->get_feature_matrix().display_matrix("dense");

		CEuclideanDistance* distance=new CEuclideanDistance(dense_features,
				dense_features);
		dists=distance->get_distance_matrix();
		features->remove_subset();
		SG_UNREF(distance);
		SG_UNREF(features);
	}
	else if (m_mmd->get_statistic_type()==S_LINEAR_TIME_MMD)
	{
		/* just stream the desired number of points */
		CLinearTimeMMD* linear_mmd=(CLinearTimeMMD*)m_mmd;

		CStreamingFeatures* p=linear_mmd->get_streaming_p();
		CStreamingFeatures* q=linear_mmd->get_streaming_q();

		/* cast is safe, see constructor */
		CDenseFeatures<float64_t>* p_streamed=(CDenseFeatures<float64_t>*)
				p->get_streamed_features(num_data);
		CDenseFeatures<float64_t>* q_streamed=(CDenseFeatures<float64_t>*)
					q->get_streamed_features(num_data);

		/* for safety */
		SG_REF(p_streamed);
		SG_REF(q_streamed);

		/* create merged feature object */
		CDenseFeatures<float64_t>* merged=(CDenseFeatures<float64_t>*)
				p_streamed->create_merged_copy(q_streamed);

		/* compute pairwise distances */
		CEuclideanDistance* distance=new CEuclideanDistance(merged, merged);
		dists=distance->get_distance_matrix();

		/* clean up */
		SG_UNREF(distance);
		SG_REF(p_streamed);
		SG_REF(q_streamed);
		SG_UNREF(p);
		SG_UNREF(q);
	}

	/* create a vector where the zeros have been removed, use upper triangle
	 * only since distances are symmetric */
	SGVector<float64_t> dist_vec(dists.num_rows*(dists.num_rows-1)/2);
	index_t write_idx=0;
	for (index_t i=0; i<dists.num_rows; ++i)
	{
		for (index_t j=i+1; j<dists.num_rows; ++j)
			dist_vec[write_idx++]=dists(i,j);
	}

	/* now we have distance matrix, compute median, allow to modify matrix */
	float64_t median_distance=CStatistics::median(dist_vec, true);
	SG_DEBUG("median_distance: %f\n", median_distance);

	/* shogun has no square and factor two in its kernel width, MATLAB does
	 * median_width = sqrt(0.5*median_distance), we do this */
	float64_t shogun_sigma=median_distance;
	SG_DEBUG("kernel width (shogun): %f\n", shogun_sigma);

	/* now of all kernels, find the one which has its width closest
	 * Cast is safe due to constructor of MMDKernelSelection class */
	CCombinedKernel* combined=(CCombinedKernel*)m_mmd->get_kernel();
	CKernel* current=combined->get_first_kernel();
	float64_t min_distance=CMath::MAX_REAL_NUMBER;
	CKernel* min_kernel=NULL;
	float64_t distance;
	for (index_t i=0; i<combined->get_num_subkernels(); ++i)
	{
		REQUIRE(current->get_kernel_type()==K_GAUSSIAN, "%s::select_kernel(): "
				"%d-th kernel is not a Gaussian but \"%s\"!\n", get_name(), i,
				current->get_name());

		/* check if width is closer to median width */
		distance=CMath::abs(((CGaussianKernel*)current)->get_width()-
				shogun_sigma);

		if (distance<min_distance)
		{
			min_distance=distance;
			min_kernel=current;
		}

		/* next kernel */
		SG_UNREF(current);
		current=combined->get_next_kernel();
	}
	SG_UNREF(combined);

	/* returned referenced kernel */
	SG_REF(min_kernel);
	return min_kernel;
}
<commit_msg>fixed a memory leak<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2013 Heiko Strathmann
 */

#include <shogun/statistics/MMDKernelSelectionMedian.h>
#include <shogun/statistics/LinearTimeMMD.h>
#include <shogun/features/streaming/StreamingFeatures.h>
#include <shogun/statistics/QuadraticTimeMMD.h>
#include <shogun/distance/EuclideanDistance.h>
#include <shogun/kernel/GaussianKernel.h>
#include <shogun/kernel/CombinedKernel.h>
#include <shogun/mathematics/Statistics.h>

using namespace shogun;

CMMDKernelSelectionMedian::CMMDKernelSelectionMedian() :
		CMMDKernelSelection()
{
	init();
}

CMMDKernelSelectionMedian::CMMDKernelSelectionMedian(
		CKernelTwoSampleTestStatistic* mmd, index_t num_data_distance) :
		CMMDKernelSelection(mmd)
{
	/* assert that a combined kernel is used */
	CKernel* kernel=mmd->get_kernel();
	CFeatures* lhs=kernel->get_lhs();
	CFeatures* rhs=kernel->get_rhs();
	REQUIRE(kernel, "%s::%s(): No kernel set!\n", get_name(), get_name());
	REQUIRE(kernel->get_kernel_type()==K_COMBINED, "%s::%s(): Requires "
			"CombinedKernel as kernel. Yours is %s", get_name(), get_name(),
			kernel->get_name());

	/* assert that all subkernels are Gaussian kernels */
	CCombinedKernel* combined=(CCombinedKernel*)kernel;
	CKernel* subkernel=combined->get_first_kernel();
	index_t i=0;
	while (subkernel)
	{
		REQUIRE(kernel, "%s::%s(): Subkernel (i) of current kernel is not"
				" of type GaussianKernel\n", get_name(), get_name(), i);
		SG_UNREF(subkernel);
		subkernel=combined->get_next_kernel();
		i++;
	}

	/* assert 64 bit dense features since EuclideanDistance can only handle
	 * those */
	if (m_mmd->get_statistic_type()==S_QUADRATIC_TIME_MMD)
	{
		CFeatures* features=((CQuadraticTimeMMD*)m_mmd)->get_p_and_q();
		REQUIRE(features->get_feature_class()==C_DENSE &&
				features->get_feature_type()==F_DREAL, "%s::select_kernel(): "
				"Only 64 bit float dense features allowed, these are \"%s\""
				" and of type %d\n",
				get_name(), features->get_name(), features->get_feature_type());
		SG_UNREF(features);
	}
	else if (m_mmd->get_statistic_type()==S_LINEAR_TIME_MMD)
	{
		CStreamingFeatures* p=((CLinearTimeMMD*)m_mmd)->get_streaming_p();
		CStreamingFeatures* q=((CLinearTimeMMD*)m_mmd)->get_streaming_q();
		REQUIRE(p->get_feature_class()==C_STREAMING_DENSE &&
				p->get_feature_type()==F_DREAL, "%s::select_kernel(): "
				"Only 64 bit float streaming dense features allowed, these (p) "
				"are \"%s\" and of type %d\n",
				get_name(), p->get_name(), p->get_feature_type());

		REQUIRE(p->get_feature_class()==C_STREAMING_DENSE &&
				p->get_feature_type()==F_DREAL, "%s::select_kernel(): "
				"Only 64 bit float streaming dense features allowed, these (q) "
				"are \"%s\" and of type %d\n",
				get_name(), q->get_name(), q->get_feature_type());
		SG_UNREF(p);
		SG_UNREF(q);
	}

	SG_UNREF(kernel);
	SG_UNREF(lhs);
	SG_UNREF(rhs);

	init();

	m_num_data_distance=num_data_distance;
}

CMMDKernelSelectionMedian::~CMMDKernelSelectionMedian()
{
}

void CMMDKernelSelectionMedian::init()
{
	SG_WARNING("register params!\n")

	/* this is a sensible value */
	m_num_data_distance=1000;
}

SGVector<float64_t> CMMDKernelSelectionMedian::compute_measures()
{
	SG_ERROR("%s::compute_measures(): Not implemented. Use select_kernel() "
	"method!\n", get_name());
	return SGVector<float64_t>();
}

CKernel* CMMDKernelSelectionMedian::select_kernel()
{
	/* number of data for distace */
	index_t num_data=CMath::min(m_num_data_distance, m_mmd->get_m());

	SGMatrix<float64_t> dists;

	/* compute all pairwise distances, depends which mmd statistic is used */
	if (m_mmd->get_statistic_type()==S_QUADRATIC_TIME_MMD)
	{
		/* fixed data, create merged copy of a random subset */

		/* create vector with that correspond to the num_data first points of
		 * each distribution, remember data is stored jointly */
		SGVector<index_t> subset(num_data*2);
		index_t m=m_mmd->get_m();
		for (index_t i=0; i<num_data; ++i)
		{
			/* num_data samples from each half of joint sample */
			subset[i]=i;
			subset[i+num_data]=i+m;
		}

		/* add subset and compute pairwise distances */
		CQuadraticTimeMMD* quad_mmd=(CQuadraticTimeMMD*)m_mmd;
		CFeatures* features=quad_mmd->get_p_and_q();
		features->add_subset(subset);

		/* cast is safe, see constructor */
		CDenseFeatures<float64_t>* dense_features=
				(CDenseFeatures<float64_t>*) features;

		dense_features->get_feature_matrix().display_matrix("dense");

		CEuclideanDistance* distance=new CEuclideanDistance(dense_features,
				dense_features);
		dists=distance->get_distance_matrix();
		features->remove_subset();
		SG_UNREF(distance);
		SG_UNREF(features);
	}
	else if (m_mmd->get_statistic_type()==S_LINEAR_TIME_MMD)
	{
		/* just stream the desired number of points */
		CLinearTimeMMD* linear_mmd=(CLinearTimeMMD*)m_mmd;

		CStreamingFeatures* p=linear_mmd->get_streaming_p();
		CStreamingFeatures* q=linear_mmd->get_streaming_q();

		/* cast is safe, see constructor */
		CDenseFeatures<float64_t>* p_streamed=(CDenseFeatures<float64_t>*)
				p->get_streamed_features(num_data);
		CDenseFeatures<float64_t>* q_streamed=(CDenseFeatures<float64_t>*)
					q->get_streamed_features(num_data);

		/* for safety */
		SG_REF(p_streamed);
		SG_REF(q_streamed);

		/* create merged feature object */
		CDenseFeatures<float64_t>* merged=(CDenseFeatures<float64_t>*)
				p_streamed->create_merged_copy(q_streamed);

		/* compute pairwise distances */
		CEuclideanDistance* distance=new CEuclideanDistance(merged, merged);
		dists=distance->get_distance_matrix();

		/* clean up */
		SG_UNREF(distance);
		SG_UNREF(p_streamed);
		SG_UNREF(q_streamed);
		SG_UNREF(p);
		SG_UNREF(q);
	}

	/* create a vector where the zeros have been removed, use upper triangle
	 * only since distances are symmetric */
	SGVector<float64_t> dist_vec(dists.num_rows*(dists.num_rows-1)/2);
	index_t write_idx=0;
	for (index_t i=0; i<dists.num_rows; ++i)
	{
		for (index_t j=i+1; j<dists.num_rows; ++j)
			dist_vec[write_idx++]=dists(i,j);
	}

	/* now we have distance matrix, compute median, allow to modify matrix */
	float64_t median_distance=CStatistics::median(dist_vec, true);
	SG_DEBUG("median_distance: %f\n", median_distance);

	/* shogun has no square and factor two in its kernel width, MATLAB does
	 * median_width = sqrt(0.5*median_distance), we do this */
	float64_t shogun_sigma=median_distance;
	SG_DEBUG("kernel width (shogun): %f\n", shogun_sigma);

	/* now of all kernels, find the one which has its width closest
	 * Cast is safe due to constructor of MMDKernelSelection class */
	CCombinedKernel* combined=(CCombinedKernel*)m_mmd->get_kernel();
	CKernel* current=combined->get_first_kernel();
	float64_t min_distance=CMath::MAX_REAL_NUMBER;
	CKernel* min_kernel=NULL;
	float64_t distance;
	for (index_t i=0; i<combined->get_num_subkernels(); ++i)
	{
		REQUIRE(current->get_kernel_type()==K_GAUSSIAN, "%s::select_kernel(): "
				"%d-th kernel is not a Gaussian but \"%s\"!\n", get_name(), i,
				current->get_name());

		/* check if width is closer to median width */
		distance=CMath::abs(((CGaussianKernel*)current)->get_width()-
				shogun_sigma);

		if (distance<min_distance)
		{
			min_distance=distance;
			min_kernel=current;
		}

		/* next kernel */
		SG_UNREF(current);
		current=combined->get_next_kernel();
	}
	SG_UNREF(combined);

	/* returned referenced kernel */
	SG_REF(min_kernel);
	return min_kernel;
}
<|endoftext|>