Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ build/*
.cproject
.project
.vs
CMakeSettings.json
CMakeSettings.json

76 changes: 75 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ message(STATUS "=======================================================\n\n")

message(STATUS "VCL2_INCLUDE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}/third_party/VCL_v2")

set(BPARSER_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include ${Boost_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/third_party/VCL_v2 ${EIGEN3_INCLUDE_DIR})
set(BPARSER_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/cases ${Boost_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/third_party/VCL_v2 ${EIGEN3_INCLUDE_DIR})
if(NOT PROJECT_IS_TOP_LEVEL)
set(BPARSER_INCLUDES ${BPARSER_INCLUDES} PARENT_SCOPE)
endif()
Expand Down Expand Up @@ -290,3 +290,77 @@ define_test(test_grammar bparser)
define_test(test_processor bparser) #is it broken? -LV
define_test(test_speed bparser)
define_test(test_simd)

macro(define_nit_gen make_name def_file gen_file)
set(src_name "nitpick_generate")
set(nit_source "${CMAKE_CURRENT_SOURCE_DIR}/nitpick/${src_name}.cc")
set(nit_name "${src_name}_${make_name}")
set(nit_binary "${nit_name}_bin")

add_executable(${nit_binary} EXCLUDE_FROM_ALL ${nit_source} )
add_dependencies(${nit_binary} bparser)
target_link_libraries(${nit_binary} bparser)
#set_property(TARGET ${nit_binary} PROPERTY COMPILE_DEFINITIONS "DEF_FILE=$<PATH:NORMAL_PATH,\"${def_file}\">;GEN_FILE=$<PATH:NORMAL_PATH,\"${gen_file}\">")
set_property(TARGET ${nit_binary} PROPERTY COMPILE_DEFINITIONS "DEF_FILE=\"${def_file}\";GEN_FILE=\"${gen_file}\"")

add_custom_target(${nit_name}
COMMAND "$<TARGET_FILE:${nit_binary}>"
DEPENDS ${nit_binary}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/cases")
endmacro()

macro(define_nit_run make_name def_file gen_file)
set(src_name "nitpick_run")
set(nit_source "${CMAKE_CURRENT_SOURCE_DIR}/nitpick/${src_name}.cc")
set(nit_name "${src_name}_${make_name}")
set(nit_binary "${nit_name}_bin")

add_executable(${nit_binary} EXCLUDE_FROM_ALL ${nit_source} )
add_dependencies(${nit_binary} bparser)
target_link_libraries(${nit_binary} bparser)
#set_target_properties(${nit_binary} PROPERTIES COMPILE_DEFINITIONS "DEF_FILE=$<PATH:NORMAL_PATH,${def_file}>;GEN_FILE=$<PATH:NORMAL_PATH,${gen_file}>")
set_property(TARGET ${nit_binary} PROPERTY COMPILE_DEFINITIONS "DEF_FILE=\"${def_file}\";GEN_FILE=\"${gen_file}\"")

add_custom_target(${nit_name}
COMMAND "$<TARGET_FILE:${nit_binary}>"
DEPENDS ${nit_binary}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/cases")
endmacro()

macro(define_nit make_name def_file gen_file)
define_nit_gen(${make_name} ${def_file} ${gen_file})

define_nit_run(${make_name} ${def_file} ${gen_file})
endmacro()

define_nit(basic_expr basic_expr_def.cc basic_expr_gen.cc)
define_nit(norm2 norm2_def.cc norm2_gen.cc)


#set(src_name "nitpick_generate")
#set(nit_source "${CMAKE_CURRENT_SOURCE_DIR}/nitpick/${src_name}.cc")
#set(nit_binary "${src_name}_bin")
#set(nit_name "${src_name}")

#add_executable(${nit_binary} EXCLUDE_FROM_ALL ${nit_source} )
#add_dependencies(${nit_binary} bparser)
#target_link_libraries(${nit_binary} bparser)

#add_custom_target(${nit_name}
#COMMAND "$<TARGET_FILE:${nit_binary}>"
#DEPENDS ${nit_binary}
#WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/nitpick")

#set(src_name "nitpick_run")
#set(nit_source "${CMAKE_CURRENT_SOURCE_DIR}/nitpick/${src_name}.cc")
#set(nit_binary "${src_name}_bin")
#set(nit_name "${src_name}")

#add_executable(${nit_binary} EXCLUDE_FROM_ALL ${nit_source} )
#add_dependencies(${nit_binary} bparser)
#target_link_libraries(${nit_binary} bparser)

#add_custom_target(${nit_name}
#COMMAND "$<TARGET_FILE:${nit_binary}>"
#DEPENDS ${nit_binary}
#WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/nitpick")
61 changes: 61 additions & 0 deletions cases/basic_expr_def.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Prepare an environment for both DAG generation and then subsequent running
*/


#ifndef NITPICK_IDE_IGNORE
#include "nitpick_include.hh"
#endif //NITPICK_IDE_IGNORE



#ifndef NITPICK_IDE_IGNORE
int main() {
#endif //NITPICK_IDE_IGNORE

// Define own value vectors, preferably aligned.
// These variable names are used in macros and/or autogenerated files. Renaming them will cause issues
constexpr uint vec_size = 8;
constexpr uint max_vec_size = vec_size;



//Memory allocation

double v1[vec_size * 3];
for (uint i = 0; i < vec_size * 3; ++i) {
v1[i] = i;
}
double v2[vec_size * 3];
for (uint i = 0; i < vec_size * 3; ++i) {
v2[i] = 2;
}
constexpr int vres_size = vec_size * 3;
double vres[vres_size];
for (uint i = 0; i < vres_size; ++i) {
vres[i] = NAN;
}

// Create parser, give the size of the value spaces.
// That is maximal allocated space. Actual values and
// active subset can be changed between evaluations of the expression.
// This variable name is used in macros and/or autogenerated files. Renaming it will cause issues
Parser p(max_vec_size);


// parse an expression.
p.parse("1 * v1 + cs1 * v2");

// "cs1" constant with shape {}, i.e. scalar and values {2}.
P_SET_CONSTANT(cs1, {}, {2});
// "cv1" vector constant with shape {3}
P_SET_CONSTANT(cv1, {3}, ARG({1, 2, 3}));
// "v1" variable with shape {3}; v1 is pointer to the value space
P_SET_VARIABLE(v1, { 3 }, v1);
P_SET_VARIABLE(v2, { 3 }, v2);
// Set the result variable (the last line of the expression)
P_SET_VARIABLE(_result_, { 3 }, vres);

#ifndef NITPICK_IDE_IGNORE
}
#endif //NITPICK_IDE_IGNORE
20 changes: 20 additions & 0 deletions cases/norm2_def.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef NITPICK_IDE_IGNORE
# include "nitpick_include.hh"
#endif //This block will not be compiled during generation/run. But it helps the IDE understand the code

constexpr uint vec_size = 8;
constexpr uint max_vec_size = vec_size;

//MEM_ALLOC(name, 3*vec_size, 2) //2,2,2,2,2,2...
//MEM_ALLOC_INDEX(namei, 3 * vec_size) // 0,1,2,3,4,5...
MEM_ALLOC_LINEAR(v1, 3 * vec_size) // 1,2,3,4,5,6...
constexpr uint vres_size = 3 * vec_size;
MEM_ALLOC(vres, vres_size, NAN)

Parser p(max_vec_size);

p.parse("norm2(v1)");

P_SET_VARIABLE(v1, ARG({3}), v1)
P_SET_VARIABLE(_result_, { }, vres);

171 changes: 164 additions & 7 deletions include/array.hh
Original file line number Diff line number Diff line change
Expand Up @@ -859,28 +859,28 @@ public:
return result;
}


typedef Eigen::MatrixX<details::ScalarWrapper> WrappedArray;

//Wraps the ScalarNodes of an Array into an Eigen Matrix of ScalarWrappers.
//Vectors will be column vectors. Eigen does not support vectors without orientation.
//Cannot wrap scalars. To wrap scalars, use the bparser::details::ScalarWrapper constructor
static Eigen::MatrixX<details::ScalarWrapper> wrap_array(const bparser::Array& a) {
static WrappedArray wrap_array(const bparser::Array& a) {
MultiIdx idx(a.range());
return wrap_array(a, idx);
}

//Wraps the ScalarNodes of an Array accessed via MultiIdx.idx_trg() created from supplied MultiIdxRange into an Eigen Matrix of ScalarWrapper
//Vectors will be column vectors. Eigen does not support vectors without orientation.
//Cannot wrap scalars. To wrap scalars, use the bparser::details::ScalarWrapper constructor
static Eigen::MatrixX<details::ScalarWrapper> wrap_array(const bparser::Array& a, MultiIdxRange& range) {
static WrappedArray wrap_array(const bparser::Array& a, MultiIdxRange& range) {
MultiIdx idx (range);
return wrap_array(a, idx);
}

//Wraps the ScalarNodes of an Array accessed via MultiIdx.idx_trg() into an Eigen Matrix of ScalarWrapper
//Vectors will be column vectors. Eigen does not support vectors without orientation.
//Cannot wrap scalars. To wrap scalars, use the bparser::details::ScalarWrapper constructor
static Eigen::MatrixX<details::ScalarWrapper> wrap_array(const bparser::Array& a, MultiIdx& index) {
static WrappedArray wrap_array(const bparser::Array& a, MultiIdx& index) {

using namespace details;
Shape trg_shape = index.range_.target_shape();
Expand Down Expand Up @@ -1127,15 +1127,15 @@ public:
//std::cout << print_shape(result_shape) << std::endl;

Array result(result_shape);
bool should_transpose = a.shape().size() == 1;
//bool should_transpose = a.shape().size() == 1;

for (MultiIdx
result_idx(result.range()),
a_idx(a_range),
b_idx(b_range); result_idx.valid(); ) {

Eigen::MatrixX<details::ScalarWrapper> m_a = wrap_array(a, a_idx);
Eigen::MatrixX<details::ScalarWrapper> m_b = wrap_array(b, b_idx);
WrappedArray m_a = wrap_array(a, a_idx);
WrappedArray m_b = wrap_array(b, b_idx);

Array matmult = unwrap_array(m_a * m_b);

Expand Down Expand Up @@ -1216,6 +1216,163 @@ public:
//return full_({}, *wrap_array(a).trace());
}

static Array norm1(const Array& a) {
switch (a.shape().size()) {
case 0: //scalar
Throw() << "Norms are not for scalar values" << "\n";
break;
case 1: //vector
{

Shape s; //empty Shape for scalar
Array r(s);
r.elements_[0U] = *wrap_array(a).lpNorm<1>();
return r;
}
case 2: //matrix
{
Shape s; //empty Shape for scalar
Array r(s);
r.elements_[0U] = *wrap_array(a).colwise().lpNorm<1>().maxCoeff();
return r;
}
default:
Throw() << "Norms are not avaiable for ND tensors" << "\n";
}
}

static Array norm2(const Array& a) {
switch (a.shape().size()) {
case 0: //scalar
Throw() << "Norms are not for scalar values" << "\n";
break;
case 1: //vector
{
//Euclidean norm
Shape s; //empty Shape for scalar
Array r(s);
r.elements_[0U] = *wrap_array(a).norm();
return r;
}
case 2: //matrix
{
//Spectral norm
Throw() << "norm2(matrix) is not yet possible" << "\n";
/*Shape s; //empty Shape for scalar
Array r(s);

Eigen::MatrixX<details::ScalarWrapper> m( wrap_array(a) );

r.elements_[0U] = *details::sqrt((m.adjoint()*m).eigenvalues().real().maxCoeff());
//computing eigenvalues would require static cast to double and comparison operators (<,<=,>,>=,!=,==)
//something which we cannot support
return r;*/
break;
}
default:
Throw() << "Norms are not avaiable for ND tensors" << "\n";
}
}

static Array normfro(const Array& a) {
if (a.shape().size() != 2) {
Throw() << "Frobenius norm is only defined for matrices" << "\n";
}

Shape s;
Array r(s);
r.elements_[0U] = *wrap_array(a).norm();
return r;
}

static Array norminf(const Array& a) {
switch (a.shape().size()) {
case 0: //scalar
Throw() << "Norms are not for scalar values" << "\n";
break;
case 1: //vector
{
Shape s; //empty Shape for scalar
Array r(s);
r.elements_[0U] = *wrap_array(a).lpNorm<Eigen::Infinity>();
return r;
}
case 2: //matrix
{
Shape s; //empty Shape for scalar
Array r(s);
r.elements_[0U] = *wrap_array(a).rowwise().lpNorm<1>().maxCoeff();
return r;
}
default:
Throw() << "Norms are not avaiable for ND tensors" << "\n";
}
}

static Array max(const Array& a) {
Shape s;
Array r(s);
r.elements_[0U] = *wrap_array(flatten(a)).maxCoeff();
return r;
}

static Array min(const Array& a) {
Shape s;
Array r(s);
r.elements_[0U] = *wrap_array(flatten(a)).minCoeff();
return r;
}

static Array sum(const Array& a) {
Shape s;
Array r(s);
r.elements_[0U] = *wrap_array(flatten(a)).sum();
return r;
}

static Array cross(const Array& a, const Array& b) {
Shape a_shape(a.shape());
Shape b_shape(b.shape());
if (a_shape.size() != 1 && a_shape.size() != 2)
Throw() << "Array a of cross product has wrong dimensions";
if (b_shape.size() != 1 && b_shape.size() != 2)
Throw() << "Array b of cross product has wrong dimensions";
if (a_shape.back() != 2 && a_shape.back() != 3)
Throw() << "Array a of cross product doesn't have the right amount of elements";
if (b_shape.back() != 2 && b_shape.back() != 3)
Throw() << "Array b of cross product doesn't have the right amount of elements";

//for (MultiIdx) //TODO: Support multiple vector cross-products
//{
WrappedArray m_a = wrap_array(a);
WrappedArray m_b = wrap_array(b);

if (m_a.cols() == 1) m_a.transposeInPlace(); //col -> row
if (m_b.cols() == 1) m_b.transposeInPlace(); //col -> row

if (m_a.cols() == 2 && m_b.cols() == 3) {
m_a.conservativeResize(Eigen::NoChange, 3);
m_a(0, 2) = details::ScalarWrapper(details::ScalarNode::create_zero());
}
else if (m_b.cols() == 2 && m_a.cols() == 3) {
m_b.conservativeResize(Eigen::NoChange, 3);
m_b(0, 2) = details::ScalarWrapper(details::ScalarNode::create_zero());
}

WrappedArray cross;
if (m_a.cols() == 2 && m_b.cols() == 2) {
//cross = Eigen::Ref<const Eigen::RowVector2<details::ScalarWrapper>>(m_a).cross(Eigen::Ref<const Eigen::RowVector2<details::ScalarWrapper>>(m_b)); // Only in Eigen 5.0.0+
cross = WrappedArray(1, 1);
cross(0, 0) = (m_a(0, 0) * m_b(0, 1) - m_b(0, 0) * m_a(0, 1));
}
else {
cross = Eigen::Ref<const Eigen::RowVector3<details::ScalarWrapper>>(m_a).cross(Eigen::Ref<const Eigen::RowVector3<details::ScalarWrapper>>(m_b));
}
Array arr = unwrap_array(cross, true);
//}
return Array(arr);
}

static Array flatten(const Array &tensor) {
uint n_elements = shape_size(tensor.shape());
Shape res_shape(1, n_elements);
Expand Down
Loading