Either and Maybe monads for better error-handling in C++ ↔️

Overview

neither

A functional implementation of Either in C++14.

Travis GitHub license

buckaroo add github.com/loopperfect/neither

Examples

Handling Unsafe Code

auto unsafe = [] { // a function that throws, sometimes we can't avoid it...
  if (true) {
    throw std::runtime_error("error");
  }
  return 1;
}

Either<std::exception, int> e = Try<std::exception>(unsafe); // let's lift the exception into the typesystem

e.left()
  .map([](auto const& e) {
    return std::cerr << e.what() << std::endl;
  }); // print error if available

int result = e
  .leftMap([](auto) { return 42; }) // do nothing with exception and map to 42
  .rightMap([](auto x) { return x * 2; }) // do further computation if value available
  .join() // join both sides of either

ASSERT_TRUE(result == 42);

Another Example

Either<std::string, int> compute(int x) {
  if(x<0) return left("don't pass x<0");
  return right(x*x);
}

std::string resultString = compute(5)
  .rightMap([](auto x){ return x/2.0;}) // success case
  .join(
    [](auto errorStr) { return "compute said: " + errorStr; }, // error-case
    [](auto x) { return "compute said: " + std::to_string(x); } // success-case
   );

std::cout << resultString << std::endl;

Composition of Eithers

neither::Either<my_error_t, int> f1();
neither::Either<my_error_t, float> f2();

void compose() {
    auto value = f1()
        .rightFlatMap([](const struct_a& v){
            return f2();
        })
        .rightMap([](const struct_b& v){
            return 5;
        })
        .leftMap([](const auto& my_error){
            return 6;
        }).join();
    // value should be either 5 or 6
}

Maybe Example

Maybe<float> compute(float x) {
  if(x<0) return {};
  return {sqrtf(x)};
}

Maybe<float> x = compute(-4)
 .map([](auto x){ return x*x;})
 .map([](auto x){ return x+1 });

if(!x.hasValue) {
  std::cerr << "error occured" << std::endl;
}

Monadic Lifting

int sum(int x, int y){ return x+y; }

//...

auto monadicSum = lift(sum); // transforms sum to: Maybe<int> MonadicSum(Maybe<int>, Maybe<int>)

ASSERT_TRUE( monadicSum( maybe(5) , maybe(7) ).get(0) == 12 );
ASSERT_TRUE( monadicSum( maybe(), maybe(1) ).hasValue == false);

Why Eithers? - Learned Lessons About Error handling

Some useful references:

Summary and Conclusions

  • Error codes break composition
    • requires out-parameters; making functions impure and hard to reason about
    • using out-parameters makes inlining harder
    • => don't use output parameters
  • Exceptions are 2-3 orders of magnitude slower if exceptions are thrown
    • => avoid throwing exceptions - not always possible
  • Overhead of exceptions grows linear with the callstack
    • => catch exceptions early
  • Exceptions are not part of the type-system
    • annotating function signatures with throw and noexcept is not helpful; contract breaches are not detected in compile-time but call std::terminate in run-time
    • handling exceptions is error prone and requires documentation
    • => encode errors in the types to enforce proper handling by the API consumer

Installation

This library requires a C++ 14 compiler.

Install with Buckaroo:

buckaroo add github.com/loopperfect/neither

The Buck target is :neither

Alternatively you can copy & paste the headers to your include path:

cp neither/include/*.hpp $InstallPath/include/neither
Comments
  • neither composable.

    neither composable.

    Hi,

    I assumed that it should be composable, i.e. something like should work:

    struct my_error_t {
        std::string s;
    };
    
    struct struct_a {
        int v;
    };
    
    struct struct_b {
        double v;
    };
    
    neither::Either<my_error_t, struct_a> f1();
    
    neither::Either<my_error_t, struct_b> f2();
    
    
    void code() {
        auto value = f1()
            .rightMap([](const struct_a& v){
                return f2();
            })
            .rightMap([](const struct_b& v){
                return 5;
            })
            .leftMap([](const auto& my_error){
                return 6;
            }).join();
        // value should be either 5 or 6
    }
    
    

    To let it compile, I have to write something like :

        auto value = f1()
            .rightMap([](const struct_a& v){
                return f2();
            })
            .rightMap([](const auto& v){
                return v.rightMap([](const struct_b& v){
                    return 5;
                })
                .leftMap([](const auto& my_error){
                    return 6;
                });
            })
            .leftMap([](const auto& my_error){
                return 6;
            }).join();
        // value should be either 5 or 6
    

    what is the sense of the library if it is not composable, i.e. forces me to unwrap in the next right_map the monadic result of the previous right_map and duplicate errors handling ?

    WBR, basiliscos

    opened by basiliscos 14
  • Uniform initialization causes problems with gcc

    Uniform initialization causes problems with gcc

    Uniform initialization (curly braces initialization) is being used in either.hpp, and while there should be nothing wrong with that some compilers do not handle this well.

    For instance, uniform initialization causes problems with nlohmann's json library compiled with gcc, as backed with this issue: https://github.com/nlohmann/json/issues/985

    So, using neither with gcc and json objects causes the latter being modified.

    As an excercise I have removed uniform initialization from either.hpp and after that Either wrapped around json I was playing with worked as expected.

    opened by WojciechMigda 4
  • Handling polymorphic errors and values

    Handling polymorphic errors and values

    Does this library support polymorphism on the left-hand-side or the right-hand-side of the Either type? Looking at the code right now, it doesn't look like it because the value will be moved into the supertype. If this is true, I would like to propose this as a feature.

    It would probably require some bit-fiddling and storing the data as a raw buffer, but I'm quite certain it can work.

    opened by ghost 3
  • Support for non-copyable objects in lvalues

    Support for non-copyable objects in lvalues

    !READ DESCRIPTION FIRST! Not up to merge yet.

    If you would be willing to adopt these changes I will also adjust neither::Maybe (and neither::lift if needed). Please give feedback if this matches your design concept. Unfortunately I did not find a contribution policy in the repository. :(

    Contents This relaxes the restrictions on using the library with types that are not copy-constructible. It leverages the SFINAE idiom to provide proper implementation for types like std::unique_ptrs. This should not change behavior of existing code, as the template candidates only apply to cases, where previously compilation would not be possible.

    Changes

    • Extend neither::Either with template candidates for non-copyable types.
    • Provide additional tests for the Either class regarding use of non-copyable types.
    opened by tmattha 2
  • Feature: Add Maybe#size() and Maybe#empty() compatible with STL containers

    Feature: Add Maybe#size() and Maybe#empty() compatible with STL containers

    The goal is to make maybe more compatible with STL containers.

    Two useful member functions are:

    • size
    • empty

    The second can also lead us to make hasValue a private member value in the future, but it could break existing client code..

    Another small change is to treat hasValue with true/false, instead of 1/0, so it can more clearly expresses the intention of the code.

    opened by rvarago 2
  • Fix copy constructors

    Fix copy constructors

    The copy constructors for neither::Either and neither::Maybe have been updated to use proper copy-construction using a placement new.

    Note: These values won't need to be deleted manually, but they will probably need to be manually destroyed, which the library already does.

    opened by dvdfreitag 2
  • Remove copy construction from argument to std::move in rightMap &&

    Remove copy construction from argument to std::move in rightMap &&

    When rightMap is applied to Either containing non-copyable type instance, such as std::unique_ptr<T>, then the compiler will hard fail trying to deduce types (rightMap && should be picked) because there is (R2) cast applied to std::move argument, thus forcing copy construction.

    leftMap works because it does not have such cast.

    opened by WojciechMigda 1
  • No license defined

    No license defined

    I would really like to use this implementation in my project but there is no license defined. Without it standard copyright laws hold. Is there any chance for some permissive license?

    opened by tinez 1
  • add a static object none for maybe<void>()

    add a static object none for maybe()

    current api requires you to write:

    Maybe<int> maybeMeaningOfLife(int x) {
      if(x<0) return maybe();  // none; would be better
      return maybe(42);
    }
    
    opened by nikhedonia 1
  • Silence 'defined but not used' warning

    Silence 'defined but not used' warning

    Compilation of maybe.hpp with g++ 7.3 results in the following warning being emitted (here with -Werror enabled):

    neither/maybe.hpp:112:8: error: ‘bool neither::{anonymous}::equal(const neither::Maybe&, const neither::Maybe&)’ defined but not used [-Werror=unused-function] bool equal(Maybe const&, Maybe const&) {

    opened by WojciechMigda 0
  • Maybe: Add static const object none

    Maybe: Add static const object none

    That is an instance of type Maybe, used to represent the absence of a value.

    Additionally, added support for operator== and operator!= for Maybe, hence none, with the semantics:

    Maybe<void> x;
    Maybe<void> y;
    
    x == y => true
    x != y => false
    

    Given that it doesn't hold a value. Therefore, none will be always equal to itself.

    opened by rvarago 0
  • Build fails on Windows 10 using Visual C++ 2019 with Bazel

    Build fails on Windows 10 using Visual C++ 2019 with Bazel

    I'm using the Visual C++ 19.27.29110 compiler on Windows 10.

    ❯ bazel test "@com_loopperfect_neither//:all_tests"
    INFO: Analyzed 4 targets (0 packages loaded, 0 targets configured).
    INFO: Found 4 test targets...
    ERROR: C:/tmp/yhlvxsm5/external/com_loopperfect_neither/BUILD.bazel:42:8: C++ compilation of rule '@com_loopperfect_neither//:lift_test' failed (Exit 2): cl.exe failed: error executing command
      cd C:/tmp/yhlvxsm5/execroot/__main__
      SET INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\ATLMFC\include;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\include;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\winrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\cppwinrt
        SET PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\\Extensions\Microsoft\IntelliCode\CLI;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.27.29110\bin\HostX64\x64;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\VC\VCPackages;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\bin\Roslyn;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Team Tools\Performance Tools\x64;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Team Tools\Performance Tools;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\\x64;C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64\;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\FSharp\;C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64;C:\Program Files (x86)\Windows Kits\10\bin\x64;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\\MSBuild\Current\Bin;C:\Windows\Microsoft.NET\Framework64\v4.0.30319;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\;;C:\WINDOWS\system32;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\VC\Linux\bin\ConnectionManagerExe
        SET PWD=/proc/self/cwd
        SET TEMP=C:\Users\yesudeep\AppData\Local\Temp
        SET TMP=C:\Users\yesudeep\AppData\Local\Temp
      C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.27.29110/bin/HostX64/x64/cl.exe /nologo /DCOMPILER_MSVC /DNOMINMAX /D_WIN32_WINNT=0x0601 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_SECURE_NO_WARNINGS /bigobj /Zm500 /EHsc /wd4351 /wd4291 /wd4250 /wd4996 /Iexternal/com_loopperfect_neither /Ibazel-out/x64_windows-fastbuild/bin/external/com_loopperfect_neither /Iexternal/com_google_googletest /Ibazel-out/x64_windows-fastbuild/bin/external/com_google_googletest /Iexternal/bazel_tools /Ibazel-out/x64_windows-fastbuild/bin/external/bazel_tools /Ibazel-out/x64_windows-fastbuild/bin/external/com_loopperfect_neither/_virtual_includes/neither /Iexternal/com_loopperfect_neither/neither/include /Ibazel-out/x64_windows-fastbuild/bin/external/com_loopperfect_neither/neither/include /Iexternal/com_google_googletest/googlemock /Ibazel-out/x64_windows-fastbuild/bin/external/com_google_googletest/googlemock /Iexternal/com_google_googletest/googlemock/include /Ibazel-out/x64_windows-fastbuild/bin/external/com_google_googletest/googlemock/include /Iexternal/com_google_googletest/googletest /Ibazel-out/x64_windows-fastbuild/bin/external/com_google_googletest/googletest /Iexternal/com_google_googletest/googletest/include /Ibazel-out/x64_windows-fastbuild/bin/external/com_google_googletest/googletest/include /showIncludes /MD /Od /Z7 /wd4117 -D__DATE__="redacted" -D__TIMESTAMP__="redacted" -D__TIME__="redacted" -DHAVE_BAZEL_BUILD /DHAVE_BAZEL_BUILD_WINDOWS /D_HAS_DEPRECATED_RESULT_OF=1 /std:c++latest /Fobazel-out/x64_windows-fastbuild/bin/external/com_loopperfect_neither/_objs/lift_test/lift.obj /c external/com_loopperfect_neither/neither/tests/lift.cpp
    Execution platform: @local_config_platform//:host
    C:\tmp\yhlvxsm5\execroot\__main__\bazel-out\x64_windows-fastbuild\bin\external\com_loopperfect_neither\_virtual_includes\neither\neither/either.hpp(149): error C2560: 'common_type<L2,R2>::type neither::Either<L,R>::join(void) &&': cannot overload a member function with ref-qualifier with a member function without ref-qualifier
    C:\tmp\yhlvxsm5\execroot\__main__\bazel-out\x64_windows-fastbuild\bin\external\com_loopperfect_neither\_virtual_includes\neither\neither/either.hpp(304): note: see reference to class template instantiation 'neither::Either<L,R>' being compiled
    INFO: Elapsed time: 2.906s, Critical Path: 1.80s
    INFO: 0 processes.
    FAILED: Build did NOT complete successfully
    @com_loopperfect_neither//:either_test                                NO STATUS
    @com_loopperfect_neither//:maybe_test                                 NO STATUS
    @com_loopperfect_neither//:try_test                                   NO STATUS
    @com_loopperfect_neither//:lift_test                            FAILED TO BUILD
    
    FAILED: Build did NOT complete successfully
    

    Bazel build file for reference:

    load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
    
    licenses(["notice"])  # MIT License
    
    exports_files(["LICENSE.txt"])
    
    cc_library(
        name = "neither",
        hdrs = [
            "neither/include/either.hpp",
            "neither/include/lift.hpp",
            "neither/include/maybe.hpp",
            "neither/include/neither.hpp",
            "neither/include/traits.hpp",
            "neither/include/try.hpp",
        ],
        include_prefix = "neither",
        includes = ["neither/include"],
        linkstatic = True,
        strip_include_prefix = "neither/include",
        visibility = ["//visibility:public"],
    )
    
    test_suite(
        name = "all_tests",
        tests = [
            ":either_test",
            ":lift_test",
            ":maybe_test",
            ":try_test",
        ],
    )
    
    cc_test(
        name = "either_test",
        size = "small",
        srcs = [
            "neither/tests/either.cpp",
        ],
        deps = [
            ":neither",
            "@com_google_googletest//:gtest_main",
        ],
    )
    
    cc_test(
        name = "lift_test",
        size = "small",
        srcs = [
            "neither/tests/lift.cpp",
        ],
        deps = [
            ":neither",
            "@com_google_googletest//:gtest_main",
        ],
    )
    
    cc_test(
        name = "maybe_test",
        size = "small",
        srcs = [
            "neither/tests/maybe.cpp",
        ],
        deps = [
            ":neither",
            "@com_google_googletest//:gtest_main",
        ],
    )
    
    cc_test(
        name = "try_test",
        size = "small",
        srcs = [
            "neither/tests/try.cpp",
        ],
        deps = [
            ":neither",
            "@com_google_googletest//:gtest_main",
        ],
    )
    
    opened by yesudeep 1
  • Possibly revert #30

    Possibly revert #30

    Hey neither developers, Hey @nikhedonia,

    so I contributed #30 some time ago and promised to implement some move specializations for neither::Maybe which I just started. However, I was not a 100% convinced of my implementation for Eithers at that time and now ran into more issues with neither::Maybe. Mostly that the hasValue attribute needed to be mutable now.

    My main concern is that pull #30 introduced mutations to Eithers, which are not directly visible to the developer. Given that a stored value is not copy-constructible the Either would lose its value on map & join. At that time I thought this was the pill one had to swallow to work with unique_ptrs in lvalues.

    Now it dawned on me that you can always std::move the object to retrieve an rvalue again. Here is a very minimal example:

    TEST(neither, either_fromLvalueByMove) {
      neither::Either<std::unique_ptr<int>, int> e = left(std::make_unique<int>(0));
      std::move(e).leftMap([](auto ptr) {
        EXPECT_EQ(*ptr, 0);
        return std::move(ptr);
        });
    }
    

    From my POV this is much more clear as it shows clearly that e is potentially no longer usable after this operation. Therefore I would suggest to revert this pull and to just add some documentation on some common and niche use cases to the documentation.

    Kind regards Tilmann

    opened by tmattha 0
  • make Either constexpr if possible

    make Either constexpr if possible

    Currently either is never constexpr because it implements a destructor. This is needed in the generic case as the types for left or right might have a custom destructor. Using type_traits we can test if this is the case and make Either a literal type(constexpr) if we deal with pods only.

    opened by nikhedonia 0
  • Implement iterator api

    Implement iterator api

    A Maybe is a container like vector but has either 0 or 1 element. This would be convenient:

    for(auto x : maybe(1) ) {
      std::cout << x << std::endl; // prints 1
    } 
    
    for(auto x : maybe<int>() ) {
      //loop not entered
    } 
    
    

    Functional maps should never have sideeffects. For sideeffects this way should be preferred.

    enhancement help wanted 
    opened by nikhedonia 2
Releases(v0.5.0)
Owner
LoopPerfect
C++ Dev Tools Company
LoopPerfect
An CPP Adaptation of esHTML. For better porpuses.

Keepy Keepy is a pseudo-language / HTML preprocessor that translates special syntax into HTML with the peculiarity of being a "compiled pseudo-languag

Alex 1 Jan 1, 2022
Hello, I am creating this file to make everyone understand the basis of C++ language which is actually the advanced version of C but better than C because of its OOPs feature.

Hello-in-C++ ?? ?? FOR BEGINNERS IN C++ Hello, I am creating this file to make everyone understand the basics of C++ language which is actually the ad

Ankita Mohan 2 Dec 27, 2021
The C++ Core Guidelines are a set of tried-and-true guidelines, rules, and best practices about coding in C++

The C++ Core Guidelines are a collaborative effort led by Bjarne Stroustrup, much like the C++ language itself. They are the result of many person-years of discussion and design across a number of organizations. Their design encourages general applicability and broad adoption but they can be freely copied and modified to meet your organization's needs.

Standard C++ Foundation 36.6k Jan 6, 2023
Welcome to my dungeon. Here, I keep all my configuration files in case I have a stroke and lose all my memory. You're very welcome to explore and use anything in this repository. Have fun!

Fr1nge's Dotfiles Welcome to my dungeon. Here, I keep all my configuration files in case I have a stroke an d lose all my memory. You're very welcome

Fr1nge 33 Oct 28, 2022
This repository contains notes and starter code for Bit manipulation and mathematics session for DSA bootcamp organized by Codeflows.

Bitmanipulation_maths This repository contains notes and starter code for Bit manipulation and mathematics session for DSA bootcamp organized by Codef

Joe 7 Jun 15, 2022
cpp fundamentals and questions for beginners and intermediates

DSA 60 days Hi people! So we have started grasping dsa concepts and solving problems from 12 July. And we shall continue till September 10 Starting fr

Sushree Satarupa 211 Jan 5, 2023
A demonstration of implementing, and using, a "type safe", extensible, and lazy iterator interface in pure C99.

c-iterators A demonstration of implementing, and using, a "type safe", extensible, and lazy iterator interface in pure C99. The iterable is generic on

Chase 69 Jan 2, 2023
About Write a program to create a circular doubly linked list and perform insertions and deletions of various cases

Write a program to create a circular doubly linked list and perform insertions and deletions of various cases Circular Doubly Linked List Circular Dou

MH Miyazi 3 Aug 28, 2021
This repository aims to solve and create new problems from different spheres of coding. A path to help students to get access to solutions and discuss their doubts.

CPP-Questions-and-Solutions ?? This repository aims to solve and create new problems from different spheres of coding, which will serve as a single po

null 49 Oct 3, 2022
The Repository Contains all about Data Structure and Algorithms with Practice problems, series, and resources to follow!

?? The Complete DSA Preparation ?? This repository contains all the DSA (Data-Structures, Algorithms, 450 DSA by Love Babbar Bhaiya,STriver Series ,FA

Pawan Roshan Gupta 5 Oct 6, 2022
Starting with OpenCV and Qt on MacOS is a bit of difficult if you haven't installed and used libraries in XCode.

OpenCV and Qt on MacOS Introduction Starting with OpenCV and Qt on MacOS is a bit of difficult if you haven't installed and used libraries in XCode. T

Martin Kersting 3 Oct 20, 2022
A place where you can learn and practise various Problems and algorithms

Problem-Solving Problem solving is an art of solving some real time challenges. And this is a place to get started, you can find many problems to solv

Google DSC, GVP Chapter 10 Apr 22, 2022
This repo is created to post all my codes and learning of C++ and DSA in C++

This is a readme file where you can read some documentaton about learning on c++and Data Structures and algorithms . I will be posting each and every

BIPIN GHIMIRE 6 Jul 27, 2022
Slides and other materials from CppCon 2020

CppCon 2020 Presentation Materials https://github.com/CppCon/CppCon2020 is the canonical location for presentations and code from CppCon 2020. For Spe

CppCon 1.6k Dec 31, 2022
Slides and other materials from CppCon 2019

CppCon 2019 Presentation Materials https://github.com/CppCon/CppCon2019 is the canonical location for presentations and code from CppCon 2019. For Spe

CppCon 1.2k Dec 27, 2022
Slides and other materials from CppCon 2018

CppCon 2018 Presentation Materials https://github.com/CppCon/CppCon2018 is the canonical location for presentations and code from CppCon 2018. For Spe

CppCon 1.4k Jan 1, 2023
Slides and other materials from CppCon 2017

CppCon 2017 Presentation Materials https://github.com/CppCon/CppCon2017 is the canonical location for presentations and code from CppCon 2017. For Spe

CppCon 1.7k Jan 4, 2023
Slides and other materials from CppCon 2016

CppCon 2016 Presentation Materials https://github.com/CppCon/CppCon2016 is the canonical location for presentations and code from CppCon 2016. For Spe

CppCon 1.8k Dec 22, 2022
This the contains the test examples and validator tool for the ISPD2021 Wafer-Scale Physics Modeling contest.

This readme documents information regarding the validator/scorer which will be used for the 2021 ISPD Contest problem: Wafer-Scale Physics Modelling

Cerebras 16 Aug 22, 2022