GithubHelp home page GithubHelp logo

blitzpp / blitz Goto Github PK

View Code? Open in Web Editor NEW
397.0 29.0 83.0 20.04 MB

Blitz++ Multi-Dimensional Array Library for C++

Home Page: https://github.com/blitzpp/blitz/wiki

License: Other

C++ 71.16% Fortran 2.26% Forth 0.04% MATLAB 0.07% Shell 0.38% C 3.44% Python 2.83% HTML 12.18% TeX 0.36% M4 0.03% Roff 6.18% CMake 1.07%
blitz array-manipulations tensor array vector cpp-library scientific-computing high-performance hpc template-metaprogramming

blitz's Introduction

Github Actions Build Status Windows Build status

IMPORTANT NOTICE

Blitz++ written for the C++98 standard, and is not able to make use of the substantial benefits that came with C++11. Although it works as well as ever, as of 2024, Blitz++ is thoroughly obsolete, which results in a number of annoyances when using it in modern C++ code.

In the meantime, Fortran-90 / NumPy style arrays have received high-level thought in the C++ Standards community, resulting in std::mdspan. I highly recommend anyone starting a new project to consider this alternative before using Blitz++. MDSpan is part of C++23 and in theory should be supported by popular compilers "out of the box." If your C++ compiler does not (yet) support MDSpan, I would try using the publicly available Reference Implemenation. Here is more information on MDSpan:

Blitz++ has not received new features for many years, and will not going forward either. However, it is likely to be required for many years by a number of existing projects, and is provided here for users and developers of those projects.

Overview

Blitz++ is a C++ template class library that provides high-performance multidimensional array containers for scientific computing.

Blitz++ has gone through some changes in location:

  1. The original Blitz++ website was located at http://oonumerics.org/blitz (archived at http://www.math.unipd.it/~michela/OP.htm).

  2. Blitz++ then moved to SourceForge, at http://www.sourceforge.net/projects/blitz.

  3. The latest maintained version of Blitz++ is now on GitHub, at https://github.com/blitzpp/blitz

Diverse information on Blitz++ is now being catalogued at the GitHub wiki: http://github.com/blitzpp/blitz/wiki/

Licensing information is detailed in the LEGAL file. Summary: you can do anything except sell this library in source form. Blitz is licensed under either the Lesser GPL version 3 license (see COPYING and COPYING.LESSER), the BSD license (see COPYRIGHT), and the less restrictive Perl "artistic license" version 2.0 (see LICENSE).

Blitz++ uses CMake for build, test and installation automation. For details on using CMake consult https://cmake.org/documentation/ In short, the following steps should work on UNIX-like systems:

  mkdir build
  cd build
  cmake ..
  make lib
  sudo make install

On Windows try:

  md build
  cd build
  cmake ..
  cmake --build . --config Release
  cmake --build . --target install

blitz's People

Contributors

citibeth avatar herveancher avatar jgmbenoit avatar papadop avatar pbertoni89 avatar roshansamuel avatar slayoo avatar toddrme2178 avatar tunalobster avatar wperkins avatar ylep avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

blitz's Issues

New Blitz11 Project

@slayoo @tobias-loew @vukics

Blitz++ is great, but let's face it... it's an old codebase from the pre-C++11 era, and has a lot of weird hacks / workarounds. It does what it does well, and has been quite stable. BUT...

  1. It is looking increasingly dated in the days of C++11
  2. The original authors are long gone
  3. The build and unit tests are a mess
  4. Alterations could break things, negating one of Blitz++'s current good features (its stability)

I would like to see if we can build a new Blitz for C++11, which I'm calling Blitz11. The singluar focus would be to build a great multi-dimensional array package for C++11. None of the other features of Blitz++ would be ported or reimplemented. And we would not worry about compilers pre-C++11. Once we get it working well, we can shop it around to see if any of Boost, Eigen, etc. might be interested in incorporating into their larger system. We would use CMake to build and Google Test to write tests.

I'm currently collecting requirements and building prototypes. Requirements I've identified so far are: (please add to this list):

Necessary Features

  1. Arrays are fully C++ compliant, can be held in standard C++ collections. Can be included in larger structs without having to write custom move constructors / assignment for those structs.
  2. Array unnderlying memory is either: (a) a shared ptr, or (b) borrowed. Both variants have the same top-level type. When new arrays are constructed from an old array, the new array shares or borrows, according to how the old arrya did it.
  3. Handles const correctly.
  4. Array layout is fully configurable: any base, any stride (even negative), any dimension order.
  5. Full complement of array slicing, reshaping, etc. Must include reduction of dimension.

Nice-To-Have Features

  1. Shared memory blocks may be used, managed, loaded, saved, etc. separately from any particular Array used to access them.
  2. The dope vector (array layout) is accessible as a first-class object. Dope vectors may be copied, manipulated and used to construct new Arrays.
  3. Bounds checking. Controlled by a template parameter. A global (compile-time) parameter can also be used to turn off all bounds checking.
  4. Bounds errors reported in a way that can generate a stacktrace.
  5. Allows to write code that can work with an any-dimension Array. This mode of access is not expected to be fast.
  6. Vectorized operations, lazy evaluation magic, etc. as in Eigen::Tensor, Blitz++, etc. This is a cool feature, and it is well known how to implement. But it is not essential. Initial design should be built in a way to not PRECLUDE these features from begin efficiently added in the future.
  7. Support ultra-long dimensions (>4 billion extent in a dimension)
  8. Support inter-process shared memory arrays (eg. boost::interprocess).

The current prototype is focused on UI and logical design. It is not expected to be fast. I believe that others here have better experience with optimizations, variadic templates, etc.

Any thoughts? Any opinions on licensing? Please see my current prototype:
https://github.com/blitzpp/b11/blob/master/slib/b11/array.hpp

indirection example in section 6.1 of the manual does not compile

Migrated from: https://sourceforge.net/p/blitz/bugs/58/

The manual includes the following code in section 6.1:

Array<int,1> A(5), B(5);
A = 0;
B = 1, 2, 3, 4, 5;
vector<int> I;
I.push_back(2);
I.push_back(4);
I.push_back(1);
A[I] = B;

It fails to compile with current Blitz with the following error:

/usr/include/blitz/array/indirect.h:95:10: error: no matching member function for call to 'moveTo'
expr.moveTo(subdomain);
~~~~~^~~~~~
/usr/include/blitz/array/indirect.h:79:9: note: in instantiation of function template specialization
'blitz::applyOverSubdomain<blitz::Array<int, 1="">, blitz::FastArrayIterator<int, 1="">, int, blitz::bz_ArrayExpr<blitz::FastArrayIterator<int, 1=""> > >' requested here
applyOverSubdomain(array, arrayIter, subdomain, expr);
^
aqq.cpp:17:6: note: in instantiation of function template specialization 'blitz::IndirectArray<blitz::Array<int, 1="">, std::vector<int, std::allocator<int=""> > >::operator=<blitz::Array<int, 1=""> >' requested here
A[I] = B;
^
/usr/include/blitz/array/expr.h:285:10: note: candidate template ignored: could not match 'TinyVector<int, N_rank="">' against 'int'
void moveTo(const TinyVector<int, N="">& i)
^

a safeToReturn() issue

Migrated from: https://sourceforge.net/p/blitz/bugs/48/

The code below fails on F_safe() call while it does work with F() call:

$ cat test.cpp
#include <blitz/array.h>
using namespace blitz;
using namespace std;

template <class T1, class T2>
auto F(const T1 &a1, const T2 &a2)
-> decltype(a1 * a2)
{ return a1 * a2; }

template <class T1, class T2>
auto F_safe(const T1 &a1, const T2 &a2)
-> decltype(safeToReturn(a1 * a2))
{ return safeToReturn(a1 * a2); }

int main()
{
Range i(0, 10);
Array<double,1>
A(Range(-1, 11)),
B(Range(-1, 11)),
C(Range( 0, 11));

cerr << "F() ..." << endl;
A(i) = F(B(i), C(i));
cerr << "F_safe() ..." << endl;
A(i) = F_safe(B(i), C(i));
}

$ g++ -DBZ_DEBUG -std=c++11 test.cpp -lblitz
$ ./a.out
F() ...
F_safe() ...
/usr/local/include/blitz/bounds.h:71 Two array operands have different
lower bounds: in rank 0, the bounds are -1 and 0

a.out: /usr/local/include/blitz/bounds.h:72: static int
blitz::bounds::compute_lbound(int, int, int): Assertion `0' failed.
Aborted

Extensions to Blitz++ from f2cpp-project

Hello,

I'm Tobias Loew. Over the last 12 month I've been working a lot with the Blitz++ library. For my Fortran 90 to C++ translation project (https://github.com/tobias-loew/Fortransformers), I use Blitz++ as template-expression library mimicking the Fortran 90 array-operations.
For having a proper replacement for Fortran I had to extend Blitz++ with some additional features:

  • added TinyBasedVector (and its associated iterator-types), an extension of TinyVector that allows specifying a base index,
    this is used as base-class for non-dynamic arrays (e.g. static or stack-based)
  • added a Policy template argument to the Array class that allows optimizations when used with TinyBasedVector
  • added support for indexing-arrays (only one level currently, nesting of index-arrays is not yet supported)
  • added support for member-projections (access struct-members as blitz-array from a blitz-array over a struct; categorical-speaking: make struct-member-access a functor)
  • added many constexpr contructors

Further on, I disabled the explicit evaluation-optimizations (alignment, SIMD), since the modern C++ compiler usually do those optimizations automatically (and may finally inline everything).
My version of Blitz++ compiles on VS 2015 or a comparable Clang/GCC compiler. It uses C++11/14 features as auto, decltype, constexpr, lambdas and variadic templates.
IMHO Blitz++ could benefit a lot by switching to a modern C++ standard, since most of the function overload sequences can be replaced by a single variadic-template function. (E.g. this could be used in a Blitz++ 2.0 version.)

All those changes I did not just for "playing around", but are used since almost a year in a quite large code-base (which was translated from Fortran and with my f2cpp-tool).
(The program I work on at my company is Ebsilon (www.ebsilon.com). The code is proprietary, but I could show you a C++ version of LAPACK using my Blitz++ library.)

When you're interested in the code, please have a lock at https://github.com/tobias-loew/Fortransformers.
I would be happy if some of my changes would make it into Blitz++ (2.0 ?).

Tobias

contents of the old TODO file

These are the contents of the TODO file that I've just removed from the repo as it clearly do not follow TODO-related discussions elsewhere:

** make Blitz STL-compliant
** extend "new" expression template support to all blitz container classes, not just Arrays
** expression template support for TinyMatrix (or perhaps a merger with the tvmet library)
** proper usage of std namespace within blitz (reduce or eliminate use of non-standard headers and using directives)
** add RPM as a dist medium
** make Blitz OpenMP supported

Is there anything here worth retaining as a "ticket" on github?

Investigate variadic templates to decrease code size

Peter Boyle wrote:

Just a small comment — I’m working on a distributed MPP cartesian grid code.

github.com/paboyle/Grid

Certainly not pitching it as it is niche, focussed on particle physics, but I found C++11 does enable MUCH smaller more
compact expression template engines ~ 250 LOC. Something I learned from Antonin Portelli, CC’d. The corresponding C++98
US QDP++ package was more like 100k LOC using PETE.

So I agree that there is VERY much scope for a rewrite/update using features that were not originally available.

check-examples chokes with newer GNU compilers

I've only noticed this with GCC 6 and 7 on Mac OS. make check-examples chokes because #include <array> somewhere in the standard library tries to install the array executable in the examples directory. Recommend renaming array example to arrayx or such.

Blitz isn't multilib

Migrated from: https://sourceforge.net/p/blitz/bugs/18/

As reported by @sergiopasra on 2008-11-13:

A multilib package can be installed simultaneously in 32 and 64 bits versions. In linux, multilib can be summarized as only architecture independent files in /usr/include and architecture dependent files in /usr/lib and /usr/lib64 (this is the layout in fedora, in other distributions it differs).

Blitz has an architecture dependent file in /usr/include, the header bzconfig.h
This file is created at build time and depends on the architecture.

As a workaround for the fedora package I have moved the bzconfig.h file to libdir/blitz/include and modified the blitz.pc file so that this new directory is included.

Another solution could be to provide a set of predefined bzconfig. files in /usr/include (one per arch) and to decide which one to load at compile time.

Compilation issue with GCC8

It looks like there is a bug in GCC8.1.0 which causes it to crash when compiling blitz. The error message is:

                 from ../../blitz-1.0.1/testsuite/expression-slicing.cpp:3:
../../blitz-1.0.1/blitz/array/stencil-classes.cc:227:73: internal compiler error: in cp_tree_equal, at cp/tree.c:3896
                                                              rank_> >::type i) const
                                                                     ^

0x5ce766 cp_tree_equal(tree_node*, tree_node*)
	../../gcc-8.1.0/gcc/cp/tree.c:3896
0x6e6179 template_args_equal(tree_node*, tree_node*, bool)
	../../gcc-8.1.0/gcc/cp/pt.c:8688
0x6e5ff9 comp_template_args(tree_node*, tree_node*, tree_node**, tree_node**, bool)
	../../gcc-8.1.0/gcc/cp/pt.c:8717
0x73e8af structural_comptypes
	../../gcc-8.1.0/gcc/cp/typeck.c:1337
0x6e62ec template_args_equal(tree_node*, tree_node*, bool)
	../../gcc-8.1.0/gcc/cp/pt.c:8669
0x6e5ff9 comp_template_args(tree_node*, tree_node*, tree_node**, tree_node**, bool)
	../../gcc-8.1.0/gcc/cp/pt.c:8717
0x6ebcf9 spec_hasher::equal(spec_entry*, spec_entry*)
	../../gcc-8.1.0/gcc/cp/pt.c:1668
0x71301d hash_table<spec_hasher, xcallocator>::find_with_hash(spec_entry* const&, unsigned int)
	../../gcc-8.1.0/gcc/hash-table.h:850
0x6fb2c4 lookup_template_class_1
	../../gcc-8.1.0/gcc/cp/pt.c:9331
0x6fb2c4 lookup_template_class(tree_node*, tree_node*, tree_node*, tree_node*, int, int)
	../../gcc-8.1.0/gcc/cp/pt.c:9650
0x71eced finish_template_type(tree_node*, tree_node*, int)
	../../gcc-8.1.0/gcc/cp/semantics.c:3228
0x6c3b14 cp_parser_template_id
	../../gcc-8.1.0/gcc/cp/parser.c:15861
0x6c3c2e cp_parser_class_name
	../../gcc-8.1.0/gcc/cp/parser.c:22396
0x6cf507 cp_parser_qualifying_entity
	../../gcc-8.1.0/gcc/cp/parser.c:6570
0x6cf507 cp_parser_nested_name_specifier_opt
	../../gcc-8.1.0/gcc/cp/parser.c:6256
0x6cfb41 cp_parser_nested_name_specifier
	../../gcc-8.1.0/gcc/cp/parser.c:6496
0x6cfc4e cp_parser_elaborated_type_specifier
	../../gcc-8.1.0/gcc/cp/parser.c:17667
0x6cb579 cp_parser_type_specifier
	../../gcc-8.1.0/gcc/cp/parser.c:16811
0x6d7755 cp_parser_decl_specifier_seq
	../../gcc-8.1.0/gcc/cp/parser.c:13623
0x6d7dbb cp_parser_parameter_declaration
	../../gcc-8.1.0/gcc/cp/parser.c:21512
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.```

I believe this is GCC's problem to fix, not blitz's but I'm putting this issue here so others having the same problem will find it mentioned.

use of unintialized value in array/methods.cc

Migrated from: https://sourceforge.net/p/blitz/bugs/21/

As reported by @tesch on 2010-01-15:

ordering(i) can be uninitialized when checked in the debug code... algorithm might still be ok, but the debug code is incorrect. this gives an error in valgrind:

==2279== Memcheck, a memory error detector
==2279== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==2279== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==2279== Command: ./peter-bienstman-5
==2279== Parent PID: 2278
==2279==
==2279== Conditional jump or move depends on uninitialised value(s)
==2279== at 0x4024DE: blitz::Array<float, 2>::Array<blitz::_bz_ArrayExprBinaryOp<blitz::FastArrayIterator<float, 2>, blitz::FastArrayIterator<float, 2>, blitz::Add<float, float> > >(blitz::_bz_ArrayExpr<blitz::_bz_ArrayExprBinaryOp<blitz::FastArrayIterator<float, 2>, blitz::FastArrayIterator<float, 2>, blitz::Add<float, float> > >) (methods.cc:36)
==2279== by 0x4013E9: main (peter-bienstman-5.cpp:23)
==2279==
==2279==
==2279== HEAP SUMMARY:
==2279== in use at exit: 0 bytes in 0 blocks
==2279== total heap usage: 10 allocs, 10 frees, 396 bytes allocated
==2279==
==2279== All heap blocks were freed -- no leaks are possible
==2279==
==2279== For counts of detected and suppressed errors, rerun with: -v
==2279== Use --track-origins=yes to see where uninitialised values come from
==2279== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)

Build efficient serialization to persist / cache / share Blitz Array

Thomas Vincent Wrote:

One thing that we had to develop (only for 3d array) and I do thing should be part of blitz++ itself is efficient file serialization to persist / cache / share blitz array.

I have stuff that does that in NetCDF, and the idea is to include those subroutines in the Blitz++
library. Is this what you are talking about, or are you think of something different?

No not really, I found volume dump (read/write) really useful when working with big (huge) volume.
So we implemented a generic binary read/write based on simple std::fstream::write() / read() to share volume across processes / cache to disk them temporally.
Format is potentially not cross platform at all but it's really convenient.
We did it for 2 / 3 dimensional array of contiguous data but it should scale nicely to higher rank ... not sure how to approach the non-contiguous part though.
I think it's something blitz should offer.

After that being able to read/write specific format is necessary too to spread blitz++ usage I think.
I have vtk / paraview structured data skills and code (write part only) if it could help.

Many examples don't work

Migrated from: https://sourceforge.net/p/blitz/bugs/34/

As reported by @torquil on 2011-12-10:

It seems that the latest Mercurial source does no contain blitz/array-old.h. The example "cfd.cpp" depends on this file, so it doesn't work. In "cfd.cpp", there are also some negative comments, e.g.:

"There are serious bugs, this simulation doesn't work very well."

So perhaps this example should be removed or updated, if array-old.h is not expected to return?

This compilation error also causes the other examples to not be built, since "make" stops the build process at this point.

Due to this, I did the following in order to compile the other examples:

$ for i in *.cpp; do make $(basename $i .cpp); done

and found that the following cpp-files did not compile:

cfd.cpp
curldiv.cpp
diff.cpp
erf.cpp
indirect.cpp
pauli.cpp
pick.cpp
profile.cpp
qcd.cpp
rangexpr.cpp
stencil3.cpp
stencilet.cpp
tiny2.cpp
tiny3.cpp
tiny.cpp
transform.cpp

Best regards
Torquil M. Sørensen

Here's a relevant comment from a 2012 commi (8a56e2b):

Commented out several example programs which rely on the Vector classes and are therefore not currently functional. The Vector classes need to be updated to use the new style expression template machinery in blitz. The old style ET machinery has been removed to reduce the overall amount of blitz code.

Build of tests fail: calling a protected destructor of class 'blitz::MemoryBlock<double>'

Getting this error with clang-40:

In file included from serialize.cpp:10:
In file included from /usr/local/include/boost/archive/text_iarchive.hpp:24:
In file included from /usr/local/include/boost/archive/basic_text_iarchive.hpp:30:
In file included from /usr/local/include/boost/archive/detail/common_iarchive.hpp:23:
In file included from /usr/local/include/boost/archive/detail/interface_iarchive.hpp:22:
/usr/local/include/boost/archive/detail/iserializer.hpp:246:24: error: calling a protected destructor of class 'blitz::MemoryBlock<double>'
                delete t;
                       ^
/usr/local/include/boost/archive/detail/iserializer.hpp:265:20: note: in instantiation of member function 'boost::archive::detail::heap_allocation<blitz::MemoryBlock<double>
      >::doesnt_have_new_operator::invoke_delete' requested here
            typex::invoke_delete(t);
                   ^
/usr/local/include/boost/archive/detail/iserializer.hpp:273:13: note: in instantiation of member function
      'boost::archive::detail::heap_allocation<blitz::MemoryBlock<double> >::invoke_delete' requested here
            invoke_delete(m_p);
            ^
/usr/local/include/boost/archive/detail/iserializer.hpp:294:36: note: in instantiation of member function 'boost::archive::detail::heap_allocation<blitz::MemoryBlock<double>
      >::~heap_allocation' requested here
        detail::heap_allocation<T> h;
                                   ^
/usr/local/include/boost/serialization/singleton.hpp:118:34: note: in instantiation of member function 'boost::archive::detail::pointer_iserializer<boost::archive::text_iarchive,
      blitz::MemoryBlock<double> >::heap_allocation' requested here
        static singleton_wrapper t;
                                 ^

Travic Continuous Integration

Jeff Hammond wrote:

Whenever this ends up on Github, I'll be happy to contribute Travis CI (continuous integration i.e. automated testing) support, since I'm on a role with that lately. CI will be particularly useful when pull requests start coming in and C++11 features are added.

continuous integration wishlist

  • test execution on Windows
  • genstencils.py execution on Windows
  • Boost.serialisation test
  • Debug build on Windows
  • Intel compiler
  • Intel compiler + TBB
  • codecov?
  • codacy?
  • 32-bit build on Appveyor
  • create tickets for all the compiler warnings popping up in the logs
  • various disable/enable options covered
  • out of tree builds

fix for boost serialization

The boost serialization functionality was broken with newer versions of boost. This patch fixes it:

diff -Naur blitz-0.10-orig/blitz/memblock.h blitz-0.10-patched/blitz/memblock.h
--- blitz-0.10-orig/blitz/memblock.h	2012-06-26 15:25:15.000000000 -0700
+++ blitz-0.10-patched/blitz/memblock.h	2017-08-08 11:16:39.763291400 -0700
@@ -41,9 +41,16 @@
 #include <boost/serialization/array.hpp>
 #include <boost/serialization/collection_size_type.hpp>
 #include <boost/serialization/nvp.hpp>
+#include <boost/version.hpp>
+
+#  if BOOST_VERSION >= 106000
+#    include <boost/serialization/array_wrapper.hpp>
+#    include <boost/archive/detail/iserializer.hpp>
+#  endif
 #endif
 #include <stddef.h>     // diffType
 
+
 BZ_NAMESPACE(blitz)
 
 enum preexistingMemoryPolicy { 
@@ -79,6 +86,12 @@
     typedef P_type T_type;
 
 protected:
+#ifdef BZ_HAVE_BOOST_SERIALIZATION
+#  if BOOST_VERSION >= 106000
+    friend class boost::serialization::access ;
+    template<class T> friend class boost::archive::detail::heap_allocation;
+#  endif
+#endif
     explicit MemoryBlock(sizeType items)
     {
       // pad the length to vecWidth, if not already done

bug when reducing over an array expression

this is an old bug http://sourceforge.net/p/blitz/bugs/17/ but I've run into this a week ago. I don't know if you just want to look at all the bugs in the sourceforge tracker or start a new list here. anyway, here goes.

#include <blitz/array.h>

using namespace blitz;
using namespace blitz::tensor;

#define EXPR a1(i, k) * a2(k, l) * a3(l, j)

int main()
{
  Array<float, 2> a1(2, 2), a2(2, 2), a3(2, 2);
  Array<float, 4> a4(2, 2, 2, 2);
  Array<float, 2> a5(2, 2), a6(2, 2);
  a1 = 1, 0, 0, 1;
  a2 = a1;
  a3 = a1;
  a4 = EXPR;
  a5 = sum(sum(a4  , l), k);  // this works
  a6 = sum(sum(EXPR, l), k);  // this fails, although it is semantically identical
  return 0;
}

Clean up Macro Stuff to Support Non-Standard Compilers

Theodore Papadopoulo wrote:

One task that really needs to be added is the cleanup of all the macro
stuff that was needed to support old non-standard compilers. Nowadays,
we can certainly rely on features such as exceptions, namespace, partial
templates, ....

Better Vectorization for GCC

Patrik Jonsson wrote:

One more thing that can be added to the improvements list is better handling of vectorization. The last big update to blitz was when I added support for vectorization by making it more obvious to the compiler when arrays were contiguous. However, this relies on the compiler to do the actual vectorization. The inter compiler was quite good at this, but as far as I remember gcc does not vectorize loops at all. Since the majority of users probably use gcc, this is a substantial disadvantage. If someone wanted to look into ways to add explicitly vectorized operations, that would greatly improve blitz's performance under gcc, I think. That does require diving deep into the guts of the expression template mechanism, though.

min([NaN,NaN]) != NaN

Migrated from: https://sourceforge.net/p/blitz/bugs/35/

The following code:

#include <blitz/array.h>
using namespace blitz;
int main()
{
Array<float, 3> arr(Range(0,10));
arr = quiet_NaN(float(0));
std::cout << "min: " << min(arr) << std::endl;
std::cout << "max: " << max(arr) << std::endl;
}

... gives the following output:

$ ./a.out
min: 3.40282e+38
max: -3.40282e+38

... which is (arguably) kind of non-intuitive.

In particular, an assertion using isnan(min()) or finite(min())
would not detect presence of NaNs, which is yet more non-intuitive

Patrik's comment from the mailing list:

Yeah, that's suboptimal. NaN isn't greater or less than anything, so the initial value never gets replaced in the reduction. We can't just check if the result is huge, because the result COULD actually be huge. We'd need a separate comparison against NaN for all elements (but only for T_numtypes that actually have NaN.)

However, that would change the existing behavior which (I assume) says that min([ 1 2 3 NaN]) is 1 and not NaN. What's the desired behavior here. It seems reasonable to have the NaN always be captured in the reduction.

Initializing the min/max reductions with the first value as opposed to with huge/neghuge should take care of this. However, I'm having difficulties making that change without breaking stuff.

Use of Runtime GPL?

Migrated from: https://sourceforge.net/p/blitz/feature-requests/2/

As suggested by @elfring back in 2007:

Would you like to consider the "GNU General Public License with runtime exception" (RGPL)?
http://gcc.gnu.org/onlinedocs/libstdc++/17_intro/license.html

How do you think about the details from the discussion "(L)GPL and C++ templates issue"?
http://groups.google.de/groups?threadm=4174046c%241_2%40news.bluewin.ch

Julian Cummings commented on 2007-05-17:

I have consulted with Todd Veldhuizen, the original author of Blitz++, and we both agree that allowing distribution of blitz under the GPL with runtime exception would make sense. Since the blitz library consists almost entirely of template code, any distributed program that was compiled using blitz would essentially be forced to include a source code distribution to allow for modifications and improvements of blitz under the original GPL or Lesser GPL. The runtime exception to the GPL appears to adequately address this concern. Blitz is already available under a separate BSD-like license called the Blitz Artistic License. I will endeavor to update all licensing references in the next blitz maintenance release from the original GPL to version 2 with the runtime exception.

@elfring commented on 2008-04-22:

Will any licence unification be performed in the near future?
http://blitz.cvs.sourceforge.net/blitz/www/legal/index.html?revision=1.1.1.1&view=markup
http://blitz.cvs.sourceforge.net/blitz/blitz/LICENSE?revision=1.2&view=markup

Julian Cummings commented on 2008-04-26:

Yes, we will now be releasing Blitz++ under version 2 of the LGPL. In addition, a request was made by SciPy developers to package Blitz++ with SciPy under a BSD license (to avoid requirements that GPL and LGPL place on a package that uses another). Todd Veldhuizen, the original author and copyright holder for Blitz++, agreed to this, so we will allow people to choose between use of the LGPL, the BSD license, or the original Blitz++ artistic license. The licensing documents have been updated within the cvs development version of blitz and will be included in the next maintenance release. We are still working on completion of some 64-bit compatibility issues, but I hope to produce that next release in the next couple of weeks.

@elfring commented on 2008-04-26:

I am confused if I understand your reply correctly. I would prefer a single licence that will fit all purposes.

How do you think about a solution from a well-known header-only class template library?
http://synesis.com.au/software/stlsoft/

Julian Cummings commented on 2008-04-28:

After looking at the STLSoft website, it is not clear to me how they have resolved this issue. The website merely states that their software is released under a "modified BSD license". How do they address GPL or LGPL? The difficulty as I see it is that the GPL and LGPL licenses specifically state that the license documents are not to be modified in any way. So I do not think you can have a single license that covers (L)GPL as well as alternate licensing terms. That is why Blitz was originally released with the option of using the GPL or the Blitz "artistic license". AFAIK, these cannot be unified into a single license because the (L)GPL must be used in its original form. But I am not a lawyer or an expert on software licensing, so I am open to other ideas on this.

how to resolve the configure-generated-config vs. packaging issue?

Packaged versions of Blitz are shipped with bzconfig.h file full of information on the compiler features and library availability which not necessarily match the ones of the environment in which package users are working. Is there any way we could help packagers resolve this issue?

Code generation with preprocessor metaprogramming

Without moving to C++11 (#9), a lot of repetitions in the blitz++ codebase could be omitted using preprocessor metaprogramming.

This would invoke dependence on one more boost library, but that’s no problem I guess?

I actually have to maintain a fork of blitz++ here because the maximal arity for the slicing operations is sometimes insufficient for my application. I used preprocessor metaprogramming to generate the necessary amount of slicing functions, which amount I define by a macro.

You can have a look at the solution in these relevant commits:
http://sourceforge.net/p/cppqed/blitz/ci/9b49b225eaf6c9f8f8cb9e039e51d7a2cb056a27
http://sourceforge.net/p/cppqed/blitz/ci/dd01d5816e6e6f56d9d0b299c5a3c999aff676b9
http://sourceforge.net/p/cppqed/blitz/ci/b28e85ab238e1d8bcf4ec4636ec965a9106b76cd

Any chance of such solutions being pulled into the default branch?

making Blitz part of Boost?

Just wondering what would be the pros and cons?

Certainly, it would clarify the way to go with docs, build system, boost dependencies (serialization, MPI, preprocessor), packaging issues, etc

Some legal clarifications would need to be done (but perhaps with benefit for Blitz).
Blitz would definitely benefit from Boost review process.
Boost folks might be interested given the Boost.MultiArray seems outdated, the overlap with Boost.ublas seems unclear.

Any thoughts?

Wrong assignment between Array, and TinyMatrix for a certain layout

Migrated from: https://sourceforge.net/p/blitz/bugs/66/

As reported by @aherrmann (?) or @AndreasHerrmann (?):

I believe that I found a bug in the assignment of a TinyMatrix into a sub-array of non-standard storage order.

The attached code demonstrates it in detail.

In short:
Take a rank-3 Array and assign a TinyMatrix into a subarray of appropriate shape. This will work if the Array has C-, or Fortran-order. However, it will fail if the Array has a different storage-order.

However, it will work, if you replace the TinyMatrix by another Array.

The issue was observed in Blitz-0.10 with both GCC and Clang.

Best, Andreas

#include <iostream>
#include <blitz/blitz.h>
#include <blitz/array.h>
#include <blitz/tinymat2.h>

int main() {
    using std::cout;
    using namespace blitz;
    auto all = Range::all();

    { // The broken case:
        TinyMatrix<int, 3, 3> m;
        m = 1, 2, 3,
            4, 5, 6,
            7, 8, 9;
        cout << "m:\n" << m << "\n";
        // Output:
        //   m:
        //   (1,2,3; 4,5,6; 7,8,9)

        GeneralArrayStorage<3> storage;
        // storage.ordering() = thirdDim, secondDim, firstDim;  // works
        // storage.ordering() = firstDim, secondDim, thirdDim;  // works
        storage.ordering() = thirdDim, firstDim, secondDim;  // error!
        Array<int, 3> A(2, 3, 3, storage);
        A = 10;
        A(0, all, all) = m;
        cout << "A:\n" << A << "\n";
        // Expected output:
        //   A:
        //   (0,1) x (0,2) x (0,2)
        //   [ 1 2 3
        //     4 5 6
        //     7 8 9
        //     10 10 10
        //     10 10 10
        //     10 10 10 ]
        //
        // Actual output:
        //   A:
        //   (0,1) x (0,2) x (0,2)
        //   [ 1 2 3       <
        //     4 5 3       < wrong!
        //     7 8 3       <
        //     10 10 10
        //     10 10 10
        //     10 10 10 ]
    }

    { // For reference, the working case:
        Array<int, 2> m(3, 3);
        m = 1, 2, 3,
            4, 5, 6,
            7, 8, 9;
        cout << "m:\n" << m << "\n";
        //   Output
        //   (0,2) x (0,2)
        //   [ 1 2 3
        //     4 5 6
        //     7 8 9 ]
        //

        GeneralArrayStorage<3> storage;
        // storage.ordering() = thirdDim, secondDim, firstDim;
        // storage.ordering() = firstDim, secondDim, thirdDim;
        storage.ordering() = thirdDim, firstDim, secondDim;
        Array<int, 3> A(2, 3, 3, storage);
        A = 10;
        A(0, all, all) = m;
        cout << "A:\n" << A << "\n";
        // Correct output:
        //   A:
        //   (0,1) x (0,2) x (0,2)
        //   [ 1 2 3       <
        //     4 5 6       < correct.
        //     7 8 9       <
        //     10 10 10
        //     10 10 10
        //     10 10 10 ]
    }
}

#pragma GCC ivdep

Migrated from https://sourceforge.net/p/blitz/bugs/61/

Since 2013 gcc supports the "ivdep" pragma. However, it has apparently a different syntax than the one used in Blitz. Instead of:

#pragma ivdep

one needs to use

#pragma GCC ivedep

Perhaps, it's then worth enabling USE_ALIGNMENT_PRAGMAS for gcc in the config files and changing

#pragma ivdep

into

#if defined(__INTEL_COMPILER)
#  pragma ivdep
#elif defined(__GNUG__)
#  pragma GCC ivdep
#endif

'configure --without-tbb' still looks for tbb

Log says there is --without-tbb:

  $ ./configure --enable-shared --disable-array-length-padding --disable-fortran --disable-serialization --without-tbb --disable-threadsafe --prefix=/usr/local --localstatedir=/var --mandir=/usr/local/man --disable-silent-rules --infodir=/usr/local/info/ --build=amd64-portbld-freebsd11.1

but it still looks for tbb:

checking tbb/atomic.h usability... yes
checking tbb/atomic.h presence... yes
checking for tbb/atomic.h... yes

docs: mention the safeToReturn() logic

Migrated from: https://sourceforge.net/p/blitz/bugs/40/

Here's a recipe to show how Blitz misbehaves with a call to a C++11 auto/decltype function:
Same results with recent versions of g++ and clang++

$ cat test.cpp
#include <blitz/array.h>
using namespace blitz;
struct cls
{
#define decltype_return(expr) -> decltype(expr) { return expr; }
auto half(const Array<double, 2> &B, const Range &i, const Range &j)
#ifdef SKIPHALF
decltype_return(B(i,j))
#else
decltype_return(.5 * B(i,j))
#endif

void substract_half(
const Array<double, 2> &A, const Array<double, 2> &B,
const Range &i, const Range &j
)
{ A(i,j) -= half(B,i,j); }
};
int main() {
Range i(0,2), j(0,4);
Array<double, 2> A(i,j), B(i,j);
A = 10;
B = 20;
cls op;
op.substract_half(A,B,i,j);
std::cerr << A << std::endl;
}

$ g++ -std=c++0x -DBZ_DEBUG -lblitz test.cpp
$ ./a.out
/opt/local/include/blitz/shapecheck.h:73 Incompatible shapes detected:
(3,5)
(1606416304,32767)

[Blitz++] Shape check failed: Module /opt/local/include/blitz/globeval.cc line 152
Expression: (s*A)
Assertion failed: (0), function _bz_evaluate, file /opt/local/include/blitz/globeval.cc, line 168.
Abort trap

$ g++ -std=c++0x -DBZ_DEBUG -lblitz test.cpp -DSKIPHALF
$ ./a.out
(0,2) x (0,4)
[ -10 -10 -10 -10 -10
-10 -10 -10 -10 -10
-10 -10 -10 -10 -10 ]

That is, if the half() function contains an expression including multiplication by a constant,
the array ranges seem to be uninitialised (i.e. the 1606416304 & 32767 values).

Quoting Patrik's comment from the mailing list:

the array you're generating with B(Range) goes out of scope, so the expression is pointing to an array that no longer exists. There is a way to make the expression hold a copy of the Array instead of a reference by using the function safeToReturn(expr).

The safeToReturn() logic is not documented anywhere.

Visual Studio 10 warnings (from Appveyor)

C:\projects\blitz-nh158\random/mt.h(183): warning C4267: '=' : conversion from 'size_t' to 'unsigned int', possible loss of data [C:\projects\blitz-nh158\blitz\blitz.vcxproj]
C:\projects\blitz-nh158\random/mt.h(202): warning C4267: '=' : conversion from 'size_t' to 'unsigned int', possible loss of data [C:\projects\blitz-nh158\blitz\blitz.vcxproj]
C:\projects\blitz-nh158\random/mt.h(210): warning C4267: '=' : conversion from 'size_t' to 'unsigned int', possible loss of data [C:\projects\blitz-nh158\blitz\blitz.vcxproj]
C:\projects\blitz-nh158\blitz/range.h(247): warning C4244: 'return' : conversion from 'const blitz::diffType' to 'int', possible loss of data [C:\projects\blitz-nh158\Blitz-Testsuite\ABA1\ABA1.vcxproj]
C:\projects\blitz-nh158\blitz/range.cc(13): warning C4244: 'return' : conversion from 'const blitz::diffType' to 'blitz::Range::T_numtype', possible loss of data [C:\projects\blitz-nh158\Blitz-Testsuite\ABA1\ABA1.vcxproj]
C:\projects\blitz-nh158\blitz/array/methods.cc(314): warning C4267: '=' : conversion from 'size_t' to 'int', possible loss of data [C:\projects\blitz-nh158\Blitz-Testsuite\ABA1\ABA1.vcxproj]
C:\projects\blitz-nh158\blitz/array/fastiter.h(199): warning C4244: 'return' : conversion from 'blitz::diffType' to 'int', possible loss of data [C:\projects\blitz-nh158\Blitz-Testsuite\ABA1\ABA1.vcxproj]
C:\projects\blitz-nh158\blitz/array/fastiter.h(252): warning C4244: 'return' : conversion from 'const blitz::diffType' to 'int', possible loss of data [C:\projects\blitz-nh158\Blitz-Testsuite\ABA1\ABA1.vcxproj]

chained reduction of array expression fails

Migrated from: https://sourceforge.net/p/blitz/bugs/17/

As reported by @mgrabner on 2008-08-18:

As the attached example demonstrates, a chained reduction of an array expression can only be processed when the intermediate results are stored in an array. This is not feasible for large arrays.

#include <blitz/array.h>

using namespace blitz;
using namespace blitz::tensor;


#define EXPR a1(i, k) * a2(k, l) * a3(l, j)


int
main()
{
  Array<float, 2> a1(2, 2), a2(2, 2), a3(2, 2);
  Array<float, 4> a4(2, 2, 2, 2);
  Array<float, 2> a5(2, 2), a6(2, 2);
  a1 = 1, 0, 0, 1;
  a2 = a1;
  a3 = a1;
  a4 = EXPR;
  a5 = sum(sum(a4  , l), k);  // this works
  a6 = sum(sum(EXPR, l), k);  // this fails, although it is semantically identical
  return 0;
}

Further comments by Patrik Jonsson:

The problem seems to have something to do with (from the manual):
"Reductions have an important restriction: It is currently only possible to reduce over the last dimension of an array or array expression."

The reduction works if the expression is transposed so tensor::l is the last index of the last operand:

sum(a1(i, k) * a2(l,k) * a3(j, l), l)

However, transposing the operands shouldn't affect whether the expression can be reduced, so there's something strange going on here.

The problem is that compute_ordering() throws an assert if the ordering of the expression is indeterminate. In _bz_ArrayExprReduce::computeOrdering(), the ordering of the reduction is taken from the operands, except that missing values are just initialized in standard order, so just calling this for an expression with mixed order will throw the assert. It seems that mixed ordering of the operands here is not a fatal problem, since the expression will be evaluated using indices anyway. So perhaps if there's mixed order of the operands, we should just skip it and initialize that dim just as if it was missing?

Keep Blitz++ Around

Thank you all for your input on this issue. After much consideration, I think that Blitz++ is worth keeping around. Even in 2016, it remains unique in concept and execution.

Blitz++ claims to do one thing only: provide multi-dimensional arrays for C++, similar to those in Fortran 90, Python/Numpy, and APL. Notice that Fortran 2008 has this feature but nothing like STL, and is widely used for scientific computing. It is clear that multi-dim arrays are essential in a way that STL is not. Of course, a system offering both is even more useful...

It is therefore disappointing that such arrays are still not part of the C++ standard. This is after 15 years of work on Blitz++, boost::multi_array, etc. Without any standard, different libraries use different classes for the same data structure, limiting compatibility between them. Interoperability is cumbersome, and often requires unnecessary copying of multi-dimensional data structures (assuming there's enough RAM).

Many of us confuse multi-dimensional arrays with matrices and vectors. Matrices and vectors are essential to scientific computing, and may be the most common type of arrays used. However, they do not take the place of the more general multi-dimensional array. This becomes clear to anyone attempting to read 5-dimensional data out of a HDF/NetCDF file. In an ideal world, matrix and vector classes (and operations) would be built upon a foundation of rank 1 and 2 arrays, thereby enhancing compatibility between different linear algebra libraries.

By offering only multi-dimensional arrays, Blitz++ provides a foundation upon which linear algebra and other libraries may be built. The fact that none have taken advantage of this foundation seems to be a missed opportunity. However... until/unless something better comes along, I believe we should continue to support Blitz++.

Why is Blitz++ so good?

  1. It works, it's stable, it's well-tested. There's really nothing wrong with it. Sometimes, software is updated infrequently because it's not buggy. That's a reason to KEEP it, not throw it away.
  2. It's well documented. The manual may feel long in the tooth compared to today's manuals. But the information you need is all there, and it works.
  3. It does one thing well and has no dependencies. I don't have to link to BLAS in order to read a NetCDF file with Blitz++.
  4. It's versatile. Blitz++ offers the full functionality of Fortran 90 arrays, and is able to use arrays in memory allocated by others. There are no restrictions on the dope vectors it allows. It is therefore REALLY useful for interfacing Fortran and Python code with C++. And since any array-like data structure can be converted (copy-free) to a blitz::Array, writing your functions to take blitz::Array parameters is an easy way to make them flexible as well.
  5. It's FAST. Benchmarks have shown it to be about as fast as Fortran 90 arrays.

In my review, I found only two other serious efforts to offer multi-dimensional arrays for C++. Both have potentially serious problems:

  • Eigen::Tensor is a relatively new part of Eigen. In theory, it offers most/all of Blitz++ functionality. However, it has many downsides at this point compared to Blitz++:
    It's a less mature product, could be evolving, could come with bugs, etc.
    We don't know how fast it is. It could be a lot slower than Blitz++.
    It's not as well documented. It provides some features that could be useful, but that I just didn't know were there because I couldn't find them in the documentation.
    If the authors do a good job, they will end up with a library similar in functionality and speed to Blitz++. I just don't see the upside to re-developing this functionality from scratch.
  • boost::multi_array showed initial promise as being part of the boost ecosystem, and therefore (possibly) on track to becoming a C++ standard. However, it has languished in boost, apparently with little or no interest. This project is even deader than Blitz++. Maybe one reason is benchmarks showed it to be about 1/2 as fast as Blitz++. We must accept that people who want multi-dimensional arrays to be part of their language standard will have to use Fortran for many years to come:

"I don't know what the language of the year 2000 will look like, but I know it will be called Fortran." -- Tony Hoare [CarHoare], apparently on a card distributed during the 1982 AFIPS National Computing Conference.

A number of other libraries exist that provide specialized matrix and vector classes. I do not need to mention them here because they don't provide multi-dimensional arrays.


I propose the following roadmap for the continued viability of Blitz++:

`. We get volunteers. Please contact me if you are interested in any of the tasks listed below.

  1. We move the repo to github.com/oonumerics/blitz. In the past, Blitz++ was hosted by oonumerics. Once this new repo is set up, we remove Blitz++ code from SourceForge and direct people to GitHub. We also move the mailing list and try to move the mailing list archives, if possible.
  2. Once things are moved, we can start putting updates into a ticket system. I would suggest the following priorities:
  3. Reformatted documentation, posted on-line. Doxygen docs would be nice.
  4. Identify and seek resolution on any warnings Blitz++ might be causing with modern compilers. We need to assure users that Blitz++ won't just stop working some day.
  5. Release the results of this as "Blitz 1.0"

We then start working on Blitz 2.0, which will make use of features in C++11 and beyond. C++98 users can continue to use Blitz 1.0. Updates might include:

  1. Replace TinyVector with std::array
    1/ Much has changed now, with std::unique_ptr<> and std::shared_ptr<> now being part of the C++ standard. It would be worth seeing if some of the shared_ptr functionality currently built into Blitz++ is worth factoring out.
  2. Consider adding new functionality that will make blitz::Array more useful out-of-the-box. I'm envisioning some stuff I've already written as little "utility" functions, but we'd want to do it right before putting it into the library. Possibilities include:
  3. A reshape() function.
  4. Easy ways to read/write to NetCDF files. (This would ONLY be compiled if Blitz++ is configured with NetCDF dependency. We don't want to add any REQUIRED dependencies).
  5. Copy-free conversions between blitz::Array and std::vector.
  6. Conversions between blitz::Array, Numpy arrays and Fortran 90 arrays.
  7. In any case, please share your comments and suggestions on this roadmap. (Ane please volunteer too!)

RectDomain and Range::all()

Migrated from: https://sourceforge.net/p/blitz/bugs/37/

the RectDomain does not work with Range::all():

# include <blitz/array.h>
using namespace blitz;
int main()
{
Array<float, 2> arr(2,2);
arr = 1,2,3,4;
Range rng_x = Range::all();
Range rng_y = Range(1,1);
RectDomain<2> sdm = RectDomain<2>(TinyVector<Range,2>(rng_x, rng_y));
cout << "arr(rng_x, rng_y) = " << arr(rng_x, rng_y) << endl;
cout << "arr(RectDomain(rng_x, rng_y)) = " << arr(sdm) << endl;
}

outputs:

arr(rng_x, rng_y) = (0,1) x (0,0)
[ 2
4 ]

arr(RectDomain(rng_x, rng_y)) = (0,0) x (0,0)
[ 2 ]

Doxygen Documents

Reformat existing documentation in modern systems: Doxygen, Markdown, ReadTheDocs.org, etc. In general, make it more searchable, more accessible, easier to use.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.