How to combine lazy evaluation with auto in C++ - c++

Some background on what I try to do:
I am trying to implement a library doing quantum mechanics. As quantum mechanics is basically just linear algebra, I'm using the armadillo linear algebra library underneath. Armadillo uses lazy evaluation to do some smart tricks with matrices, which gives a pretty good abstraction from what is actually going on and looks close to matlab code.
I want to do something similar, but I also want to be able to use auto, which is not possible with armadillo (or eigen).
I have been looking around a little, and this answer contains what I think is the typical way of implementing this: https://stackoverflow.com/a/414260/6306265
The problem with this approach is that when you write
auto C = A+B;
you get a C that is a matrix_add, not a matrix. Even if matrix_add behaves similarly enough to matrix, the fact that matrix_add contains references to A and B makes it awkward to carry around. E.g.
auto A = matrix(2,2,{0,1,0,1});
auto B = matrix(2,2,{1,0,1,0});
auto C = A+B;
C.printmatrix(); // 1,1 ; 1,1
but
auto A = matrix(2,2,{0,1,0,1});
auto B = matrix(2,2,{1,0,1,0});
auto C = A+B;
A(0,0) = 1;
C.printmatrix(); // 2,1 ; 1,1
which is counter-intuitive. As mathematically intuitive behaviour is what I want to achieve, that is a problem.
Even worse is when I do
auto sumMatrices(const matrix& A, const matrix& B)
{
return A+B;
}
which returns a matrix_add with references to local memory.
I would really like to be able to have the nice, overloaded behaviour but also be able to use auto. My idea was to make a wrapper that can hold either a reference or an instance:
template<class T>
class maybe_reference
{
public:
maybe_reference(const T& t):
ptr_(std::make_unique<T>(t)),
t_(*ptr_)
{}
maybe_reference(std::reference_wrapper<const T> t):
t_(t.get())
{}
const T& get(){return t_;}
private:
unique_ptr<T> ptr_;
const T& t_;
}
It may not be implemented exactly this way, but the general idea is to have two constructors that can be clearly distinguished to ensure that get() returns either the referenced object or the one in the unique_ptr.
Modified matrix_add:
class matrix_add {
public:
friend matrix_add operator+(const matrix& A, const matrix& B);
matrix_add(matrix_add&& other): A_(other.A_.get()), B_(other.B_.get()){}
private:
matrix_add(const matrix& A, const matrix& B): A_(std::ref(A)), B_(std::ref(B)){}
maybe_reference<matrix> A_;
maybe_reference<matrix> B_;
};
I have left out all the parts that make matrix_add behave like a matrix. The idea is to have the object refer to the outside objects A&B as long as it was constructed with A+B, but when it is move-constructed, it would own copies.
My question is basically: does this work?
I have been thinking that the move-constructor may be elided in some or all cases, which might be devastating.
Also, is there an alternative to achieve the same thing? I have been looking, but it seems that for linear algebra at least its either lazy or auto.
EDIT: Thanks to being reminded of the term "expression templates", my google search was a lot more fruitful. I found this reddit-post: https://www.reddit.com/r/cpp/comments/4puabu/news_about_operator_auto/
and the referenced papers, which allow specification of "casts" to auto. That would be the feature that really would make all of this work.

I think, your basic problem is, that lazy evaluation does not mix well with changing state. I see two possible routes out of this:
Make your matrices immutable. If you "modify" a matrix, you actually create a copy with the incorporated change, the original remains intact. This works well semantically (any math works exactly as you expect it to do), however it may incur an intolerable runtime overhead if you are setting your matrices value by value.
This allows your implementation of matrix_add to silently replace itself with a matrix object when it is evaluated, ensuring that each evaluation is only performed at most once.
Make your functions explicit. Don't create matrix_add objects that act as if they were matrices themselves, but create matrix_function objects that operate on some input matrices to yield some result. This allows you to explicitly perform the evaluation where you see fit, and to reuse the functions that you define. However, this approach will lead to a lot of additional code complexity.
I don't think it's a good idea to try to work around this problem by introducing implicit points of forced evaluation: You'll loose large parts of what can be achieved by lazy evaluation, so why bother in the first place? Just my two cents.

You could write a template function evaluate which by default is a NOP, and then overload as necessary.
#include <utility>
#include <type_traits>
struct matrix {};
struct matrix_add {
matrix operator()() const;
};
matrix_add operator + (matrix const& a, matrix const& b);
template<class T> decltype(auto) evaluate(T&& val) { return std::forward<T>(val); }
matrix evaluate(matrix_add const& lazy) { return lazy(); }
matrix evaluate(matrix_add & lazy) { return lazy(); }
matrix evaluate(matrix_add && lazy) { return lazy(); }
int main()
{
auto a = matrix();
auto b = matrix();
auto c = evaluate(a + b);
auto d = evaluate(1 + 2);
static_assert(std::is_same<decltype(c), matrix>::value, "");
static_assert(std::is_same<decltype(d), int>::value, "");
}

I will define a new operator: eager_eval, like this:
namespace lazy {
template<class T>
void eager_eval(T const volatile&)=delete;
template<class T>
struct expression {
template<class D,
std::enable_if_t<std::is_base_of<expression, std::decay_t<D>>{}, int> =0
>
friend T eager_eval( D&& d ) { return std::forward<D>(d); }
};
}
Whenever you want something to be evaluatable in an eager manner, define eager_eval in its namespace, or derive it from lazy::lazy_expression<target_type>.
So we modify your matrix_add to (A) derive from it with the lazy-produced type you want, and (B) have an operator matrix:
struct matrix_add:
lazy::expression<matrix>
{
matrix_add(matrix const& a, matrix const& b) : a(a), b(b) { }
operator matrix() && { // rvalue ref qualified as it should be.
matrix result;
// Do the addition.
return result;
}
private:
matrix const& a, b;
};
and now, anyone can do:
auto e = eager_eval( a+b );
and ADL finds the right type to eager evaluate the lazy expression to.
live example.
You could, optionally, implement a default eager_eval that returns its argument:
template<class T, class...Ts>
T eager_eval(T&& t, Ts&&...) { return std::forward<T>(t); }
then
using lazy::eager_eval;
auto x = eager_eval( 1+2 );
lets you be agnostic to the type you pass to eager_eval; if it is a type that is aware of being lazy via an eager_eval overload, it converts, and if not it does not convert.
The pack in lazy::eager_eval above is to ensure that it has the lowest priority as an overload.

with c++17 class template argument deduction, you may write
struct matrix_expr_foo {};
struct matrix_expr_bar {};
template< typename L, typename R >
struct matrix_add {
// ...
};
matrix_add<matrix_expr_foo,matrix_expr_bar> operator + (matrix_expr_foo const& a, matrix_expr_bar const& b);
template< typename T >
struct expr {
expr( T const& expr ){
// evaluate expr ( to be stored in an appropriate member )
}
// ...
};
int main()
{
auto a = matrix_expr_foo();
auto b = matrix_expr_bar();
expr c = a + b;
/* different naming ?
auto_ c = a + b;
...
*/
}
where expr is meant to act as an auto for expression templates ...

Related

Resize Eigen::Matrix resulting from CwiseUnaryOperation for automatic differentiation (AD) types

This problem is related to Workaround for resizing Eigen::Ref, however, I do not have the restriction of trying to avoid templates (in-fact, I would like to have a solution working with templates)
I'm using the the eigen library (version 3.2.9, but testet with the latest version of eigen as well with the same outcome) for some automatic differentiation (AD) calculations and came across this "bug", which is already known to the developers (see also the following bug reports: Bug report 1, Bug report 2 and Bug report 3).
TL;DR: It is not really a bug, but a generic and clean workaround would likely require some extensive work and since it is not supported by Eigen, not pursued (I guess ...). For me, I am only interested in a subset for of expression for which to get it to work (at least for now) for which there might be a acceptable workaround.
The problem is the following, consider this simplified code, where we have a fixed and dynamic matrix sized AD type
#include <Eigen/Core>
#include "unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h"
typedef Eigen::AutoDiffScalar<Eigen::Matrix<double, -1, 1>> T_dynamic;
typedef Eigen::AutoDiffScalar<Eigen::Matrix<double, 40, 1>> T_fixed;
int main() {
const T_fixed fixed = 10.0;
const T_dynamic dynamic = 100.0;
const auto result = fixed - dynamic;
return 0;
}
This works great. When we hit fixed - dynamic, Eigen will call first the overloaded operator- which looks at both left and right hand side and resizes the derivatives accordingly through the make_coherent_impl() method, which is a template specialised version of make_coherent()
template<typename OtherDerType>
inline const AutoDiffScalar<CwiseBinaryOp<internal::scalar_difference_op<Scalar>, const DerType,const typename internal::remove_all<OtherDerType>::type> >
operator-(const AutoDiffScalar<OtherDerType>& other) const
{
internal::make_coherent(m_derivatives, other.derivatives());
return AutoDiffScalar<CwiseBinaryOp<internal::scalar_difference_op<Scalar>, const DerType,const typename internal::remove_all<OtherDerType>::type> >(
m_value - other.value(),
m_derivatives - other.derivatives());
}
// resize a to match b is a.size()==0, and conversely.
template<typename A, typename B>
void make_coherent(const A& a, const B&b)
{
make_coherent_impl<A,B>::run(a.const_cast_derived(), b.const_cast_derived());
}
template<typename A_Scalar, int A_Rows, int A_Cols, int A_Options, int A_MaxRows, int A_MaxCols, typename B>
struct make_coherent_impl<Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols>, B> {
typedef Matrix<A_Scalar, A_Rows, A_Cols, A_Options, A_MaxRows, A_MaxCols> A;
static void run(A& a, B& b) {
if((A_Rows==Dynamic || A_Cols==Dynamic) && (a.size()==0))
{
a.resize(b.size());
a.setZero();
}
}
};
This works, because both types A and B are of Eigen::Matrix<...> type (there are other permutations of the make_coherent_impl() version which is omitted here).
However, consider the following slightly modified example:
#include <Eigen/Core>
#include "unsupported/Eigen/src/AutoDiff/AutoDiffScalar.h"
typedef Eigen::AutoDiffScalar<Eigen::Matrix<double, -1, 1>> T_dynamic;
typedef Eigen::AutoDiffScalar<Eigen::Matrix<double, 40, 1>> T_fixed;
int main() {
const double scalar = 1.0;
const T_fixed fixed = 10.0;
const T_dynamic dynamic = 100.0;
const auto result = dynamic * scalar - fixed * scalar;
return 0;
}
now, when we hit dynamic * scalar - fixed * scalar and go through the the make_coherent() method, we call
template<typename A, typename B>
struct make_coherent_impl {
static void run(A&, B&) {}
};
instead, as A and B are no longer of type Eigen::matrix<...> but rather a CwiseUnaryOp<Operation, DerivativeType>.
This type is again a matrix in the end and I want to resize it, but when doing so, eigen detects that it is not a matrix type and calls a no-op resize function (in the DenseBase.h), as it only allows to resize matrices and arrays (see also the function description, here the CwiseUnaryOp is an expression)
/** Only plain matrices/arrays, not expressions, may be resized; therefore the only useful resize methods are
* Matrix::resize() and Array::resize(). The present method only asserts that the new size equals the old size, and does
* nothing else.
*/
void resize(Index newSize)
{
EIGEN_ONLY_USED_FOR_DEBUG(newSize);
eigen_assert(newSize == this->size() && "DenseBase::resize() does not actually allow to resize.");
}
The partially specialised template version I am using to call the resize function is as follows
template<class UnaryOpLhs, class DerTypeLhs, class UnaryOpRhs, class DerTypeRhs>
struct make_coherent_impl<Eigen::CwiseUnaryOp<UnaryOpLhs, DerTypeLhs>, Eigen::CwiseUnaryOp<UnaryOpRhs, DerTypeRhs> >
{
typedef Eigen::CwiseUnaryOp<UnaryOpLhs, DerTypeLhs> A;
typedef Eigen::CwiseUnaryOp<UnaryOpRhs, DerTypeRhs> B;
static void run(A& a, B& b) {
if(a.size()==0 && b.size()!=0)
a.resize(b.size());
else if(b.size()==0 && a.size()!=0)
b.resize(a.size());
}
};
Is there a way to cast the CwiseUnaryOp to a matrix so we can resize it again or a different route that would achieve the same thing here? I am only showing CwiseUnaryOp here but it should work equally for CwiseBinaryOp

Sorting a vector of custom objects with std::sort [duplicate]

If I want to sort a vector of a UDT by one of two types of variables it holds, is it possible for the standard library sort to do this or do I need to write my own sort function.
For example if you had
struct MyType{
int a;
int b;
};
vector<MyType> moo;
// do stuff that pushes data back into moo
sort(moo.begin(), moo.end()) // but sort it by lowest to highest for a, not b
So is this possible using the stdlib sort? Thanks.
It is possible to use standard function if your type implements "bool operator < (...) const" and a copy constructor (compiler-generated or custom).
struct MyType {
int a;
int b;
bool operator < (const MyType& other) const {
... // a meaningful implementation for your type
}
// Copy constructor (unless it's a POD type).
MyType(const MyType &other)
: a(other.a), b(other.b) { }
// Some other form of construction apart from copy constructor.
MyType()
: a(0), b(0) { }
};
Alternatively, you can pass an ordering function (or a functor) as a third argument to sort() instead of implementing operator "<".
bool type_is_less(const MyType& t1, const MyType& t2) { ... }
...
std::sort(c.begin(), c.end(), type_is_less);
This is useful in the following situations:
you don't want to implement operator "<" for whatever reason,
you need to sort a container of built-in or pointer types for which you can't overload operators.
you wish to sort the sequence using different orderings. ex: sometimes you want a struct with first/last name members sorted by first name, other times by last name. two different functions (or functors) make such options trivial.
There's three ways to do this:
You could overload operator< for your class:
bool operator<(const MyType& lhs, const MyType& rhs) {return lhs.a<rhs.a;}
This has the disadvantage that, if you ever want to sort them according to b, you're out of luck.
You could also specialize std::less for your type. That makes std::sort working (and other things, like using the type as a key in a map) without hijacking operator< for this meaning. It does, however, still hijack a general-purpose comparison syntax for a, while you might, at other places in your code, compare your type according to b.
Or you could write your own comparator like this:
struct compare_by_a {
bool operator()(const MyType& lhs, const MyType& rhs) const
{return lhs.a<rhs.a;}
};
(Note: The const after the operator isn't strictly necessary. I still consider it good style, though.) This leaves the general-purpose means of comparison undefined; so if some code wants to use them without you being aware, the compile emits an error and makes you aware of it. You can use this or other comparators selectively and explicitly where ever you need comparison.
Nowadays, with C++ 20, you can use:
universal initializers
designated initializers
sort function from ranges library
projections
structured bindings
Then, life will be simpler.
Please see:
#include <vector>
#include <algorithm>
namespace rng = std::ranges;
// Some demo type
struct MyType {
int a{};
int b{};
};
int main () {
// Test data
std::vector<MyType> data{ {.b = 5}, {.b = 4}, {.b = 3}, {.b = 2}, {.b = 1} };
// Sort it for b
rng::sort(data, {}, &MyType::b);
// Debug output
for (const auto& [a, b] : data) std::cout << a << '\t' << b << '\n';
}

how to store the logical relationship

I want to figure out a solution for automatic logical relationship check. For example, I have a function IsGood(), it will get the bool value from a, b, c .... In the main program, there is if(a||b) or if(b&&c) or if(g&&!k&&l||!z), different relationship. I want to replace all of them with IsGood(), and I want to make this function more general, it can handle different logical relationship.
So my idea is to put some ID, which will help this function to know which variables are required to handle now, for example, IsGood() got value k1,k2,k3, but the logical relationship ||,&& between k1,k2,k3 are not known by IsGood().
So I want to know how to let IsGood() automatically get the relationship between values. Store them in database??
Like : IsGood() firstly check that it is in the place1, so it queries the database, the result is : (this why I don't take parameters in IsGood(), it will retrieve the variables it needs from database or configuration file, what it needs is only the placeID.)
place 1 (the place number); k1,k2,k3 (variable name); true,true,false(value); &&, || (logical relationship).
But I don't think it is good...So, could you give me some ideas? Thanks a lot! My work is based on C++.
I want to know some ideas about this :
a||b&&c, I can store the information, like 0,1, so 0 represents ||, 1 represents &&, so the structure like a&&b||c...is easy to control.
But how to set (a||b)&&c? I also want to find a way to record this relationship. A smart method will be appreciated!! Thanks.
This can't work. Period.
In C++, variables have scope. The name k1 may mean different things in different places. Therefore, even if the function IsGood magically knew that it somehow should access a variable named k1, it still has no way whatsoever to figure out which k1 from which scope that would be.
This is not a big deal for C++ programmers. Their solution: IsGood(k1), which means: call IsGood with this k1 variable from the current scope, and not another.
Now, passing operators is a bit harder. You need lambda's for that: IsGood( [&k1,&k2,&k3](){return (k1&&k2)||k3;} );. This takes a reference to the variables k1-3, and passes the expression (k1&&k2)||k3; to IsGood. Or in two lines:
auto myLambda = [&k1,&k2,&k3](){return (k1&&k2)||k3;} ;
IsGood(myLambda);
Again, this all works because you pass IsGood the information it needs. It can't get it any other way.
I would first start off by defining a set of logical operations that work on a given object, for example:
// This is just a simple wrapper for the first argument
template <typename T>
struct FirstOp
{
FirstOp(T const& v) : _v(v)
{ }
T const & operator*() const { return _v; }
T const& _v;
};
template <typename T>
struct AndOp
{
AndOp(T const& v) : _v(v)
{ }
T const & operator*() const { return _v; }
// Then hack the stream operator
template <typename O>
O const & operator>>(O const & o) const
{
if (o)
o = o && _v; // assumes T supports safe bool
return o;
}
T const& _v;
};
template <typename T>
struct OrOp
{
OrOp(T const& v) : _v(v)
{ }
T const& operator*() const { return _v; }
// Then hack the stream operator
template <typename O>
O const & operator>>(O const & o) const
{
if (!o)
o = o || _v; // assumes T supports safe bool
return o;
}
T const& _v;
};
template <typename Op1>
struct ResultOf
{
ResultOf(Op1 const& cOp) : _o1(cOp), _r(*_o1)
{ }
ResultOf const & operator=(bool r) const
{ _r = r; return *this; }
operator bool() const { return _r; }
// Then hack the stream operator
template <typename O>
ResultOf& operator>>(O& o)
{
o >> *this;
return *this;
}
Op1 const& _o1;
mutable bool _r;
};
Then define a IsGood to accept parameters, overload to support more parameters.
template <typename T1, typename T2>
bool IsGood(T1 const& t1, T2 const& t2)
{
return ResultOf<T1>(t1) >> t2;
}
Then you can call as follows.
int main(void)
{
std::cout << IsGood(FirstOp<int>(0), OrOp<int>(1)) << std::endl;
}
So what this approach has allowed you to do is to wrap the value that you want to use for a specific logical operation with that operation and then pass it to the generic IsGood function. Now here, the actual operators that are constructed is hard-coded, but there is nothing that prevents you reading this from a file for example and then constructing the appropriate operators to pass to IsGood. NOTE: The above is short-circuiting, so will only evaluate the arguments as necessary (function calls will be made), but expressions will not be evaluated. You should be able to use the above approach to make arbitrarily complex logical relationships.
DISCLAIMER: This is my limited understanding of your problem... if it's off the mark, ah well...

Standard library sort and user defined types

If I want to sort a vector of a UDT by one of two types of variables it holds, is it possible for the standard library sort to do this or do I need to write my own sort function.
For example if you had
struct MyType{
int a;
int b;
};
vector<MyType> moo;
// do stuff that pushes data back into moo
sort(moo.begin(), moo.end()) // but sort it by lowest to highest for a, not b
So is this possible using the stdlib sort? Thanks.
It is possible to use standard function if your type implements "bool operator < (...) const" and a copy constructor (compiler-generated or custom).
struct MyType {
int a;
int b;
bool operator < (const MyType& other) const {
... // a meaningful implementation for your type
}
// Copy constructor (unless it's a POD type).
MyType(const MyType &other)
: a(other.a), b(other.b) { }
// Some other form of construction apart from copy constructor.
MyType()
: a(0), b(0) { }
};
Alternatively, you can pass an ordering function (or a functor) as a third argument to sort() instead of implementing operator "<".
bool type_is_less(const MyType& t1, const MyType& t2) { ... }
...
std::sort(c.begin(), c.end(), type_is_less);
This is useful in the following situations:
you don't want to implement operator "<" for whatever reason,
you need to sort a container of built-in or pointer types for which you can't overload operators.
you wish to sort the sequence using different orderings. ex: sometimes you want a struct with first/last name members sorted by first name, other times by last name. two different functions (or functors) make such options trivial.
There's three ways to do this:
You could overload operator< for your class:
bool operator<(const MyType& lhs, const MyType& rhs) {return lhs.a<rhs.a;}
This has the disadvantage that, if you ever want to sort them according to b, you're out of luck.
You could also specialize std::less for your type. That makes std::sort working (and other things, like using the type as a key in a map) without hijacking operator< for this meaning. It does, however, still hijack a general-purpose comparison syntax for a, while you might, at other places in your code, compare your type according to b.
Or you could write your own comparator like this:
struct compare_by_a {
bool operator()(const MyType& lhs, const MyType& rhs) const
{return lhs.a<rhs.a;}
};
(Note: The const after the operator isn't strictly necessary. I still consider it good style, though.) This leaves the general-purpose means of comparison undefined; so if some code wants to use them without you being aware, the compile emits an error and makes you aware of it. You can use this or other comparators selectively and explicitly where ever you need comparison.
Nowadays, with C++ 20, you can use:
universal initializers
designated initializers
sort function from ranges library
projections
structured bindings
Then, life will be simpler.
Please see:
#include <vector>
#include <algorithm>
namespace rng = std::ranges;
// Some demo type
struct MyType {
int a{};
int b{};
};
int main () {
// Test data
std::vector<MyType> data{ {.b = 5}, {.b = 4}, {.b = 3}, {.b = 2}, {.b = 1} };
// Sort it for b
rng::sort(data, {}, &MyType::b);
// Debug output
for (const auto& [a, b] : data) std::cout << a << '\t' << b << '\n';
}

Lazy evaluation in C++

C++ does not have native support for lazy evaluation (as Haskell does).
I'm wondering if it is possible to implement lazy evaluation in C++ in a reasonable manner. If yes, how would you do it?
EDIT: I like Konrad Rudolph's answer.
I'm wondering if it's possible to implement it in a more generic fashion, for example by using a parametrized class lazy that essentially works for T the way matrix_add works for matrix.
Any operation on T would return lazy instead. The only problem is to store the arguments and operation code inside lazy itself. Can anyone see how to improve this?
I'm wondering if it is possible to implement lazy evaluation in C++ in a reasonable manner. If yes, how would you do it?
Yes, this is possible and quite often done, e.g. for matrix calculations. The main mechanism to facilitate this is operator overloading. Consider the case of matrix addition. The signature of the function would usually look something like this:
matrix operator +(matrix const& a, matrix const& b);
Now, to make this function lazy, it's enough to return a proxy instead of the actual result:
struct matrix_add;
matrix_add operator +(matrix const& a, matrix const& b) {
return matrix_add(a, b);
}
Now all that needs to be done is to write this proxy:
struct matrix_add {
matrix_add(matrix const& a, matrix const& b) : a(a), b(b) { }
operator matrix() const {
matrix result;
// Do the addition.
return result;
}
private:
matrix const& a, b;
};
The magic lies in the method operator matrix() which is an implicit conversion operator from matrix_add to plain matrix. This way, you can chain multiple operations (by providing appropriate overloads of course). The evaluation takes place only when the final result is assigned to a matrix instance.
EDIT I should have been more explicit. As it is, the code makes no sense because although evaluation happens lazily, it still happens in the same expression. In particular, another addition will evaluate this code unless the matrix_add structure is changed to allow chained addition. C++0x greatly facilitates this by allowing variadic templates (i.e. template lists of variable length).
However, one very simple case where this code would actually have a real, direct benefit is the following:
int value = (A + B)(2, 3);
Here, it is assumed that A and B are two-dimensional matrices and that dereferencing is done in Fortran notation, i.e. the above calculates one element out of a matrix sum. It's of course wasteful to add the whole matrices. matrix_add to the rescue:
struct matrix_add {
// … yadda, yadda, yadda …
int operator ()(unsigned int x, unsigned int y) {
// Calculate *just one* element:
return a(x, y) + b(x, y);
}
};
Other examples abound. I've just remembered that I have implemented something related not long ago. Basically, I had to implement a string class that should adhere to a fixed, pre-defined interface. However, my particular string class dealt with huge strings that weren't actually stored in memory. Usually, the user would just access small substrings from the original string using a function infix. I overloaded this function for my string type to return a proxy that held a reference to my string, along with the desired start and end position. Only when this substring was actually used did it query a C API to retrieve this portion of the string.
Boost.Lambda is very nice, but Boost.Proto is exactly what you are looking for. It already has overloads of all C++ operators, which by default perform their usual function when proto::eval() is called, but can be changed.
What Konrad already explained can be put further to support nested invocations of operators, all executed lazily. In Konrad's example, he has an expression object that can store exactly two arguments, for exactly two operands of one operation. The problem is that it will only execute one subexpression lazily, which nicely explains the concept in lazy evaluation put in simple terms, but doesn't improve performance substantially. The other example shows also well how one can apply operator() to add only some elements using that expression object. But to evaluate arbitrary complex expressions, we need some mechanism that can store the structure of that too. We can't get around templates to do that. And the name for that is expression templates. The idea is that one templated expression object can store the structure of some arbitrary sub-expression recursively, like a tree, where the operations are the nodes, and the operands are the child-nodes. For a very good explanation i just found today (some days after i wrote the below code) see here.
template<typename Lhs, typename Rhs>
struct AddOp {
Lhs const& lhs;
Rhs const& rhs;
AddOp(Lhs const& lhs, Rhs const& rhs):lhs(lhs), rhs(rhs) {
// empty body
}
Lhs const& get_lhs() const { return lhs; }
Rhs const& get_rhs() const { return rhs; }
};
That will store any addition operation, even nested one, as can be seen by the following definition of an operator+ for a simple point type:
struct Point { int x, y; };
// add expression template with point at the right
template<typename Lhs, typename Rhs> AddOp<AddOp<Lhs, Rhs>, Point>
operator+(AddOp<Lhs, Rhs> const& lhs, Point const& p) {
return AddOp<AddOp<Lhs, Rhs>, Point>(lhs, p);
}
// add expression template with point at the left
template<typename Lhs, typename Rhs> AddOp< Point, AddOp<Lhs, Rhs> >
operator+(Point const& p, AddOp<Lhs, Rhs> const& rhs) {
return AddOp< Point, AddOp<Lhs, Rhs> >(p, rhs);
}
// add two points, yield a expression template
AddOp< Point, Point >
operator+(Point const& lhs, Point const& rhs) {
return AddOp<Point, Point>(lhs, rhs);
}
Now, if you have
Point p1 = { 1, 2 }, p2 = { 3, 4 }, p3 = { 5, 6 };
p1 + (p2 + p3); // returns AddOp< Point, AddOp<Point, Point> >
You now just need to overload operator= and add a suitable constructor for the Point type and accept AddOp. Change its definition to:
struct Point {
int x, y;
Point(int x = 0, int y = 0):x(x), y(y) { }
template<typename Lhs, typename Rhs>
Point(AddOp<Lhs, Rhs> const& op) {
x = op.get_x();
y = op.get_y();
}
template<typename Lhs, typename Rhs>
Point& operator=(AddOp<Lhs, Rhs> const& op) {
x = op.get_x();
y = op.get_y();
return *this;
}
int get_x() const { return x; }
int get_y() const { return y; }
};
And add the appropriate get_x and get_y into AddOp as member functions:
int get_x() const {
return lhs.get_x() + rhs.get_x();
}
int get_y() const {
return lhs.get_y() + rhs.get_y();
}
Note how we haven't created any temporaries of type Point. It could have been a big matrix with many fields. But at the time the result is needed, we calculate it lazily.
I have nothing to add to Konrad's post, but you can look at Eigen for an example of lazy evaluation done right, in a real world app. It is pretty awe inspiring.
I'm thinking about implementing a template class, that uses std::function. The class should, more or less, look like this:
template <typename Value>
class Lazy
{
public:
Lazy(std::function<Value()> function) : _function(function), _evaluated(false) {}
Value &operator*() { Evaluate(); return _value; }
Value *operator->() { Evaluate(); return &_value; }
private:
void Evaluate()
{
if (!_evaluated)
{
_value = _function();
_evaluated = true;
}
}
std::function<Value()> _function;
Value _value;
bool _evaluated;
};
For example usage:
class Noisy
{
public:
Noisy(int i = 0) : _i(i)
{
std::cout << "Noisy(" << _i << ")" << std::endl;
}
Noisy(const Noisy &that) : _i(that._i)
{
std::cout << "Noisy(const Noisy &)" << std::endl;
}
~Noisy()
{
std::cout << "~Noisy(" << _i << ")" << std::endl;
}
void MakeNoise()
{
std::cout << "MakeNoise(" << _i << ")" << std::endl;
}
private:
int _i;
};
int main()
{
Lazy<Noisy> n = [] () { return Noisy(10); };
std::cout << "about to make noise" << std::endl;
n->MakeNoise();
(*n).MakeNoise();
auto &nn = *n;
nn.MakeNoise();
}
Above code should produce the following message on the console:
Noisy(0)
about to make noise
Noisy(10)
~Noisy(10)
MakeNoise(10)
MakeNoise(10)
MakeNoise(10)
~Noisy(10)
Note that the constructor printing Noisy(10) will not be called until the variable is accessed.
This class is far from perfect, though. The first thing would be the default constructor of Value will have to be called on member initialization (printing Noisy(0) in this case). We can use pointer for _value instead, but I'm not sure whether it would affect the performance.
Johannes' answer works.But when it comes to more parentheses ,it doesn't work as wish. Here is an example.
Point p1 = { 1, 2 }, p2 = { 3, 4 }, p3 = { 5, 6 }, p4 = { 7, 8 };
(p1 + p2) + (p3+p4)// it works ,but not lazy enough
Because the three overloaded + operator didn't cover the case
AddOp<Llhs,Lrhs>+AddOp<Rlhs,Rrhs>
So the compiler has to convert either (p1+p2) or(p3+p4) to Point ,that's not lazy enough.And when compiler decides which to convert ,it complains. Because none is better than the other .
Here comes my extension: add yet another overloaded operator +
template <typename LLhs, typename LRhs, typename RLhs, typename RRhs>
AddOp<AddOp<LLhs, LRhs>, AddOp<RLhs, RRhs>> operator+(const AddOp<LLhs, LRhs> & leftOperandconst, const AddOp<RLhs, RRhs> & rightOperand)
{
return AddOp<AddOp<LLhs, LRhs>, AddOp<RLhs, RRhs>>(leftOperandconst, rightOperand);
}
Now ,the compiler can handle the case above correctly ,and no implicit conversion ,volia!
As it's going to be done in C++0x, by lambda expressions.
Anything is possible.
It depends on exactly what you mean:
class X
{
public: static X& getObjectA()
{
static X instanceA;
return instanceA;
}
};
Here we have the affect of a global variable that is lazily evaluated at the point of first use.
As newly requested in the question.
And stealing Konrad Rudolph design and extending it.
The Lazy object:
template<typename O,typename T1,typename T2>
struct Lazy
{
Lazy(T1 const& l,T2 const& r)
:lhs(l),rhs(r) {}
typedef typename O::Result Result;
operator Result() const
{
O op;
return op(lhs,rhs);
}
private:
T1 const& lhs;
T2 const& rhs;
};
How to use it:
namespace M
{
class Matrix
{
};
struct MatrixAdd
{
typedef Matrix Result;
Result operator()(Matrix const& lhs,Matrix const& rhs) const
{
Result r;
return r;
}
};
struct MatrixSub
{
typedef Matrix Result;
Result operator()(Matrix const& lhs,Matrix const& rhs) const
{
Result r;
return r;
}
};
template<typename T1,typename T2>
Lazy<MatrixAdd,T1,T2> operator+(T1 const& lhs,T2 const& rhs)
{
return Lazy<MatrixAdd,T1,T2>(lhs,rhs);
}
template<typename T1,typename T2>
Lazy<MatrixSub,T1,T2> operator-(T1 const& lhs,T2 const& rhs)
{
return Lazy<MatrixSub,T1,T2>(lhs,rhs);
}
}
In C++11 lazy evaluation similar to hiapay's answer can be achieved using std::shared_future. You still have to encapsulate calculations in lambdas but memoization is taken care of:
std::shared_future<int> a = std::async(std::launch::deferred, [](){ return 1+1; });
Here's a full example:
#include <iostream>
#include <future>
#define LAZY(EXPR, ...) std::async(std::launch::deferred, [__VA_ARGS__](){ std::cout << "evaluating "#EXPR << std::endl; return EXPR; })
int main() {
std::shared_future<int> f1 = LAZY(8);
std::shared_future<int> f2 = LAZY(2);
std::shared_future<int> f3 = LAZY(f1.get() * f2.get(), f1, f2);
std::cout << "f3 = " << f3.get() << std::endl;
std::cout << "f2 = " << f2.get() << std::endl;
std::cout << "f1 = " << f1.get() << std::endl;
return 0;
}
C++0x is nice and all.... but for those of us living in the present you have Boost lambda library and Boost Phoenix. Both with the intent of bringing large amounts of functional programming to C++.
Lets take Haskell as our inspiration - it being lazy to the core.
Also, let's keep in mind how Linq in C# uses Enumerators in a monadic (urgh - here is the word - sorry) way.
Last not least, lets keep in mind, what coroutines are supposed to provide to programmers. Namely the decoupling of computational steps (e.g. producer consumer) from each other.
And lets try to think about how coroutines relate to lazy evaluation.
All of the above appears to be somehow related.
Next, lets try to extract our personal definition of what "lazy" comes down to.
One interpretation is: We want to state our computation in a composable way, before executing it. Some of those parts we use to compose our complete solution might very well draw upon huge (sometimes infinite) data sources, with our full computation also either producing a finite or infinite result.
Lets get concrete and into some code. We need an example for that! Here, I choose the fizzbuzz "problem" as an example, just for the reason that there is some nice, lazy solution to it.
In Haskell, it looks like this:
module FizzBuzz
( fb
)
where
fb n =
fmap merge fizzBuzzAndNumbers
where
fizz = cycle ["","","fizz"]
buzz = cycle ["","","","","buzz"]
fizzBuzz = zipWith (++) fizz buzz
fizzBuzzAndNumbers = zip [1..n] fizzBuzz
merge (x,s) = if length s == 0 then show x else s
The Haskell function cycle creates an infinite list (lazy, of course!) from a finite list by simply repeating the values in the finite list forever. In an eager programming style, writing something like that would ring alarm bells (memory overflow, endless loops!). But not so in a lazy language. The trick is, that lazy lists are not computed right away. Maybe never. Normally only as much as subsequent code requires it.
The third line in the where block above creates another lazy!! list, by means of combining the infinite lists fizz and buzz by means of the single two elements recipe "concatenate a string element from either input list into a single string". Again, if this were to be immediately evaluated, we would have to wait for our computer to run out of resources.
In the 4th line, we create tuples of the members of a finite lazy list [1..n] with our infinite lazy list fizzbuzz. The result is still lazy.
Even in the main body of our fb function, there is no need to get eager. The whole function returns a list with the solution, which itself is -again- lazy. You could as well think of the result of fb 50 as a computation which you can (partially) evaluate later. Or combine with other stuff, leading to an even larger (lazy) evaluation.
So, in order to get started with our C++ version of "fizzbuzz", we need to think of ways how to combine partial steps of our computation into larger bits of computations, each drawing data from previous steps as required.
You can see the full story in a gist of mine.
Here the basic ideas behind the code:
Borrowing from C# and Linq, we "invent" a stateful, generic type Enumerator, which holds
- The current value of the partial computation
- The state of a partial computation (so we can produce subsequent values)
- The worker function, which produces the next state, the next value and a bool which states if there is more data or if the enumeration has come to an end.
In order to be able to compose Enumerator<T,S> instance by means of the power of the . (dot), this class also contains functions, borrowed from Haskell type classes such as Functor and Applicative.
The worker function for enumerator is always of the form: S -> std::tuple<bool,S,T where S is the generic type variable representing the state and T is the generic type variable representing a value - the result of a computation step.
All this is already visible in the first lines of the Enumerator class definition.
template <class T, class S>
class Enumerator
{
public:
typedef typename S State_t;
typedef typename T Value_t;
typedef std::function<
std::tuple<bool, State_t, Value_t>
(const State_t&
)
> Worker_t;
Enumerator(Worker_t worker, State_t s0)
: m_worker(worker)
, m_state(s0)
, m_value{}
{
}
// ...
};
So, all we need to create a specific enumerator instance, we need to create a worker function, have the initial state and create an instance of Enumerator with those two arguments.
Here an example - function range(first,last) creates a finite range of values. This corresponds to a lazy list in the Haskell world.
template <class T>
Enumerator<T, T> range(const T& first, const T& last)
{
auto finiteRange =
[first, last](const T& state)
{
T v = state;
T s1 = (state < last) ? (state + 1) : state;
bool active = state != s1;
return std::make_tuple(active, s1, v);
};
return Enumerator<T,T>(finiteRange, first);
}
And we can make use of this function, for example like this: auto r1 = range(size_t{1},10); - We have created ourselves a lazy list with 10 elements!
Now, all is missing for our "wow" experience, is to see how we can compose enumerators.
Coming back to Haskells cycle function, which is kind of cool. How would it look in our C++ world? Here it is:
template <class T, class S>
auto
cycle
( Enumerator<T, S> values
) -> Enumerator<T, S>
{
auto eternally =
[values](const S& state) -> std::tuple<bool, S, T>
{
auto[active, s1, v] = values.step(state);
if (active)
{
return std::make_tuple(active, s1, v);
}
else
{
return std::make_tuple(true, values.state(), v);
}
};
return Enumerator<T, S>(eternally, values.state());
}
It takes an enumerator as input and returns an enumerator. Local (lambda) function eternally simply resets the input enumeration to its start value whenever it runs out of values and voilà - we have an infinite, ever repeating version of the list we gave as an argument:: auto foo = cycle(range(size_t{1},3)); And we can already shamelessly compose our lazy "computations".
zip is a good example, showing that we can also create a new enumerator from two input enumerators. The resulting enumerator yields as many values as the smaller of either of the input enumerators (tuples with 2 element, one for each input enumerator). I have implemented zip inside class Enumerator itself. Here is how it looks like:
// member function of class Enumerator<S,T>
template <class T1, class S1>
auto
zip
( Enumerator<T1, S1> other
) -> Enumerator<std::tuple<T, T1>, std::tuple<S, S1> >
{
auto worker0 = this->m_worker;
auto worker1 = other.worker();
auto combine =
[worker0,worker1](std::tuple<S, S1> state) ->
std::tuple<bool, std::tuple<S, S1>, std::tuple<T, T1> >
{
auto[s0, s1] = state;
auto[active0, newS0, v0] = worker0(s0);
auto[active1, newS1, v1] = worker1(s1);
return std::make_tuple
( active0 && active1
, std::make_tuple(newS0, newS1)
, std::make_tuple(v0, v1)
);
};
return Enumerator<std::tuple<T, T1>, std::tuple<S, S1> >
( combine
, std::make_tuple(m_state, other.state())
);
}
Please note, how the "combining" also ends up in combining the state of both sources and the values of both sources.
As this post is already TL;DR; for many, here the...
Summary
Yes, lazy evaluation can be implemented in C++. Here, I did it by borrowing the function names from haskell and the paradigm from C# enumerators and Linq. There might be similarities to pythons itertools, btw. I think they followed a similar approach.
My implementation (see the gist link above) is just a prototype - not production code, btw. So no warranties whatsoever from my side. It serves well as demo code to get the general idea across, though.
And what would this answer be without the final C++ version of fizzbuz, eh? Here it is:
std::string fizzbuzz(size_t n)
{
typedef std::vector<std::string> SVec;
// merge (x,s) = if length s == 0 then show x else s
auto merge =
[](const std::tuple<size_t, std::string> & value)
-> std::string
{
auto[x, s] = value;
if (s.length() > 0) return s;
else return std::to_string(x);
};
SVec fizzes{ "","","fizz" };
SVec buzzes{ "","","","","buzz" };
return
range(size_t{ 1 }, n)
.zip
( cycle(iterRange(fizzes.cbegin(), fizzes.cend()))
.zipWith
( std::function(concatStrings)
, cycle(iterRange(buzzes.cbegin(), buzzes.cend()))
)
)
.map<std::string>(merge)
.statefulFold<std::ostringstream&>
(
[](std::ostringstream& oss, const std::string& s)
{
if (0 == oss.tellp())
{
oss << s;
}
else
{
oss << "," << s;
}
}
, std::ostringstream()
)
.str();
}
And... to drive the point home even further - here a variation of fizzbuzz which returns an "infinite list" to the caller:
typedef std::vector<std::string> SVec;
static const SVec fizzes{ "","","fizz" };
static const SVec buzzes{ "","","","","buzz" };
auto fizzbuzzInfinite() -> decltype(auto)
{
// merge (x,s) = if length s == 0 then show x else s
auto merge =
[](const std::tuple<size_t, std::string> & value)
-> std::string
{
auto[x, s] = value;
if (s.length() > 0) return s;
else return std::to_string(x);
};
auto result =
range(size_t{ 1 })
.zip
(cycle(iterRange(fizzes.cbegin(), fizzes.cend()))
.zipWith
(std::function(concatStrings)
, cycle(iterRange(buzzes.cbegin(), buzzes.cend()))
)
)
.map<std::string>(merge)
;
return result;
}
It is worth showing, since you can learn from it how to dodge the question what the exact return type of that function is (as it depends on the implementation of the function alone, namely how the code combines the enumerators).
Also it demonstrates that we had to move the vectors fizzes and buzzes outside the scope of the function so they are still around when eventually on the outside, the lazy mechanism produces values. If we had not done that, the iterRange(..) code would have stored iterators to the vectors which are long gone.
Using a very simple definition of lazy evaluation, which is the value is not evaluated until needed, I would say that one could implement this through the use of a pointer and macros (for syntax sugar).
#include <stdatomic.h>
#define lazy(var_type) lazy_ ## var_type
#define def_lazy_type( var_type ) \
typedef _Atomic var_type _atomic_ ## var_type; \
typedef _atomic_ ## var_type * lazy(var_type); //pointer to atomic type
#define def_lazy_variable(var_type, var_name ) \
_atomic_ ## var_type _ ## var_name; \
lazy_ ## var_type var_name = & _ ## var_name;
#define assign_lazy( var_name, val ) atomic_store( & _ ## var_name, val )
#define eval_lazy(var_name) atomic_load( &(*var_name) )
#include <stdio.h>
def_lazy_type(int)
void print_power2 ( lazy(int) i )
{
printf( "%d\n", eval_lazy(i) * eval_lazy(i) );
}
typedef struct {
int a;
} simple;
def_lazy_type(simple)
void print_simple ( lazy(simple) s )
{
simple temp = eval_lazy(s);
printf("%d\n", temp.a );
}
#define def_lazy_array1( var_type, nElements, var_name ) \
_atomic_ ## var_type _ ## var_name [ nElements ]; \
lazy(var_type) var_name = _ ## var_name;
int main ( )
{
//declarations
def_lazy_variable( int, X )
def_lazy_variable( simple, Y)
def_lazy_array1(int,10,Z)
simple new_simple;
//first the lazy int
assign_lazy(X,111);
print_power2(X);
//second the lazy struct
new_simple.a = 555;
assign_lazy(Y,new_simple);
print_simple ( Y );
//third the array of lazy ints
for(int i=0; i < 10; i++)
{
assign_lazy( Z[i], i );
}
for(int i=0; i < 10; i++)
{
int r = eval_lazy( &Z[i] ); //must pass with &
printf("%d\n", r );
}
return 0;
}
You'll notice in the function print_power2 there is a macro called eval_lazy which does nothing more than dereference a pointer to get the value just prior to when it's actually needed. The lazy type is accessed atomically, so it's completely thread-safe.