lsils / mockturtle Goto Github PK
View Code? Open in Web Editor NEWC++ logic network library
License: MIT License
C++ logic network library
License: MIT License
Dears,
I've found a possible issue when lut_mapping is used.
I've slightly changed the experiment file experiments/lut_mapping.cpp in this way:
/* mockturtle: C++ logic network library
* Copyright (C) 2018-2019 EPFL
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <string>
#include <vector>
#include <fmt/format.h>
#include <lorina/aiger.hpp>
#include <mockturtle/algorithms/collapse_mapped.hpp>
#include <mockturtle/algorithms/equivalence_checking.hpp>
#include <mockturtle/algorithms/lut_mapping.hpp>
#include <mockturtle/algorithms/miter.hpp>
#include <mockturtle/io/bench_reader.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/networks/klut.hpp>
#include <mockturtle/views/mapping_view.hpp>
#include <experiments.hpp>
#include <mockturtle/mockturtle.hpp>
int main()
{
using namespace experiments;
using namespace mockturtle;
experiment<std::string, uint32_t, double, double, bool> exp( "lut_mapping", "benchmark", "luts", "runtime", "runtime cec", "equivalent" );
for ( auto const& benchmark : epfl_benchmarks( ( adder | bar | max | experiments::random ) & ~mem_ctrl & ~voter ) )
{
fmt::print( "[i] processing {}\n", benchmark );
klut_network aig;
lorina::read_bench( "file.bench", bench_reader( aig ) );
lut_mapping_stats st;
mapping_view<klut_network, true> mapped_aig{aig};
lut_mapping<decltype( mapped_aig ), true>( mapped_aig, {}, &st );
const auto klut = *collapse_mapped_network<klut_network>( mapped_aig );
equivalence_checking_stats ecst;
auto cec = *equivalence_checking( *miter<klut_network>( aig, klut ), {}, &ecst );
exp( benchmark, klut.num_gates(), to_seconds( st.time_total ), to_seconds( ecst.time_total ), cec );
}
exp.save();
exp.table();
return 0;
}
```if file.bench is defined in this way:
INPUT(n2)
OUTPUT(po0)
n0 = gnd
n1 = vdd
n3 = LUT 0x6 (n2, n1)
po0 = LUT 0x2 (n3)
you are going to have the seg fault
kind regards,
Fabrizio
Hi,
I am checking the options of using mockturtle in lgraph (https://github.com/masc-ucsc/lgraph), but I have this seg-fault when I combine optimizations with lut mapping.
The following programs works fine, but if I define BUG1 or BUG2, it has a seg-fault. Looks like the cut_enumeration fails.
#include <iostream>
#include <sstream>
#include <mockturtle/algorithms/cut_enumeration.hpp>
#include <mockturtle/algorithms/resubstitution.hpp>
#include <mockturtle/algorithms/refactoring.hpp>
#include <mockturtle/algorithms/collapse_mapped.hpp>
#include <mockturtle/algorithms/node_resynthesis.hpp>
#include <mockturtle/algorithms/node_resynthesis/akers.hpp>
#include <mockturtle/algorithms/node_resynthesis/direct.hpp>
#include <mockturtle/algorithms/node_resynthesis/mig_npn.hpp>
#include <mockturtle/algorithms/node_resynthesis/xmg_npn.hpp>
#include <mockturtle/algorithms/cleanup.hpp>
#include <mockturtle/generators/arithmetic.hpp>
#include <mockturtle/io/write_bench.hpp>
#include <mockturtle/networks/aig.hpp>
#include <mockturtle/networks/klut.hpp>
#include <mockturtle/networks/mig.hpp>
#include <mockturtle/algorithms/lut_mapping.hpp>
#include <mockturtle/views/mapping_view.hpp>
using namespace mockturtle;
//#define BUG1
//#define BUG2
int main() {
mig_network aig;
mig_network::signal array[32];
mig_network::signal array2[32];
for(int i=0;i<32;i++) {
array[i] = aig.create_pi();
}
array2[0] = aig.create_xor(array[0],array[1]);
for(int i=1;i<32;i++) {
array2[i] = aig.create_xor(array[i],array2[i-1]);
}
aig.create_po( array2[31] );
#ifdef BUG1
resubstitution(aig);
cleanup_dangling(aig);
#endif
#ifdef BUG2
//mig_npn_resynthesis resyn;
akers_resynthesis<mig_network> resyn;
refactoring(aig, resyn);
//const auto mig = node_resynthesis<mig_network>( aig, resyn );
#endif
mapping_view<mig_network, true> mapped_mig{aig};
lut_mapping_params ps;
ps.cut_enumeration_ps.cut_size = 6;
lut_mapping<mapping_view<mig_network, true>, true>( mapped_mig, ps);
auto lut =*collapse_mapped_network<klut_network>(mapped_mig);
write_bench(lut, std::cout);
}
// g++ -std=c++17 -I ../../lib/sparsepp/ -I ../../lib/fmt/ -I ../../lib/ez/ -I ../../lib/kitty/ -I ../../include/ test1.cpp ../../lib/fmt/fmt/*.cc
We've run into an issue where, when optimizing a names_view, the names are not preserved through optimization. We've confirmed this is the case for balancing; it is likely true for other methods as well.
For example
Hi msoeken,
we are currently integrating mockturtle with lgraph
https://github.com/masc-ucsc/lgraph
and running some benchmarks for a woset19 paper
the basic flow is lgraph->mig->klut->lgraph
we notice that there are some internal debug information printed out like this,
it would be good to ifdef out these debug messages, can you help on this?
thanks
INPUT(n1)
INPUT(n2)
INPUT(n6)
INPUT(n10)
INPUT(n14)
INPUT(n18)
INPUT(n22)
INPUT(n26)
INPUT(n30)
INPUT(n34)
INPUT(n38)
OUTPUT(po0)
OUTPUT(po1)
OUTPUT(po2)
OUTPUT(po3)
OUTPUT(po4)
OUTPUT(po5)
OUTPUT(po6)
OUTPUT(po7)
OUTPUT(po8)
OUTPUT(po9)
n0 = gnd
n3 = LUT 0x8e (n0, n1, n2)
n4 = LUT 0xb2 (n0, n1, n2)
n5 = LUT 0xd4 (n0, n3, n4)
n7 = LUT 0x8e (n0, n5, n6)
n8 = LUT 0xb2 (n0, n5, n6)
n9 = LUT 0xd4 (n0, n7, n8)
n11 = LUT 0x8e (n0, n9, n10)
n12 = LUT 0xb2 (n0, n9, n10)
n13 = LUT 0xd4 (n0, n11, n12)
n15 = LUT 0x8e (n0, n13, n14)
n16 = LUT 0xb2 (n0, n13, n14)
n17 = LUT 0xd4 (n0, n15, n16)
n19 = LUT 0x8e (n0, n17, n18)
n20 = LUT 0xb2 (n0, n17, n18)
n21 = LUT 0xd4 (n0, n19, n20)
n23 = LUT 0x8e (n0, n21, n22)
n24 = LUT 0xb2 (n0, n21, n22)
n25 = LUT 0xd4 (n0, n23, n24)
n27 = LUT 0x8e (n0, n25, n26)
po6 = LUT 0x2 (n29)
po7 = LUT 0x2 (n33)
po8 = LUT 0x2 (n37)
po9 = LUT 0x2 (n41)
INPUT(n2)
INPUT(n3)
INPUT(n4)
INPUT(n5)
INPUT(n6)
INPUT(n7)
INPUT(n8)
INPUT(n9)
INPUT(n10)
INPUT(n11)
INPUT(n12)
OUTPUT(po0)
OUTPUT(po1)
OUTPUT(po2)
OUTPUT(po3)
OUTPUT(po4)
OUTPUT(po5)
OUTPUT(po6)
OUTPUT(po7)
OUTPUT(po8)
OUTPUT(po9)
n0 = gnd
n1 = vdd
n13 = LUT 0x6 (n2, n3)
n14 = LUT 0x96 (n2, n3, n4)
n15 = LUT 0x6996 (n2, n3, n4, n5)
n16 = LUT 0x6 (n6, n15)
n17 = LUT 0x96 (n6, n7, n15)
n18 = LUT 0x6996 (n6, n7, n8, n15)
n19 = LUT 0x6 (n9, n18)
n20 = LUT 0x96 (n9, n10, n18)
n21 = LUT 0x6996 (n9, n10, n11, n18)
n22 = LUT 0x6 (n12, n21)
po0 = LUT 0x2 (n13)
po1 = LUT 0x2 (n14)
po2 = LUT 0x2 (n15)
po3 = LUT 0x2 (n16)
po4 = LUT 0x2 (n17)
po5 = LUT 0x2 (n18)
po6 = LUT 0x2 (n19)
po7 = LUT 0x2 (n20)
po8 = LUT 0x2 (n21)
po9 = LUT 0x2 (n22)
Hi,
I am implementing an algorithm that chains together a few operations for MIG graphs, and have noticed that after calling the mig_algebraic_depth_rewriting
operation on a depth view of a MIG graph, I am not able to call the cut_rewriting
operation on the original MIG graph (cut_rewriting
uses the dsd_resynthesis
resynthesis engine that uses direct_resynthesis
as a fallback). In order to attempt to remedy this, I have tried calling the cleanup_dangling
function on the original MIG graph, before calling the cut_rewriting
function. This has solved my issue.
Now, after calling mig_algebraic_depth_rewriting
, when examining the size and depth of the original MIG graph, before and after calling the cleanup_dangling
function, I have observed that the size decreases while the depth remains the same. My question is: is this expected? I am asking because the Mockturtle documentation only specifies that the cleanup_dangling
function should be called after the refactoring
operation, and the documentation for Algebraic Rewriting does not mention that cleanup_dangling
should be called after the operation at all.
Also, if this is the case and the cleanup_dangling
should be called after mig_algebraic_depth_rewriting
, I would like to also ask if it should also be called after any other operation applicable to MIGs except for refactoring
? The operations that I am interested in in particular are: Cut rewriting, MIG algebraic rewriting, Resubstitution and Balancing.
Thanks a lot!
Suspected bug in refactoring
and/or direct_resynthesis
reported by @KamilDre in #511.
Test case and code to reproduce:
module top( x0 , x1 , x2 , y0 );
input x0 , x1 , x2 ;
output y0 ;
wire n4 , n5 , n6 , n7 , n8 , n9 , n10 , n11 , n12 , n13 , n14 , n15 , n16 , n17 , n18 , n19 , n20 , n21 , n22 , n23 , n24 , n25 , n26 , n27 ;
assign n4 = x0 | x1 ;
assign n5 = x1 & ~n4 ;
assign n6 = x1 & ~x2 ;
assign n7 = n5 & ~n6 ;
assign n8 = x1 | n4 ;
assign n9 = n6 | n8 ;
assign n10 = ~n7 & n9 ;
assign n11 = x0 & x1 ;
assign n12 = ~n5 & n6 ;
assign n13 = ~n11 & n12 ;
assign n14 = n10 & ~n13 ;
assign n15 = x0 & ~n4 ;
assign n16 = x0 | n15 ;
assign n17 = x0 & n15 ;
assign n18 = n16 & ~n17 ;
assign n19 = n14 & ~n18 ;
assign n20 = n18 | n19 ;
assign n21 = ( ~n14 & n19 ) | ( ~n14 & n20 ) | ( n19 & n20 ) ;
assign n22 = ~n13 & n18 ;
assign n23 = n10 & ~n22 ;
assign n24 = n17 & ~n23 ;
assign n25 = ~n17 & n23 ;
assign n26 = n24 | n25 ;
assign n27 = n21 | n26 ;
assign y0 = ~n27 ;
endmodule
#include <mockturtle/networks/mig.hpp>
#include <mockturtle/io/verilog_reader.hpp>
#include <mockturtle/algorithms/refactoring.hpp>
#include <mockturtle/algorithms/node_resynthesis/direct.hpp>
#include <mockturtle/utils/debugging_utils.hpp>
#include <lorina/verilog.hpp>
int main()
{
using namespace mockturtle;
mig_network ntk;
auto lorina_res = lorina::read_verilog( "acyclic.v", verilog_reader( ntk ) );
assert( lorina_res == lorina::return_code::success );
assert( network_is_acylic( ntk ) );
direct_resynthesis<mig_network> resyn;
refactoring( ntk, resyn );
if ( network_is_acylic( ntk ) )
return 0; // bug-free
else
return 1; // buggy
}
Note: The reproducibility of the bug using the above case might be platform-dependent, as the bug seems to be related to an uninitialized variable (see below).
Dears,
Looking at the results of this simple code:
lut_mapping_stats st;
mapping_view<klut_network, true> mapped_aig{aig};
lut_mapping<decltype( mapped_aig ), true>( mapped_aig, {}, &st );
const auto klut = *collapse_mapped_network<klut_network>( mapped_aig );
mockturtle::write_bench(klut, std::cout);
I've noticed a possible simple optimization to add to the mockturtle stack.
This is the resulting bench:
INPUT(n2)
INPUT(n3)
INPUT(n4)
INPUT(n5)
INPUT(n6)
INPUT(n7)
INPUT(n8)
INPUT(n9)
INPUT(n10)
INPUT(n11)
INPUT(n12)
INPUT(n13)
INPUT(n14)
INPUT(n15)
INPUT(n16)
INPUT(n17)
INPUT(n18)
INPUT(n19)
INPUT(n20)
INPUT(n21)
INPUT(n22)
INPUT(n23)
INPUT(n24)
INPUT(n25)
INPUT(n26)
INPUT(n27)
INPUT(n28)
INPUT(n29)
INPUT(n30)
INPUT(n31)
INPUT(n32)
INPUT(n33)
INPUT(n34)
INPUT(n35)
INPUT(n36)
INPUT(n37)
OUTPUT(po0)
OUTPUT(po1)
OUTPUT(po2)
OUTPUT(po3)
OUTPUT(po4)
OUTPUT(po5)
OUTPUT(po6)
OUTPUT(po7)
OUTPUT(po8)
OUTPUT(po9)
OUTPUT(po10)
OUTPUT(po11)
OUTPUT(po12)
OUTPUT(po13)
OUTPUT(po14)
OUTPUT(po15)
OUTPUT(po16)
OUTPUT(po17)
OUTPUT(po18)
OUTPUT(po19)
OUTPUT(po20)
OUTPUT(po21)
OUTPUT(po22)
OUTPUT(po23)
OUTPUT(po24)
OUTPUT(po25)
OUTPUT(po26)
OUTPUT(po27)
OUTPUT(po28)
OUTPUT(po29)
OUTPUT(po30)
OUTPUT(po31)
OUTPUT(po32)
OUTPUT(po33)
OUTPUT(po34)
OUTPUT(po35)
OUTPUT(po36)
OUTPUT(po37)
n0 = gnd
n1 = vdd
n38 = LUT 0x9 (n2, n3)
n39 = LUT 0x1 (n4)
n40 = LUT 0x1 (n5)
n41 = LUT 0x1 (n6)
n42 = LUT 0x1 (n7)
n43 = LUT 0x1 (n8)
n44 = LUT 0x1 (n2)
n45 = LUT 0x1 (n9)
n46 = LUT 0x0010 (n10, n11, n12, n15)
n47 = LUT 0x00040000 (n10, n11, n16, n17, n18)
n48 = LUT 0x4000 (n10, n11, n16, n19)
n49 = LUT 0x0040 (n10, n11, n16, n19)
n50 = LUT 0x02 (n10, n20, n21)
n51 = LUT 0x80 (n10, n20, n23)
n52 = LUT 0x10 (n10, n11, n12)
n53 = LUT 0x1 (n15)
n54 = LUT 0x0fff0888 (n10, n20, n52, n53, n49)
n55 = LUT 0x10 (n24, n25, n26)
n56 = LUT 0x0400 (n24, n25, n28, n29)
n57 = LUT 0x00040000 (n24, n25, n28, n29, n30)
n58 = LUT 0x02 (n24, n32, n33)
n59 = LUT 0x2000 (n24, n32, n33, n34)
n60 = LUT 0x08 (n24, n32, n35)
n61 = LUT 0x0302 (n12, n24, n25, n26)
n62 = LUT 0x1 (n24)
n63 = LUT 0xff80 (n25, n28, n62, n61)
n64 = LUT 0xbfffbfff1555bfff (n24, n25, n28, n31, n32, n35)
n65 = LUT 0x1 (n35)
n66 = LUT 0xbfff (n24, n25, n28, n31)
n67 = LUT 0x03020100ffffffff (n12, n24, n25, n26, n27, n66)
n68 = LUT 0x007f7f7f (n24, n32, n65, n63, n67)
n69 = LUT 0x0004 (n10, n11, n16, n36)
n70 = LUT 0x00001000 (n10, n11, n12, n15, n36)
n71 = LUT 0xf080 (n24, n32, n36, n63)
n72 = LUT 0xff20 (n25, n28, n62, n59)
n73 = LUT 0x8 (n36, n72)
n74 = LUT 0xf8 (n24, n32, n63)
n75 = LUT 0x000000000000fddd (n24, n32, n33, n34, n74, n72)
n76 = LUT 0x8 (n36, n75)
n77 = LUT 0x02 (n10, n20, n36)
n78 = LUT 0x0000000004040400 (n10, n11, n16, n17, n18, n36)
n79 = LUT 0x1 (n37)
n80 = LUT 0x1 (n36)
n81 = LUT 0xffffffff01000000 (n10, n11, n12, n13, n80, n77)
n82 = LUT 0x1 (n32)
n83 = LUT 0xff00ff002a000000 (n24, n33, n34, n36, n82, n72)
n84 = LUT 0xe (n76, n83)
n85 = LUT 0x00000222 (n10, n20, n21, n22, n36)
n86 = LUT 0x0000000000010000 (n10, n11, n12, n13, n14, n36)
n87 = LUT 0xfe (n69, n81, n86)
n88 = LUT 0x9 (n2, n81)
po0 = LUT 0x2 (n38)
po1 = LUT 0x2 (n39)
po2 = LUT 0x2 (n40)
po3 = LUT 0x2 (n41)
po4 = LUT 0x2 (n42)
po5 = LUT 0x2 (n43)
po6 = LUT 0x2 (n44)
po7 = LUT 0x2 (n45)
po8 = LUT 0x2 (n46)
po9 = LUT 0x2 (n47)
po10 = LUT 0x2 (n48)
po11 = LUT 0x2 (n49)
po12 = LUT 0x2 (n50)
po13 = LUT 0x2 (n51)
po14 = LUT 0x2 (n54)
po15 = LUT 0x2 (n55)
po16 = LUT 0x2 (n56)
po17 = LUT 0x2 (n57)
po18 = LUT 0x2 (n58)
po19 = LUT 0x2 (n59)
po20 = LUT 0x2 (n60)
po21 = LUT 0x2 (n61)
po22 = LUT 0x2 (n63)
po23 = LUT 0x2 (n64)
po24 = LUT 0x2 (n68)
po25 = LUT 0x2 (n69)
po26 = LUT 0x2 (n70)
po27 = LUT 0x2 (n71)
po28 = LUT 0x2 (n73)
po29 = LUT 0x2 (n76)
po30 = LUT 0x2 (n77)
po31 = LUT 0x2 (n78)
po32 = LUT 0x2 (n79)
po33 = LUT 0x2 (n81)
po34 = LUT 0x2 (n84)
po35 = LUT 0x2 (n85)
po36 = LUT 0x2 (n87)
po37 = LUT 0x2 (n88)
In particular, nodes like n53 could be subsumed in their fanout nodes such as n54. This reduces the number of LUTs and levels of the network without paying too much in code optimization complexity. Not sure if the best place to insert this is before collapse_mapped_network starts or after.
Cheers,
Fabrizio
The issue fixed by #464 seems to be also needed for Clang 10.
In the following line, shouldn't it be "set_visited"?
The README gives the following example:
#include <mockturtle/mockturtle.hpp>
#include <lorina/aiger.hpp>
aig_network aig;
lorina::read_aiger( "file.aig", mockturtle::aiger_reader( aig ) );
const auto cuts = cut_enumeration( aig );
aig.foreach_node( [&]( auto node ) {
std::cout << cuts.cuts( aig.node_to_index( node ) ) << "\n";
} );
When trying to run this, I found I needed to give the namespace for aig_network
. I.e.
-aig_network aig;
+mockturtle::aig_network aig;
All node_to_value[f]
should be node_to_value[ntk.get_node( f )]
(in lines 220, 349, and 353).
(Not sure if this really breaks something but just noticed it.)
https://github.com/lsils/mockturtle/blob/master/include/mockturtle/algorithms/simulation.hpp#L220
Hi
I found some possible issues in the code.
In Solver::addClause_ variable flag is set but not used. Is this intended?
mockturtle/lib/bill/bill/sat/solver/ghack.hpp
Line 2812 in 0b98f81
In Solver::simplifyLearnt variables beforeSize and afterSize are set but not used. There were used when the printf was active.
mockturtle/lib/bill/bill/sat/solver/maple.hpp
Line 2911 in 0b98f81
All these warnings come when option -Werror=unused-but-set-variable is passed to gcc compiler.
Cheers,
Fabrizio
There is an error in the [quality]
tests which is not only about quality differences (regressions).
(Seems to be a problem with partial truth tables.)
Assertion failed: (first.num_vars() == second.num_vars()), function binary_operation, file /mockturtle/lib/kitty/kitty/algorithm.hpp, line 101.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
run_tests is a Catch v2.5.0 host application.
Run with -? for options
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Test quality improvement of MIG k-resubstitution
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/mockturtle/test/algorithms/quality.cpp:202
...........................................................................................................................................................................................................................................................................................................
/mockturtle/test/algorithms/quality.cpp:202: FAILED:
due to a fatal error condition:
SIGABRT - Abort (abnormal termination) signal
===========================================================================================================================================================================================================================================================================================================
test cases: 173 | 172 passed | 1 failed
assertions: 6107 | 6106 passed | 1 failed
fish: Job 1, './test/run_tests' terminated by signal SIGABRT (Abort)
Describe the bug
First of all, I'm not sure whether this is a bug or intended behavior.
I have noticed that the default network implementations do not trigger the on_add
events when their create_pi()
function is called.
I found this behavior misleading as, e.g., depth_view
makes explicit usage of this event type to recompute levels on creation of new nodes. There is a test case in depth_view.cpp
that tests this feature which of course works because PIs are placed in level 0 anyway, i.e., the default-constructed value for the level data type (uint32_t
). To be more precise, PIs show their intended level on creation even though on_add
was never called on them.
I'm currently implementing a view that's similar to depth_view
and I wanted to rely on this event to process new nodes (including PIs) on creation. @lee30sonia recommended to override the create_pi
function and manually call on_add
(many thanks for this idea!). While that provides intended behavior for my use case, it would break as soon as someone introduced a new network type that did trigger on_add
events on create_pi()
because it'd then process PIs twice.
Any input on this matter is welcome. Many thanks in advance!
Experiments fails while parsing benchmarks dec
and mem_ctrl
.
It is unclear with the problem is with the benchmarks files in the repository or the AIGER parser in mockturtle.
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x501801320)
frame #0: 0x000000010003d186 satlut`mockturtle::aiger_reader<mockturtle::aig_network>::on_and(this=0x00007ffeefbff538, index=33, left_lit=24, right_lit=4294967260) const at aiger_reader.hpp:348:18
345 left = _ntk.create_not( left );
346 }
347
-> 348 auto right = signals[right_lit >> 1];
349 if ( right_lit & 1 )
350 {
351 right = _ntk.create_not( right );
When I run mig_algebraic_depth_rewriting_splitters
for c5315.v with the parameter selective
, I found that the run_selective
is endless.
ps_alg_rewrite.strategy = mockturtle::mig_algebraic_depth_rewriting_params::selective;
mig_algebraic_depth_rewriting_splitters(mig, ps_alg_rewrite);
And while in mockturtle::buffer_insertion::optimize can be not finished:
while ( true )
{
mark_critical_paths();
topo_view topo{ntk};
topo.foreach_node( [this, &counter]( auto n ) {
if ( ntk.fanout_size( n ) == 0 || ntk.value( n ) == 0 )
return;
if ( reduce_depth( n ) )
{
mark_critical_paths();
}
else
{
++counter;
}
} );
if ( counter > ntk.size() )
break;
}
Can you help me solve it?
Hello, the latest esoteric issue from me...
I have some code that looks something like:
mockturtle::cut_enumeration_params ps;
ps.cut_size = s;
ps.cut_limit = l;
const auto cuts = mockturtle::cut_enumeration<mockturtle::aig_network::node, true>(aig, ps);
I was using this with an s
of 2
and 3
, which seemed to work fine with an l
of std::numeric_limits<decltype(ps.cut_limit)>::max()
(maybe already unwise...). However, when I go beyond 3
I get an assertion failure:
foo: /home/matthew/foo/mockturtle/include/mockturtle/algorithms/../utils/cuts.hpp:482: CutType& mockturtle::cut_set<CutType, MaxCuts>::add_cut(Iterator, Iterator) [with Iterator = unsigned int*; CutType = mockturtle::cut<16, mockturtle::cut_data<true, mockturtle::empty_cut_data> >; int MaxCuts = 26]: Assertion `_pend != _pcuts.end()' failed.
The default cut_size
is 4
and the default cut_limit
is 26
. I have confirmed that increasing either of these causes this assertion failure. I.e.:
// this fails
ps.cut_size = 4;
ps.cut_limit = 27;
// so does this
ps.cut_size = 5;
ps.cut_limit = 26;
Possibly this is specific to my graph, but I suspect I am doing something wrong in my code. Are 4
and 26
somehow pseudo max values for these fields? I could not find anything in the documentation or comments to indicate this. I am using commit 1e7f423 of mockturtle if this is relevant information.
/tmp/mockturtle/test/algorithms/quality.cpp:151: FAILED:
CHECK( v == std::vector<uint32_t>{{0, 18, 34, 22, 114, 56, 253, 113, 442, 449, 69}} )
with expansion:
{ 0, 18, 34, 22, 114, 56, 268 (0x10c), 118, 472 (0x1d8), 449 (0x1c1), 69 }
==
{ 0, 18, 34, 22, 114, 56, 253, 113, 442 (0x1ba), 449 (0x1c1), 69 }
/tmp/mockturtle/test/algorithms/quality.cpp:164: FAILED:
CHECK( v2 == std::vector<uint32_t>{{0, 18, 34, 21, 115, 55, 254, 118, 443, 449, 66}} )
with expansion:
{ 0, 18, 34, 21, 115, 55, 254, 118, 447 (0x1bf), 449 (0x1c1), 66 }
==
{ 0, 18, 34, 21, 115, 55, 254, 118, 443 (0x1bb), 449 (0x1c1), 66 }
I think maybe the following is caused by my own misunderstanding of mockturtle, but I'm not quite sure where I've gone wrong. When I read in an AIG and attempt to programmatically traverse it, it doesn't contain exactly the gates specified in the input AIG. The network seems to have been optimized before I get a chance to interact with it.
Distilling this to a simple AAG, I'm parsing the following:
aag 18 4 0 4 14
2
4
6
8
10
23
35
36
10 6 2
12 8 2
14 6 4
16 14 12
18 17 12
20 17 14
22 21 19
24 14 12
26 8 4
28 26 24
30 29 24
32 29 26
34 33 31
36 26 24
i0 a0
i1 a1
i2 b0
i3 b1
o0 Z0
o1 Z1
o2 Z2
o3 Z3
which is the following translated AIG: small-circ.zip.
Using the C++ at the bottom of this post to view mockturtle's interpretation of this network, I get the following:
$ ./aigls small-circ.aig
aag 16 4 0 4 12
2
4
6
8
10
23
33
26
10 2 6
12 2 8
14 4 6
16 12 14
18 12 17
20 14 17
22 19 21
24 4 8
26 16 24
28 16 27
30 24 27
32 29 31
As you can see, it has fewer AND gates than the original. From node 12 onwards, it seems to have an altered understanding of the gates. Is this known behavior? Or maybe my input is somehow not canonical with respect to what mockturtle is assuming? If this is an issue with lorina rather than mockturtle, I can move it over there instead. Any help or advice would be greatly appreciated.
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <lorina/aiger.hpp>
#include <mockturtle/mockturtle.hpp>
using net_t = mockturtle::aig_network;
using node_t = mockturtle::aig_network::node;
using signal_t = mockturtle::aig_network::signal;
int main(int argc, char **argv) {
// validate command line arguments
if (argc != 2 || strcmp(argv[1], "--help") == 0) {
std::cerr << "usage: " << argv[0] << " aig_file\n"
<< " list Mockturtle's interpretation of an AIG\n";
return EXIT_FAILURE;
}
// parse the input AIG into memory
net_t aig;
lorina::return_code rc
= lorina::read_aiger(argv[1], mockturtle::aiger_reader(aig));
if (rc != lorina::return_code::success) {
std::cerr << "failed to parse " << argv[1] << "\n";
return EXIT_FAILURE;
}
// print AAG header
std::cout << "aag"
<< " " << (aig.num_pis() + aig.num_gates())
<< " " << aig.num_pis()
<< " 0" // latches (assume none)
<< " " << aig.num_pos()
<< " " << aig.num_gates()
<< "\n";
// print inputs
aig.foreach_pi([&](const node_t &n) {
std::cout << (2 * aig.node_to_index(n)) << "\n";
});
// print outputs
aig.foreach_po([&](const signal_t &s) {
uint32_t index = aig.node_to_index(aig.get_node(s));
uint32_t lsb = aig.is_complemented(s) ? 1 : 0;
std::cout << (2 * index + lsb) << "\n";
});
// print gates
aig.foreach_gate([&](const node_t &n) {
std::cout << (2 * aig.node_to_index(n));
aig.foreach_fanin(n, [&](const signal_t &s) {
uint32_t index = aig.node_to_index(aig.get_node(s));
uint32_t lsb = aig.is_complemented(s) ? 1 : 0;
std::cout << " " << (2 * index + lsb);
});
std::cout << "\n";
});
return EXIT_SUCCESS;
}
Test cases are missing for names_view
.
Please have a look at the following piece of code which tries to synthesize an MIG network wrapped in a names_view from a truth table using akers_synthesis.
#include <mockturtle/networks/mig.hpp>
#include <mockturtle/views/names_view.hpp>
#include <mockturtle/algorithms/akers_synthesis.hpp>
#include <kitty/dynamic_truth_table.hpp>
#include <kitty/constructors.hpp>
int main()
{
kitty::dynamic_truth_table tt(2);
kitty::create_from_binary_string(tt, "0110");
using named_mig = mockturtle::names_view<mockturtle::mig_network>;
named_mig ntk;
ntk = mockturtle::akers_synthesis<named_mig>(tt, tt);
}
I'm using a derivative of ubuntu 18.04 LTS and gcc/g++ 7.4.0. Trying to compile this code leads to the following error output.
./mockturtle/include/mockturtle/views/names_view.hpp:68:51: internal compiler error: in finish_member_declaration, at cp/semantics.c:3018
current_pis.emplace_back( Ntk::make_signal( n ) );
~~~~~~~~~~~~~~~~^~~~~
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-7/README.Bugs> for instructions.
However, by combining declaration and definition of ntk
in the code snippet above, it compiles and works just fine.
auto ntk = mockturtle::akers_synthesis<named_mig>(tt, tt);
Do you have any idea, what is going on here? Thanks a lot for your help!
The issue is the following:
Following is the code:
#include <mockturtle/mockturtle.hpp>
using namespace std;
int main(int argc, char *argv[])
{
//AIG from file
mockturtle::aig_network aig;
lorina::read_aiger("file.aig", mockturtle::aiger_reader(aig));
//Cut enumeration parameters
mockturtle::cut_enumeration_params cp;
cp.cut_size = 3u; //maximum number of leaves
cp.cut_limit = 100u; //maximum number of computed cuts for a node
//Cut enumeration algorithm from mockturtle
auto cuts = mockturtle::cut_enumeration<mockturtle::aig_network, true>(aig, cp);
cout<<"Number of cuts: "<<cuts.total_cuts()<<"\n";
//Node to be substituted, index 21
int node_index = 21;
auto old_node = aig.index_to_node(node_index);
auto& old_node_storage = aig._storage->nodes[old_node];
int child0 = aig._storage->nodes[node_index].children[0u].index;
int child1 = aig._storage->nodes[node_index].children[1u].index;
auto child0_sig = aig.make_signal(aig.index_to_node(child0));
auto child1_sig = aig.make_signal(aig.index_to_node(child1));
//The new node we want instead of the old node
auto new_node = aig.create_and(child0_sig, child1_sig);
aig.substitute_node( old_node, new_node );
cout<<"\nNode substituted...\n";
cleanup_dangling(aig);
cuts = mockturtle::cut_enumeration<mockturtle::aig_network, true>(aig, cp);
cout<<"\nNumber of cuts after substitution: "<<cuts.total_cuts()<<"\n";
}
Thank you in advance for any help!
I found this a few days ago and haven't been able to figure out what's causing it. In most benchmarks there's no problem, but in mem_ctrl from the EPFL benchmark suite, if I apply functional reduction followed by SOP balancing to an AIG, then write the file, it's not equivalent to the original network. Either of them alone (or if I put a different optimization between them) seems to work fine.
mockturtle::aig_network run(mockturtle::aig_network &aig){
mockturtle::sop_rebalancing<mockturtle::aig_network> balfn;
mockturtle::balancing_params bp;
bp.cut_enumeration_ps.cut_size = 4u;
mockturtle::functional_reduction(aig);
aig = mockturtle::balancing(aig, {balfn}, bp);
return aig;
}
failing ABC cec output, in case it helps:
Verification failed for at least 62 outputs: y153 y160 y189 ...
Output y153: Value in Network1 = 0. Value in Network2 = 1.
Input pattern: x55=0 x92=0 x215=0 x221=0 x929=0 x216=0 x833=0 x332=0 x1144=0 x265=0 x228=0 x105=0 x153=0 x166=0 x152=0 x161=0 x234=0 x210=0 x137=0 x95=0 x479=0 x32=0 x225=0 x40=0 x72=0 x102=0 x50=0 x77=0 x88=0 x98=0 x81=0 x64=0 x65=0 x71=0 x83=0 x103=0 x67=0 x69=0 x66=0 x73=0 x45=0 x104=0 x49=0 x89=0 x48=0 x61=0 x76=0 x85=0 x106=0 x68=0 x84=0 x36=0 x82=0 x111=0 x63=0 x107=0 x94=0 x97=0 x108=0 x46=0 x86=0 x53=0 x60=0 x109=0 x110=0 x47=0 x58=0 x91=0 x90=0 x93=0 x70=0 x96=0 x35=0 x51=0 x1091=0 x957=0 x841=0 x829=0 x950=0 x1092=0 x1093=0 x146=0 x299=0 x39=0 x223=0 x222=0 x224=0 x142=0 x198=0 x189=0 x144=0 x174=0 x38=0 x100=0 x87=0 x252=0 x75=0 x54=0 x74=0 x56=0 x62=0 x59=0 x57=0
Any idea what may be causing this? Working around it is easy, but it's been bugging me.
sequential interface is a good start. But to be useful, it should at least support an optional "clock" and a "clock-enable". then it becomes a tuple, not just a pair of ri,ro, i.e., each ro has a supporting set of inputs. It is upto the client to decide to use these or not.
Describe the bug
The optimized circuit was not equivalent to the original one.
To Reproduce
Version: latest (#544)
// common
#include <mockturtle/algorithms/cleanup.hpp>
#include <mockturtle/networks/aig.hpp>
// algorithm under test
#include <mockturtle/algorithms/aig_resub.hpp>
#include <mockturtle/algorithms/resubstitution.hpp>
// cec
#include <mockturtle/algorithms/equivalence_checking.hpp>
#include <mockturtle/algorithms/miter.hpp>
// io
#include <mockturtle/io/aiger_reader.hpp>
#include <mockturtle/io/write_aiger.hpp>
#include <lorina/aiger.hpp>
using namespace mockturtle;
int main()
{
aig_network aig;
auto res = lorina::read_aiger( "fuzz_aigresub_minimized.aig", aiger_reader( aig ) );
aig_network aig_copy = cleanup_dangling( aig );
resubstitution_params ps;
ps.max_pis = 8u;
ps.max_inserts = 5u;
aig_resubstitution( aig, ps );
aig = cleanup_dangling( aig );
write_aiger( aig, "fuzz_aigresub_minimized_opt.aig" );
auto cec = *equivalence_checking( *miter<aig_network>( aig_copy, aig ) );
if ( !cec )
std::cout << "NEQ\n";
return 0;
}
fuzz_aigresub_minimized.aig.txt
(Please remove manually the .txt
extension)
Environment
Additional context
Found by fuzz testing :)
Minimal test case produced by testcase minimizer.
The quality test (to be more specific, "Test quality improvement of MIG cut rewriting with compatibility graph and NPN4 resynthesis"
) does not pass anymore after the fix of #560. This is because cut_rewriting_with_compatibility_graph
tries to substitute with a dead node and "revive" it. There are a few possible fixes:
cut_rewriting_with_compatibility_graph
, as we already know this algorithm is buggy and is not recommended to use.cut_rewriting_with_compatibility_graph
to skip the substitution if the replacement is dead. This will affect the quality of cut_rewriting_with_compatibility_graph
, so the expected number in the quality test will also be modified. Also, is_dead
needs to be implemented for klut_network
.cut_rewriting_with_compatibility_graph
to use substitute_nodes
. For this, substitute_nodes
needs to be implemented for other network types than AIG. With a quick experiment, this fix also affected the quality of cut_rewriting_with_compatibility_graph
, and ended up in an infinite while loop in "Test quality improvement of cut rewriting with AIG NPN4 resynthesis"
, meaning that there might be some other problems...substitute_node
to "revive" it. This will affect other networks and algorithms, but also makes sense to some extent. So the question is: should this be allowed?When I insert buffer for inv6
using dry_run
with the parameter until_sat
, I found that the dry_run
is endless.
And while
in mockturtle::buffer_insertion::optimize
can be not finished:
bool updated;
do {
updated = find_and_move_chunks();
} while ( updated && _ps.optimization_effort == buffer_insertion_params::until_sat );
Can you help me solve it?
The source of inv6.v:
module top( x0 , x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 , x9 , x10 , x11 , x12 , x13 , x14 , x15 , x16 , x17 , x18 , x19 , x20 , x21 , x22 , x23 , x24 , x25 , x26 , x27 , x28 , x29 , x30 , x31 , x32 , y0 , y1 , y2 , y3 , y4 , y5 , y6 , y7 , y8 , y9 , y10 , y11 , y12 , y13 , y14 , y15 , y16 , y17 , y18 , y19 , y20 , y21 , y22 );
input x0 , x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 , x9 , x10 , x11 , x12 , x13 , x14 , x15 , x16 , x17 , x18 , x19 , x20 , x21 , x22 , x23 , x24 , x25 , x26 , x27 , x28 , x29 , x30 , x31 , x32 ;
output y0 , y1 , y2 , y3 , y4 , y5 , y6 , y7 , y8 , y9 , y10 , y11 , y12 , y13 , y14 , y15 , y16 , y17 , y18 , y19 , y20 , y21 , y22 ;
wire n34 , n35 , n36 , n37 , n38 , n39 , n40 , n41 , n42 , n43 , n44 , n45 , n46 , n47 , n48 , n49 , n50 , n51 , n52 , n53 , n54 , n55 , n56 , n57 , n58 , n59 , n60 , n61 , n62 , n63 , n64 , n65 , n66 , n67 , n68 , n69 , n70 , n71 , n72 , n73 , n74 , n75 , n76 , n77 , n78 , n79 , n80 , n81 , n82 , n83 , n84 , n85 , n86 , n87 , n88 , n89 , n90 , n91 , n92 , n93 , n94 , n95 , n96 , n97 , n98 , n99 , n100 , n101 , n102 , n103 , n104 , n105 , n106 , n107 , n108 , n109 , n110 , n111 , n112 , n113 , n114 , n115 , n116 , n117 , n118 , n119 , n120 , n121 , n122 , n123 , n124 , n125 , n126 , n127 , n128 , n129 , n130 , n131 , n132 , n133 , n134 , n135 , n136 , n137 , n138 , n139 , n140 , n141 , n142 , n143 , n144 , n145 , n146 , n147 , n148 , n149 , n150 , n151 , n152 , n153 , n154 , n155 , n156 , n157 , n158 , n159 , n160 , n161 , n162 , n163 , n164 , n165 , n166 , n167 , n168 , n169 , n170 , n171 , n172 , n173 , n174 , n175 , n176 , n177 , n178 , n179 , n180 , n181 , n182 , n183 , n184 , n185 , n186 , n187 , n188 , n189 , n190 , n191 , n192 , n193 , n194 , n195 , n196 , n197 , n198 , n199 , n200 , n201 , n202 , n203 , n204 , n205 , n206 , n207 , n208 , n209 , n210 , n211 , n212 , n213 , n214 , n215 , n216 , n217 , n218 , n219 , n220 , n221 , n222 , n223 , n224 , n225 , n226 , n227 , n228 , n229 , n230 , n231 , n232 , n233 , n234 , n235 , n236 , n237 , n238 , n239 , n240 , n241 , n242 , n243 , n244 , n245 , n246 , n247 , n248 , n249 , n250 , n251 , n252 , n253 , n254 , n255 , n256 , n257 , n258 , n259 , n260 , n261 , n262 , n263 , n264 , n265 , n266 , n267 , n268 , n269 , n270 , n271 , n272 , n273 , n274 , n275 , n276 , n277 , n278 , n279 , n280 , n281 , n282 , n283 , n284 , n285 , n286 , n287 , n288 , n289 , n290 , n291 , n292 , n293 , n294 , n295 , n296 , n297 , n298 , n299 , n300 , n301 , n302 , n303 , n304 , n305 , n306 , n307 , n308 , n309 , n310 , n311 , n312 , n313 , n314 , n315 , n316 , n317 , n318 , n319 , n320 , n321 , n322 , n323 , n324 , n325 , n326 , n327 , n328 , n329 , n330 , n331 , n332 , n333 , n334 , n335 , n336 , n337 , n338 , n339 , n340 , n341 , n342 , n343 , n344 , n345 , n346 , n347 , n348 , n349 , n350 , n351 , n352 , n353 , n354 , n355 , n356 , n357 , n358 , n359 , n360 , n361 , n362 , n363 , n364 , n365 , n366 , n367 , n368 , n369 , n370 , n371 , n372 , n373 , n374 , n375 , n376 , n377 , n378 , n379 , n380 , n381 , n382 ;
assign n34 = ~x16 & x31 ;
assign n35 = ~x15 & n34 ;
assign n37 = x28 & x30 ;
assign n36 = x1 & x22 ;
assign n38 = ( x31 & ~n36 ) | ( x31 & n37 ) | ( ~n36 & n37 ) ;
assign n39 = n37 & ~n38 ;
assign n40 = ( ~x0 & n35 ) | ( ~x0 & n39 ) | ( n35 & n39 ) ;
assign n42 = x1 & x29 ;
assign n41 = x24 & x28 ;
assign n43 = ( x32 & ~n41 ) | ( x32 & n42 ) | ( ~n41 & n42 ) ;
assign n44 = n42 & ~n43 ;
assign n45 = x4 | n44 ;
assign n46 = x32 & ~n45 ;
assign n47 = ( ~x0 & n44 ) | ( ~x0 & n46 ) | ( n44 & n46 ) ;
assign n48 = ~x0 & x3 ;
assign n49 = ( x28 & x30 ) | ( x28 & n48 ) | ( x30 & n48 ) ;
assign n50 = n48 & ~n49 ;
assign n51 = x29 & ~x30 ;
assign n52 = ~x0 & x28 ;
assign n53 = ( x0 & n51 ) | ( x0 & ~n52 ) | ( n51 & ~n52 ) ;
assign n54 = ( x0 & x3 ) | ( x0 & n53 ) | ( x3 & n53 ) ;
assign n80 = x0 | x28 ;
assign n58 = x11 | x12 ;
assign n55 = ( x12 & x21 ) | ( x12 & x29 ) | ( x21 & x29 ) ;
assign n56 = ( ~x12 & x20 ) | ( ~x12 & x29 ) | ( x20 & x29 ) ;
assign n57 = n55 & n56 ;
assign n59 = ( x19 & n57 ) | ( x19 & ~n58 ) | ( n57 & ~n58 ) ;
assign n60 = ( ~x11 & n58 ) | ( ~x11 & n59 ) | ( n58 & n59 ) ;
assign n61 = n58 & n60 ;
assign n66 = ( ~x9 & x10 ) | ( ~x9 & n61 ) | ( x10 & n61 ) ;
assign n62 = x11 & ~x29 ;
assign n63 = ( x11 & ~x21 ) | ( x11 & n62 ) | ( ~x21 & n62 ) ;
assign n64 = ( ~x11 & x12 ) | ( ~x11 & n63 ) | ( x12 & n63 ) ;
assign n65 = ( ~x12 & n58 ) | ( ~x12 & n64 ) | ( n58 & n64 ) ;
assign n67 = ( x9 & x10 ) | ( x9 & ~n65 ) | ( x10 & ~n65 ) ;
assign n68 = n66 & n67 ;
assign n69 = x11 & ~x12 ;
assign n70 = ~x9 & x10 ;
assign n71 = ( x9 & n69 ) | ( x9 & ~n70 ) | ( n69 & ~n70 ) ;
assign n75 = x19 & x20 ;
assign n72 = x10 & ~x11 ;
assign n73 = ~x12 & n72 ;
assign n74 = ( ~x10 & x29 ) | ( ~x10 & n73 ) | ( x29 & n73 ) ;
assign n76 = ( x21 & n74 ) | ( x21 & ~n75 ) | ( n74 & ~n75 ) ;
assign n77 = n75 & n76 ;
assign n78 = x9 & ~n77 ;
assign n79 = ( n68 & n71 ) | ( n68 & ~n78 ) | ( n71 & ~n78 ) ;
assign n81 = ( x30 & n79 ) | ( x30 & n80 ) | ( n79 & n80 ) ;
assign n82 = ~n80 & n81 ;
assign n101 = x0 | x16 ;
assign n83 = x1 & x23 ;
assign n90 = x28 & n83 ;
assign n84 = x15 & ~x17 ;
assign n85 = x7 & ~x17 ;
assign n86 = ( x6 & x15 ) | ( x6 & ~n85 ) | ( x15 & ~n85 ) ;
assign n87 = ( x17 & n84 ) | ( x17 & ~n86 ) | ( n84 & ~n86 ) ;
assign n88 = x15 & x17 ;
assign n89 = ~x14 & n88 ;
assign n91 = ( n87 & n89 ) | ( n87 & n90 ) | ( n89 & n90 ) ;
assign n92 = n90 & n91 ;
assign n95 = ~x14 & x15 ;
assign n96 = ( ~x17 & x28 ) | ( ~x17 & n95 ) | ( x28 & n95 ) ;
assign n97 = n95 & ~n96 ;
assign n93 = ( x11 & x12 ) | ( x11 & n70 ) | ( x12 & n70 ) ;
assign n94 = n70 & ~n93 ;
assign n98 = ~n92 & n94 ;
assign n99 = n97 & n98 ;
assign n100 = ( x30 & n92 ) | ( x30 & n99 ) | ( n92 & n99 ) ;
assign n102 = ( ~x18 & n100 ) | ( ~x18 & n101 ) | ( n100 & n101 ) ;
assign n103 = ~n101 & n102 ;
assign n114 = x1 & ~x9 ;
assign n111 = ~x10 & x11 ;
assign n104 = x23 & ~x28 ;
assign n105 = ~x16 & n104 ;
assign n106 = x6 | x8 ;
assign n107 = x18 & ~n106 ;
assign n108 = ( x6 & x17 ) | ( x6 & n107 ) | ( x17 & n107 ) ;
assign n109 = x17 | x18 ;
assign n110 = ( n105 & n108 ) | ( n105 & ~n109 ) | ( n108 & ~n109 ) ;
assign n112 = ( x12 & n110 ) | ( x12 & ~n111 ) | ( n110 & ~n111 ) ;
assign n113 = n111 & n112 ;
assign n115 = ( x30 & n113 ) | ( x30 & ~n114 ) | ( n113 & ~n114 ) ;
assign n116 = n114 & n115 ;
assign n121 = ~x16 & x17 ;
assign n122 = x16 & x18 ;
assign n123 = x17 & x18 ;
assign n124 = ( x6 & x17 ) | ( x6 & n123 ) | ( x17 & n123 ) ;
assign n125 = ( n121 & n122 ) | ( n121 & ~n124 ) | ( n122 & ~n124 ) ;
assign n117 = ( x28 & n58 ) | ( x28 & n70 ) | ( n58 & n70 ) ;
assign n118 = n70 & ~n117 ;
assign n119 = x28 | n118 ;
assign n120 = ( n83 & n118 ) | ( n83 & n119 ) | ( n118 & n119 ) ;
assign n126 = ( x30 & n120 ) | ( x30 & ~n125 ) | ( n120 & ~n125 ) ;
assign n127 = ( n116 & n125 ) | ( n116 & n126 ) | ( n125 & n126 ) ;
assign n128 = ~x15 & n127 ;
assign n129 = ~x0 & n128 ;
assign n131 = x1 & x18 ;
assign n130 = x0 | x15 ;
assign n132 = ( ~x22 & n130 ) | ( ~x22 & n131 ) | ( n130 & n131 ) ;
assign n133 = n131 & ~n132 ;
assign n134 = ( x18 & n118 ) | ( x18 & n130 ) | ( n118 & n130 ) ;
assign n135 = ~n130 & n134 ;
assign n136 = ( n119 & n133 ) | ( n119 & n135 ) | ( n133 & n135 ) ;
assign n137 = x15 & ~x18 ;
assign n144 = x1 & n137 ;
assign n138 = ( x22 & x28 ) | ( x22 & ~n137 ) | ( x28 & ~n137 ) ;
assign n139 = x9 | x10 ;
assign n140 = ~x28 & n139 ;
assign n141 = ( ~x22 & n137 ) | ( ~x22 & n140 ) | ( n137 & n140 ) ;
assign n142 = x11 & x12 ;
assign n143 = ( n138 & ~n141 ) | ( n138 & n142 ) | ( ~n141 & n142 ) ;
assign n145 = ~n136 & n143 ;
assign n146 = n144 & n145 ;
assign n147 = ( x30 & n136 ) | ( x30 & n146 ) | ( n136 & n146 ) ;
assign n148 = ~x17 & n147 ;
assign n149 = ( x0 & n101 ) | ( x0 & n148 ) | ( n101 & n148 ) ;
assign n150 = x1 & ~x6 ;
assign n151 = ( ~x8 & x10 ) | ( ~x8 & n150 ) | ( x10 & n150 ) ;
assign n152 = n150 & ~n151 ;
assign n153 = ~x17 & x22 ;
assign n154 = x16 & n153 ;
assign n155 = ( ~n142 & n152 ) | ( ~n142 & n154 ) | ( n152 & n154 ) ;
assign n156 = n142 & n155 ;
assign n157 = ~x0 & n156 ;
assign n158 = ( ~x14 & x17 ) | ( ~x14 & n156 ) | ( x17 & n156 ) ;
assign n159 = ( x0 & ~x16 ) | ( x0 & n158 ) | ( ~x16 & n158 ) ;
assign n160 = ( ~x0 & n157 ) | ( ~x0 & n159 ) | ( n157 & n159 ) ;
assign n161 = x10 & ~n58 ;
assign n162 = ( n157 & n160 ) | ( n157 & n161 ) | ( n160 & n161 ) ;
assign n163 = x28 & n36 ;
assign n164 = ( x16 & x17 ) | ( x16 & ~n163 ) | ( x17 & ~n163 ) ;
assign n165 = n163 & ~n164 ;
assign n166 = x9 | x28 ;
assign n167 = ( x30 & n165 ) | ( x30 & ~n166 ) | ( n165 & ~n166 ) ;
assign n168 = ( x16 & x17 ) | ( x16 & ~n58 ) | ( x17 & ~n58 ) ;
assign n169 = n58 | n168 ;
assign n170 = ~x6 & x7 ;
assign n171 = ( x28 & n70 ) | ( x28 & ~n170 ) | ( n70 & ~n170 ) ;
assign n172 = n70 & ~n171 ;
assign n173 = ~n169 & n172 ;
assign n174 = ( x30 & n165 ) | ( x30 & n173 ) | ( n165 & n173 ) ;
assign n175 = ( n162 & n167 ) | ( n162 & n174 ) | ( n167 & n174 ) ;
assign n176 = ~x18 & n175 ;
assign n177 = x15 & n176 ;
assign n178 = x0 | n177 ;
assign n179 = x0 & x7 ;
assign n200 = x16 | x18 ;
assign n180 = x22 & x28 ;
assign n181 = x1 & n180 ;
assign n185 = ( ~x15 & x17 ) | ( ~x15 & n170 ) | ( x17 & n170 ) ;
assign n186 = n170 & ~n185 ;
assign n182 = ( ~x6 & x15 ) | ( ~x6 & x17 ) | ( x15 & x17 ) ;
assign n183 = ( x14 & x15 ) | ( x14 & ~x17 ) | ( x15 & ~x17 ) ;
assign n184 = n182 & ~n183 ;
assign n187 = n184 & ~n186 ;
assign n188 = ~x0 & n187 ;
assign n189 = ( n181 & n186 ) | ( n181 & n188 ) | ( n186 & n188 ) ;
assign n190 = x12 | x14 ;
assign n196 = x30 & ~n190 ;
assign n191 = x15 & ~x28 ;
assign n192 = ( x17 & n190 ) | ( x17 & n191 ) | ( n190 & n191 ) ;
assign n193 = x0 | x9 ;
assign n194 = ( x10 & ~x11 ) | ( x10 & n193 ) | ( ~x11 & n193 ) ;
assign n195 = ~n193 & n194 ;
assign n197 = ( n192 & n195 ) | ( n192 & ~n196 ) | ( n195 & ~n196 ) ;
assign n198 = n196 & n197 ;
assign n199 = ( x30 & n189 ) | ( x30 & n198 ) | ( n189 & n198 ) ;
assign n201 = n179 | n199 ;
assign n202 = ( n179 & ~n200 ) | ( n179 & n201 ) | ( ~n200 & n201 ) ;
assign n232 = ~n58 & n70 ;
assign n228 = ( ~x28 & n58 ) | ( ~x28 & n122 ) | ( n58 & n122 ) ;
assign n215 = x15 & ~x16 ;
assign n226 = ( x18 & ~n170 ) | ( x18 & n215 ) | ( ~n170 & n215 ) ;
assign n227 = n215 & ~n226 ;
assign n229 = ( ~x28 & n58 ) | ( ~x28 & n227 ) | ( n58 & n227 ) ;
assign n230 = n130 & ~n227 ;
assign n231 = ( n228 & n229 ) | ( n228 & ~n230 ) | ( n229 & ~n230 ) ;
assign n233 = n179 | n231 ;
assign n234 = ( n179 & n232 ) | ( n179 & n233 ) | ( n232 & n233 ) ;
assign n203 = x7 & ~x15 ;
assign n204 = ( x16 & x28 ) | ( x16 & n203 ) | ( x28 & n203 ) ;
assign n205 = n203 & ~n204 ;
assign n206 = ( x0 & ~x12 ) | ( x0 & n111 ) | ( ~x12 & n111 ) ;
assign n207 = ( ~x15 & x16 ) | ( ~x15 & n106 ) | ( x16 & n106 ) ;
assign n208 = ( x0 & x15 ) | ( x0 & ~x28 ) | ( x15 & ~x28 ) ;
assign n209 = x6 & ~x16 ;
assign n210 = ( x0 & ~x28 ) | ( x0 & n209 ) | ( ~x28 & n209 ) ;
assign n211 = ( n207 & n208 ) | ( n207 & n210 ) | ( n208 & n210 ) ;
assign n212 = ( x12 & ~n111 ) | ( x12 & n211 ) | ( ~n111 & n211 ) ;
assign n213 = ( n205 & ~n206 ) | ( n205 & n212 ) | ( ~n206 & n212 ) ;
assign n214 = n111 & n213 ;
assign n216 = ( x28 & n170 ) | ( x28 & ~n215 ) | ( n170 & ~n215 ) ;
assign n217 = n215 & n216 ;
assign n218 = n214 & ~n217 ;
assign n219 = ~x9 & n218 ;
assign n220 = ( ~x28 & n122 ) | ( ~x28 & n130 ) | ( n122 & n130 ) ;
assign n221 = n122 & ~n220 ;
assign n222 = ( ~x18 & n36 ) | ( ~x18 & n221 ) | ( n36 & n221 ) ;
assign n223 = n36 & n222 ;
assign n224 = ( n36 & n217 ) | ( n36 & n221 ) | ( n217 & n221 ) ;
assign n225 = n36 & n224 ;
assign n235 = ( n219 & n223 ) | ( n219 & n225 ) | ( n223 & n225 ) ;
assign n236 = n234 | n235 ;
assign n237 = ~x17 & x30 ;
assign n238 = ( n179 & n236 ) | ( n179 & n237 ) | ( n236 & n237 ) ;
assign n242 = x1 & ~x10 ;
assign n239 = x12 & ~x16 ;
assign n240 = ( x17 & x23 ) | ( x17 & ~n239 ) | ( x23 & ~n239 ) ;
assign n241 = n239 & n240 ;
assign n243 = ( x11 & n241 ) | ( x11 & ~n242 ) | ( n241 & ~n242 ) ;
assign n244 = n242 & n243 ;
assign n245 = x16 & ~x17 ;
assign n246 = ( x28 & ~n161 ) | ( x28 & n245 ) | ( ~n161 & n245 ) ;
assign n247 = n245 & ~n246 ;
assign n248 = ( ~x9 & n244 ) | ( ~x9 & n247 ) | ( n244 & n247 ) ;
assign n249 = x18 & x30 ;
assign n250 = ~x15 & n249 ;
assign n251 = ( x16 & x17 ) | ( x16 & ~x23 ) | ( x17 & ~x23 ) ;
assign n252 = ( x16 & x17 ) | ( x16 & x28 ) | ( x17 & x28 ) ;
assign n253 = ~n251 & n252 ;
assign n254 = ~n248 & n253 ;
assign n255 = x1 & n254 ;
assign n256 = ( n248 & n250 ) | ( n248 & n255 ) | ( n250 & n255 ) ;
assign n257 = ~x0 & n256 ;
assign n258 = x0 & ~x7 ;
assign n259 = n257 | n258 ;
assign n267 = x6 | x15 ;
assign n260 = x1 & ~x8 ;
assign n261 = ( x10 & ~x23 ) | ( x10 & n260 ) | ( ~x23 & n260 ) ;
assign n262 = n260 & ~n261 ;
assign n263 = ( x18 & ~n142 ) | ( x18 & n262 ) | ( ~n142 & n262 ) ;
assign n264 = n142 & n263 ;
assign n265 = ( x12 & x18 ) | ( x12 & n72 ) | ( x18 & n72 ) ;
assign n266 = n72 & ~n265 ;
assign n268 = ( n264 & n266 ) | ( n264 & ~n267 ) | ( n266 & ~n267 ) ;
assign n269 = ~n267 & n268 ;
assign n270 = ( x18 & n95 ) | ( x18 & ~n161 ) | ( n95 & ~n161 ) ;
assign n271 = n95 & ~n270 ;
assign n272 = ( ~n166 & n269 ) | ( ~n166 & n271 ) | ( n269 & n271 ) ;
assign n273 = ~n166 & n272 ;
assign n274 = ( x15 & x18 ) | ( x15 & ~n90 ) | ( x18 & ~n90 ) ;
assign n275 = n90 & ~n274 ;
assign n276 = ( x30 & n273 ) | ( x30 & n275 ) | ( n273 & n275 ) ;
assign n277 = ( n121 & n179 ) | ( n121 & n276 ) | ( n179 & n276 ) ;
assign n278 = ( x0 & ~n179 ) | ( x0 & n277 ) | ( ~n179 & n277 ) ;
assign n279 = ~n179 & n278 ;
assign n280 = x24 & ~x25 ;
assign n281 = ~x0 & n280 ;
assign n282 = ( x25 & x29 ) | ( x25 & n281 ) | ( x29 & n281 ) ;
assign n283 = x28 & n282 ;
assign n284 = x0 | x1 ;
assign n285 = ( x0 & n283 ) | ( x0 & n284 ) | ( n283 & n284 ) ;
assign n286 = ~x0 & x1 ;
assign n287 = ( ~x13 & x22 ) | ( ~x13 & n286 ) | ( x22 & n286 ) ;
assign n288 = n286 & ~n287 ;
assign n289 = ( x29 & ~n41 ) | ( x29 & n288 ) | ( ~n41 & n288 ) ;
assign n290 = n41 & n289 ;
assign n292 = x1 & x28 ;
assign n291 = ~x0 & x24 ;
assign n293 = ( x29 & n291 ) | ( x29 & ~n292 ) | ( n291 & ~n292 ) ;
assign n294 = n292 & n293 ;
assign n295 = x5 | x22 ;
assign n296 = ( x5 & n37 ) | ( x5 & n295 ) | ( n37 & n295 ) ;
assign n297 = ~x0 & n296 ;
assign n298 = ( ~x28 & x30 ) | ( ~x28 & n58 ) | ( x30 & n58 ) ;
assign n299 = ~n58 & n298 ;
assign n300 = ( x10 & n193 ) | ( x10 & n299 ) | ( n193 & n299 ) ;
assign n301 = ~n193 & n300 ;
assign n302 = x26 & ~x27 ;
assign n303 = x3 & n302 ;
assign n304 = ( x26 & n301 ) | ( x26 & ~n303 ) | ( n301 & ~n303 ) ;
assign n305 = x0 | n304 ;
assign n306 = x3 & x27 ;
assign n307 = ( x3 & x26 ) | ( x3 & n306 ) | ( x26 & n306 ) ;
assign n308 = ( n301 & ~n306 ) | ( n301 & n307 ) | ( ~n306 & n307 ) ;
assign n309 = ( x27 & ~n306 ) | ( x27 & n308 ) | ( ~n306 & n308 ) ;
assign n310 = x0 | n309 ;
assign n311 = ~x28 & x30 ;
assign n312 = ~x0 & n311 ;
assign n313 = x10 | x12 ;
assign n314 = x9 | n313 ;
assign n315 = x12 & x21 ;
assign n316 = ( x9 & x29 ) | ( x9 & n315 ) | ( x29 & n315 ) ;
assign n317 = ( x12 & x19 ) | ( x12 & x21 ) | ( x19 & x21 ) ;
assign n318 = ( ~x12 & x19 ) | ( ~x12 & x20 ) | ( x19 & x20 ) ;
assign n319 = n317 & n318 ;
assign n320 = ( ~x9 & x29 ) | ( ~x9 & n319 ) | ( x29 & n319 ) ;
assign n321 = n316 & n320 ;
assign n322 = x10 & n321 ;
assign n323 = ( x11 & ~n314 ) | ( x11 & n322 ) | ( ~n314 & n322 ) ;
assign n324 = x12 | n77 ;
assign n325 = ( n72 & n77 ) | ( n72 & n324 ) | ( n77 & n324 ) ;
assign n326 = x9 & ~n323 ;
assign n327 = n325 & n326 ;
assign n328 = ( n312 & n323 ) | ( n312 & n327 ) | ( n323 & n327 ) ;
assign n332 = x3 & ~x29 ;
assign n333 = x30 | n332 ;
assign n335 = x10 & x11 ;
assign n334 = x21 & x29 ;
assign n336 = ( x12 & n334 ) | ( x12 & ~n335 ) | ( n334 & ~n335 ) ;
assign n337 = n335 & n336 ;
assign n349 = ( x9 & x30 ) | ( x9 & ~n337 ) | ( x30 & ~n337 ) ;
assign n341 = ~x11 & x12 ;
assign n338 = ~x12 & x19 ;
assign n339 = ( x21 & x29 ) | ( x21 & ~n338 ) | ( x29 & ~n338 ) ;
assign n340 = n338 & n339 ;
assign n342 = ( x10 & ~x11 ) | ( x10 & n340 ) | ( ~x11 & n340 ) ;
assign n343 = ( x11 & n341 ) | ( x11 & n342 ) | ( n341 & n342 ) ;
assign n346 = ~x10 & n334 ;
assign n344 = ( x11 & ~x12 ) | ( x11 & n75 ) | ( ~x12 & n75 ) ;
assign n345 = n75 & n344 ;
assign n347 = n343 | n345 ;
assign n348 = ( n343 & n346 ) | ( n343 & n347 ) | ( n346 & n347 ) ;
assign n350 = ( x9 & ~x30 ) | ( x9 & n348 ) | ( ~x30 & n348 ) ;
assign n351 = n349 & ~n350 ;
assign n329 = ( x3 & x29 ) | ( x3 & x30 ) | ( x29 & x30 ) ;
assign n330 = ( x2 & x29 ) | ( x2 & ~x30 ) | ( x29 & ~x30 ) ;
assign n331 = ~n329 & n330 ;
assign n352 = x28 | n331 ;
assign n353 = ( n333 & ~n351 ) | ( n333 & n352 ) | ( ~n351 & n352 ) ;
assign n354 = ( x0 & ~x28 ) | ( x0 & n353 ) | ( ~x28 & n353 ) ;
assign n370 = ( x3 & ~x28 ) | ( x3 & x30 ) | ( ~x28 & x30 ) ;
assign n371 = ~x0 & n370 ;
assign n358 = ( x11 & ~x12 ) | ( x11 & n139 ) | ( ~x12 & n139 ) ;
assign n359 = ~n139 & n358 ;
assign n355 = x9 & x12 ;
assign n356 = ( x21 & x29 ) | ( x21 & ~n355 ) | ( x29 & ~n355 ) ;
assign n357 = n355 & n356 ;
assign n360 = n75 & n357 ;
assign n361 = ( ~x10 & n359 ) | ( ~x10 & n360 ) | ( n359 & n360 ) ;
assign n364 = ~x12 & x21 ;
assign n365 = ~x11 & n364 ;
assign n366 = ( ~n111 & n142 ) | ( ~n111 & n365 ) | ( n142 & n365 ) ;
assign n367 = x9 & n366 ;
assign n362 = x20 & x29 ;
assign n363 = x19 & n362 ;
assign n368 = n361 | n363 ;
assign n369 = ( n361 & n367 ) | ( n361 & n368 ) | ( n367 & n368 ) ;
assign n372 = ( x28 & x30 ) | ( x28 & ~n369 ) | ( x30 & ~n369 ) ;
assign n373 = n371 & ~n372 ;
assign n380 = ~x28 & x29 ;
assign n377 = x12 & x19 ;
assign n374 = ~x0 & x9 ;
assign n375 = ( x10 & x11 ) | ( x10 & ~n374 ) | ( x11 & ~n374 ) ;
assign n376 = n374 & n375 ;
assign n378 = ( x20 & n376 ) | ( x20 & ~n377 ) | ( n376 & ~n377 ) ;
assign n379 = n377 & n378 ;
assign n381 = ( x30 & n379 ) | ( x30 & ~n380 ) | ( n379 & ~n380 ) ;
assign n382 = n380 & n381 ;
assign y0 = n40 ;
assign y1 = n47 ;
assign y2 = n50 ;
assign y3 = n54 ;
assign y4 = n82 ;
assign y5 = n103 ;
assign y6 = n129 ;
assign y7 = n149 ;
assign y8 = n178 ;
assign y9 = n202 ;
assign y10 = n238 ;
assign y11 = n259 ;
assign y12 = n279 ;
assign y13 = n285 ;
assign y14 = n290 ;
assign y15 = n294 ;
assign y16 = n297 ;
assign y17 = n305 ;
assign y18 = n310 ;
assign y19 = n328 ;
assign y20 = n354 ;
assign y21 = n373 ;
assign y22 = n382 ;
endmodule
Describe the bug
When compiling with different toolsets under Windows, it becomes apparent that certain constructs do not compile.
To Reproduce
To be seen in #530.
Environment
Additional context
I suspect this to be the tip of the iceberg, unfortunately, as I had some further issues down the road when compiling any code involving bill
under Windows with the v142 toolset. It would always complain that it misses __sync_bool_compare_and_swap
in glucose.hpp
(the actual solver). However, that will be a different issue. I would be glad to assist in the process of fixing these problems.
Check list
Hello,
I am evaluating to include mockturtle as part of LGraph. LGraph is a BSD3 license, but it excludes 3rd party repositories that have known patents (same was as LLVM does) (https://github.com/masc-ucsc/lgraph/blob/master/docs/CONTRIBUTING.md#Patents)
Is there any pass in mockturtle that I should not use if I am concerned about patents?
Describe the bug
There has been a known bug that mockturtle/algorithms/akers_synthesis.hpp
produces incorrect results for some functions.
To Reproduce
Failing test case:
TEST_CASE( "Akers regressions", "[akers_synthesis]" )
{
for ( std::string const& function : std::vector<std::string>{ "0000", "3333", "5555", "aaaa", "cccc", "f0f0", "0f0f", "ffff" } )
{
kitty::dynamic_truth_table f( 4 ), care( 4 );
create_from_hex_string( f, function );
for ( auto i = 0u; i < unsigned( f.num_bits() ); i++ )
{
set_bit( care, i );
}
std::vector<kitty::dynamic_truth_table> xs{6, kitty::dynamic_truth_table( 4 )};
xs[0] = f;
xs[1] = care;
kitty::create_nth_var( xs[2], 0 );
kitty::create_nth_var( xs[3], 1 );
kitty::create_nth_var( xs[4], 2 );
kitty::create_nth_var( xs[5], 3 );
mig_network mig = akers_synthesis<mig_network>( f, care );
if ( mig.size() > 4 )
{
mig.foreach_gate( [&]( auto n ) {
std::vector<kitty::dynamic_truth_table> fanin{3, kitty::dynamic_truth_table( 4 )};
mig.foreach_fanin( n, [&]( auto s, auto j ) {
if ( mig.node_to_index( mig.get_node( s ) ) == 0 )
{
fanin[j] = ~xs[1];
}
else
{
fanin[j] = xs[mig.node_to_index( mig.get_node( s ) ) + 1];
}
} );
xs.push_back( mig.compute( n, fanin.begin(), fanin.end() ) );
} );
mig.foreach_po( [&]( auto s ){
if ( mig.is_complemented( s ) )
{
CHECK( ~xs[xs.size() - 1] == f );
}
else
{
CHECK( xs[xs.size() - 1] == f );
}
});
}
}
}
Additional context
This implementation of the Akers majority synthesis algorithm has been modified from the original paper [1]. An exact re-implementation of the Akers algorithm can be found in mockturtle/algorithms/resyn_engines/mig_resyn.hpp
. However, it is advised to use mig_resyn_topdown
instead, as this is more efficient. [2]
This issue will not be worked on and is only for documentation purpose.
[1] Akers, S. B. (1962, October). Synthesis of combinational logic using three-input majority gates. In 3rd Annual Symposium on Switching Circuit Theory and Logical Design (SWCT 1962) (pp. 149-158). IEEE.
[2] S.-Y. Lee, H. Riener and G. D. Micheli, "Logic Resynthesis of Majority-Based Circuits by Top-Down Decomposition," 2021 24th International Symposium on Design and Diagnostics of Electronic Circuits & Systems (DDECS), 2021
While trying to fix some warnings on my side, I found that the author of sparsepp
recommends the use of his new header-only library parallel-hashmap
: https://github.com/greg7mdp/parallel-hashmap
I suppose the change should be straightforward.
I'm not sure how much of an impact it would make on mockturtle
performance, but the author says that parallel-hashmap
is significantly faster.
include/mockturtle/algorithms/reconv_cut2.hpp contains the following:
/* \brief limit on the size of the supernode */
int node_size_max;
/* \brief limit on the size of the supernode */
int node_fan_stop;
I think the comment on the second of these is meant to refer to a fan-in limit.
The implementation of aiger_reader
takes a network and optionally a NameMap as parameters. The second parameter is used to store the signal names from the AIGER file.
However, the optional parameter can be avoided by decorating the network with a names_view
.
A test case that fails:
TEST_CASE( "bug in assumptions", "[cnf_view]" )
{
cnf_view<xag_network> xag;
const auto a = xag.create_pi();
const auto b = xag.create_pi();
const auto f = xag.create_xor( a, b );
const auto g = xag.create_xor( f, f );
/* if delete the following 4 lines, this test case will pass */
bill::result::clause_type assump1( 1, xag.lit(f) );
const auto result1 = xag.solve( assump1 );
CHECK( result1 ); /* has result */
CHECK( *result1 ); /* result is SAT */
bill::result::clause_type assump2( 1, xag.lit(g) );
const auto result2 = xag.solve( assump2 );
CHECK( result2 ); /* has result */
CHECK( !*result2 ); /* result is UNSAT */ /* this check fails */
}
lines 258 and 281 should be has( n )
and has( ntk.get_node( f ) )
, respectively
Hello,
I'm trying to create a cell mapping for a network to process each cell. Please consider the following code snippet.
template<class Ntk>
void print_cell_io( Ntk const& ntk ) // ntk is a mapped network
{
auto cells = mockturtle::cell_window( ntk );
ntk.foreach_node( [&]( auto const n ) {
if ( ntk.is_constant( n ) || ntk.is_pi( n ) || !ntk.is_cell_root( n ) )
return;
auto fanin_counter = 0u;
ntk.foreach_cell_fanin( n, [&]( auto const f ) {
++fanin_counter;
} );
std::cout << "cell has " << fanin_counter << " fanins\n";
cells.compute_window_for( n );
std::cout << "cell_window i/o = " << cells.num_pis() << "/" << cells.num_pos() << "\n";
} );
}
As I've understood the documentation about mappings, a cell has a single root (i.e. one primary output?). So I assumed the cell_fanin
s to be the primary inputs of the cell. When executing the above code in CirKit with e.g. AIG networks, the cell_fanins
don't match the cell_window
I/Os. Additionally, cell_window
s can have multiple outputs.
May I ask you to clarify the difference between the cell mapping and the cell_window
applied to it? How do I process cells correctly? How do I access their I/Os, their contained nodes, etc.?
Thanks a lot for your help!
Dears,
I'm playing with the mockturtle library in these days and I found something for me unexpected.
It looks that lut_mapping may produce LUT with 0x0 as functionality.
For example for this bench
INPUT(n2)
INPUT(n4)
INPUT(n6)
INPUT(n7)
INPUT(n8)
INPUT(n10)
INPUT(n12)
INPUT(n13)
INPUT(n14)
INPUT(n18)
INPUT(n20)
INPUT(n22)
OUTPUT(po0)
OUTPUT(po1)
OUTPUT(po2)
OUTPUT(po3)
OUTPUT(po4)
OUTPUT(po5)
OUTPUT(po6)
OUTPUT(po7)
OUTPUT(po8)
OUTPUT(po9)
OUTPUT(po10)
OUTPUT(po11)
OUTPUT(po12)
OUTPUT(po13)
OUTPUT(po14)
OUTPUT(po15)
OUTPUT(po16)
OUTPUT(po17)
OUTPUT(po18)
OUTPUT(po19)
OUTPUT(po20)
OUTPUT(po21)
n0 = gnd
n1 = vdd
n3 = LUT 0x1 (n2)
n5 = LUT 0x2 (n4)
n9 = LUT 0x1000 (n2, n6, n7, n8)
n11 = LUT 0x2 (n6, n10)
n15 = LUT 0x00008000 (n6, n10, n12, n13, n14)
n16 = LUT 0x8000000000000000 (n6, n10, n12, n13, n14, n0)
n17 = LUT 0xa2222222 (n6, n10, n12, n13, n14)
n19 = LUT 0x1 (n18)
n21 = LUT 0x8 (n18, n20)
n23 = LUT 0x02 (n6, n10, n22)
n24 = LUT 0x0000000000008000 (n6, n10, n12, n13, n14, n22)
n25 = LUT 0x4000000000000000 (n22, n6, n10, n12, n13, n14)
n26 = LUT 0x8 (n0, n25)
n27 = LUT 0x0800 (n12, n13, n14, n22)
n28 = LUT 0x80000000 (n22, n12, n13, n14, n0)
n29 = LUT 0xf000000080000000 (n6, n10, n12, n13, n14, n22)
n30 = LUT 0x00000000 (n6, n10, n12, n13, n14)
n31 = LUT 0x08880888 (n6, n10, n12, n13, n14)
n32 = LUT 0x0 (n14)
n33 = LUT 0x10 (n2, n6, n7)
n34 = LUT 0xfffffffc (n8, n15, n17, n30, n33)
n35 = LUT 0xffffffff08880888 (n6, n10, n12, n13, n32, n34)
n36 = LUT 0x0000000000000000 (n6, n10, n12, n13, n14, n22)
n37 = LUT 0x0000000008880888 (n6, n10, n12, n13, n14, n22)
n38 = LUT 0x0000 (n12, n13, n14, n22)
n39 = LUT 0x7700 (n12, n13, n14, n22)
po0 = LUT 0x2 (n3)
po1 = LUT 0x2 (n5)
po2 = LUT 0x2 (n9)
po3 = LUT 0x2 (n11)
po4 = LUT 0x2 (n15)
po5 = LUT 0x2 (n16)
po6 = LUT 0x2 (n17)
po7 = LUT 0x2 (n19)
po8 = LUT 0x2 (n21)
po9 = LUT 0x2 (n23)
po10 = LUT 0x2 (n24)
po11 = LUT 0x2 (n26)
po12 = LUT 0x2 (n27)
po13 = LUT 0x2 (n28)
po14 = LUT 0x2 (n29)
po15 = LUT 0x2 (n30)
po16 = LUT 0x2 (n31)
po17 = LUT 0x2 (n35)
po18 = LUT 0x2 (n36)
po19 = LUT 0x2 (n37)
po20 = LUT 0x2 (n38)
po21 = LUT 0x2 (n39)
I've got something like:
INPUT(n2)
INPUT(n3)
INPUT(n4)
INPUT(n5)
INPUT(n6)
INPUT(n7)
INPUT(n8)
INPUT(n9)
INPUT(n10)
INPUT(n11)
INPUT(n12)
INPUT(n13)
OUTPUT(po0)
OUTPUT(po1)
OUTPUT(po2)
OUTPUT(po3)
OUTPUT(po4)
OUTPUT(po5)
OUTPUT(po6)
OUTPUT(po7)
OUTPUT(po8)
OUTPUT(po9)
OUTPUT(po10)
OUTPUT(po11)
OUTPUT(po12)
OUTPUT(po13)
OUTPUT(po14)
OUTPUT(po15)
OUTPUT(po16)
OUTPUT(po17)
OUTPUT(po18)
OUTPUT(po19)
OUTPUT(po20)
OUTPUT(po21)
n0 = gnd
n1 = vdd
n14 = LUT 0x1 (n2)
n15 = LUT 0x2 (n3)
n16 = LUT 0x1000 (n2, n4, n5, n6)
n17 = LUT 0x2 (n4, n7)
n18 = LUT 0x00008000 (n4, n7, n8, n9, n10)
n19 = LUT 0x00000000 (n4, n7, n8, n9, n10)
n20 = LUT 0xa2222222 (n4, n7, n8, n9, n10)
n21 = LUT 0x1 (n11)
n22 = LUT 0x8 (n11, n12)
n23 = LUT 0x02 (n4, n7, n13)
n24 = LUT 0x0000000000008000 (n4, n7, n8, n9, n10, n13)
n25 = LUT 0x0000000000000000 (n4, n7, n8, n9, n10, n13)
n26 = LUT 0x0800 (n8, n9, n10, n13)
n27 = LUT 0x0000 (n8, n9, n10, n13)
n28 = LUT 0xf000000080000000 (n4, n7, n8, n9, n10, n13)
n29 = LUT 0x08880888 (n4, n7, n8, n9, n10)
n30 = LUT 0x10 (n2, n4, n5)
n31 = LUT 0xfffffffc (n6, n18, n19, n20, n30)
n32 = LUT 0xffffffff08880888 (n4, n7, n8, n9, n10, n31)
n33 = LUT 0x0000000008880888 (n4, n7, n8, n9, n10, n13)
n34 = LUT 0x7700 (n8, n9, n10, n13)
po0 = LUT 0x2 (n14)
po1 = LUT 0x2 (n15)
po2 = LUT 0x2 (n16)
po3 = LUT 0x2 (n17)
po4 = LUT 0x2 (n18)
po5 = LUT 0x2 (n19)
po6 = LUT 0x2 (n20)
po7 = LUT 0x2 (n21)
po8 = LUT 0x2 (n22)
po9 = LUT 0x2 (n23)
po10 = LUT 0x2 (n24)
po11 = LUT 0x2 (n25)
po12 = LUT 0x2 (n26)
po13 = LUT 0x2 (n27)
po14 = LUT 0x2 (n28)
po15 = LUT 0x2 (n19)
po16 = LUT 0x2 (n29)
po17 = LUT 0x2 (n32)
po18 = LUT 0x2 (n25)
po19 = LUT 0x2 (n33)
po20 = LUT 0x2 (n27)
po21 = LUT 0x2 (n34)
As you may see, node n19 is equivalent to a constant false. Detecting and propagating this to primary output it looks not so complex. What I'm not able to manage is how to simplify node n31 receiving n19 as input. This redundancy seems to happen only in case the node is feeding a primary output.
Is there anything I can do to remove such redundancies?
The source code I use is pretty simple. Something like:
lut_mapping_stats st;
mapping_view<klut_network, true> mapped_aig{aig};
lut_mapping<decltype( mapped_aig ), true>( mapped_aig, {}, &st );
const auto klut = *collapse_mapped_network<klut_network>( mapped_aig );
mockturtle::write_bench(klut, std::cout);
Cheers,
Fabrizio
The network interface API contains foreach_pi
and foreach_po
. However it has is_pi
but seemingly no is_po
. Looking at the implementations of is_pi
, it seems like maybe this is deliberate as there isn't a way to implement it efficiently? Seems like one can roll their own as something like:
// untested
bool is_po(const aig_network &net, const node &n) {
bool match = false;
net.foreach_po([&](const signal &s) {
if (node_to_index(n) == s.index) {
match = true;
return false;
}
return true;
});
return match;
}
Do you think this is suitable for inclusion in mockturtle?
When compiling with -Wparentheses
GCC 9.2.0 has this to say:
In file included from /home/matthew/project/mockturtle/include/mockturtle/algorithms/node_resynthesis/xmg_npn.hpp:47:0,
from /home/matthew/project/mockturtle/include/mockturtle/mockturtle.hpp:71,
from /home/matthew/project/project/main.cc:8:
/home/matthew/project/mockturtle/include/mockturtle/algorithms/node_resynthesis/../../networks/xmg.hpp: In member function ‘mockturtle::xmg_network::signal mockturtle::xmg_network::create_maj(mockturtle::xmg_network::signal, mockturtle::xmg_network::signal, mockturtle::xmg_network::signal)’:
/home/matthew/project/mockturtle/include/mockturtle/algorithms/node_resynthesis/../../networks/xmg.hpp:300:23: warning: suggest parentheses around comparison in operand of ‘==’ [-Wparentheses]
else if ( a.index == b.index == c.index )
~~~~~~~~^~~~~~~~~~
This looks to me like a legitimate problem. Is this supposed to read a.index == b.index && b.index == c.index
?
It complains:
error: non-constant-expression cannot be narrowed from type 'unsigned long long' to 'std::size_t' (aka 'unsigned long') in initializer list [-Wc++11-narrowing]
Describe the bug
Refactoring can lead to segmentation fault which is detected by the assert at line 267 in mffc_view
.
This is due to the use of reference counters to keep track of the fanout of the gates. Reference counters can be invalidated after a node substitution. Moreover there are some wrong updates to the reference counters. The right way of keeping the fanout information correct is to use directly the fanout size field of gates.
To Reproduce
I haven't found a way of reproducing it using "standard'' mockturtle yet.
Environment
Additional information
I know how to solve the bug. I will find time to fix it properly in the next weeks.
The proposed fix is to replace the use of reference counters with the fanout_size
.
The order in which assign statements are printed is non-deterministic.
When linking against commit 23401c1 of mockturtle, we get the following error:
...
../libfoo/libfoo.a(bar.cc.o): In function `mockturtle::xmg_dont_cares_optimization(mockturtle::xmg_network const&)':
bar.cc:(.text+0x5cb2): multiple definition of `mockturtle::xmg_dont_cares_optimization(mockturtle::xmg_network const&)'
CMakeFiles/foo.dir/main.cc.o:main.cc:(.text+0x5cb2): first defined here
../libfoo/libfoo.a(baz.cc.o): In function `mockturtle::xmg_dont_cares_optimization(mockturtle::xmg_network const&)':
baz.cc:(.text+0x5cb2): multiple definition of `mockturtle::xmg_dont_cares_optimization(mockturtle::xmg_network const&)'
CMakeFiles/foo.dir/main.cc.o:main.cc:(.text+0x5cb2): first defined here
../libfoo/libfoo.a(qux.cc.o): In function `mockturtle::xmg_dont_cares_optimization(mockturtle::xmg_network const&)':
qux.cc:(.text+0x5cb2): multiple definition of `mockturtle::xmg_dont_cares_optimization(mockturtle::xmg_network const&)'
CMakeFiles/foo.dir/main.cc.o:main.cc:(.text+0x5cb2): first defined here
collect2: error: ld returned 1 exit status
The root cause seems to be that xmg_dont_cares_optimization
is a free-standing non-template non-static non-inline function in a header, so it ends up exported in multiple translation units. Is this intended to be inline
?
In several of our key benchmarks (BOOM, Rocket...), we have a high percentage of cells using buses.
I mean, we do xor or and for a bus not a single bit wire. Checking BOOM, over 10% of the gates
are for buses, since they are multibit, if I flatten the number of gates more than doubles. We could "flatten" the wire to use mockturle bit representation, but it is an unnecessary overhead. Also, different bits can have slightly different (but equally good) results break symmetry.
Do you have anything on the plan to handle buses? (notice, this is not the same as nary functions that you have)
Trying to run the satlut
experiments fails for benchmarks log2
, multiplier
, sqrt
and voter
. They all fail while computing windows, more specifically at:
Assertion failed: (false), function compute_window_for, file mockturtle/include/mockturtle/algorithms/cell_window.hpp, line 150.
Which seems to be checking if the size of the pivot
mffc cone is grater the a maximum defined size for windows. Maybe the intended behaviour should be to simply ignore this window this as a pivot.
I implemented a draft (but not complete -- consideration of inverter cost is missing, and maybe some more details, plus documentation and tests etc. are also missing) during research but didn't need it in the end, so just to keep a back-up here in case someone decides that it's useful and makes a PR in the future.
As a public member function of depth_view
:
void ALAP()
{
_levels.reset( 0 );
this->incr_trav_id();
this->foreach_po( [&]( auto const& f ) {
const auto n = this->get_node( f );
if ( !this->is_constant( n ) && this->visited( n ) != this->trav_id() && !this->is_pi( n ) )
{
_levels[n] = _depth;
compute_levels_ALAP( n );
}
} );
}
As a private member function of depth_view
:
void compute_levels_ALAP( node const& n )
{
this->set_visited( n, this->trav_id() );
this->foreach_fanin( n, [&]( auto const& fi ) {
auto const ni = this->get_node( fi );
if ( !this->is_constant( ni ) && !this->is_pi( ni ) )
{
assert( _levels[n] >= _cost_fn( *this, ni ) );
auto fi_level = _levels[n] - _cost_fn( *this, ni );
if ( this->visited( ni ) != this->trav_id() || _levels[ni] > fi_level )
{
_levels[ni] = fi_level;
compute_levels_ALAP( ni );
}
}
} );
}
Hi,
I was experimenting with the refactoring
operation and noticed that if I apply it twice with the direct_resynthesis
resynthesis engine to the "adder" network from the EPFL Arithmetic benchmark (https://github.com/lsils/benchmarks/tree/master/arithmetic), then the resultant network is no longer equivalent to the original network. However, this is not the case if I apply the refactoring
operation only once or change the resynthesis engine to exact_aig_resynthesis
. Do you maybe know why this is the case?
The code below illustrates how this reproduce this issue.
#include <iostream>
#include <mockturtle/mockturtle.hpp>
using namespace std;
using namespace mockturtle;
int main() {
string epfl_arithmetic_benchmark_dir = "/path/to/epfl/arithmetic/benchmark/";
string ntk_name = "adder.aig";
// load network
aig_network ntk;
auto const loading_res = lorina::read_aiger(epfl_arithmetic_benchmark_dir + ntk_name, aiger_reader(ntk));
assert(loading_res == lorina::return_code::success);
cout << "Network " << ntk_name << " has been loaded successfully" << "\n";
// make a copy of the ntk for equivalence checking
aig_network original_ntk = ntk;
// refactoring parameters
refactoring_params refactor_ps;
refactor_ps.max_pis = 3u;
direct_resynthesis<aig_network> refactor_resyn;
// Apply refactoring twice
refactoring(ntk, refactor_resyn, refactor_ps);
ntk = cleanup_dangling(ntk);
refactoring(ntk, refactor_resyn, refactor_ps);
ntk = cleanup_dangling(ntk);
// equivalence checking
const auto miter_ntk = *miter<aig_network>(original_ntk, ntk);
const auto equivalence_res = equivalence_checking(miter_ntk);
/* result is an optional, which is nullopt if no solution was found */
if (equivalence_res && *equivalence_res) {
cout << "networks are equivalent after applying sequence\n";
}
else{
cout << "networks are NOT equivalent after applying sequence\n";
}
}
When I use mockturtle as a library in my project, I meet a problem about "multiple definition", can you help me?
../aqfp/libscflow.a(MajOpt.cpp.o): In function `mockturtle::generate_aqfp_dags(mockturtle::dag_generator_params const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int)':
~/SCFlow/third-party/mockturtle/include/mockturtle/algorithms/aqfp_resynthesis/detail/db_utils.hpp:51: multiple definition of `mockturtle::generate_aqfp_dags(mockturtle::dag_generator_params const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int)'
../aqfp/libscflow.a(Synthesis.cpp.o):~/SCFlow/third-party/mockturtle/include/mockturtle/algorithms/aqfp_resynthesis/detail/db_utils.hpp:51: first defined here
../aqfp/libscflow.a(MajOpt.cpp.o): In function `mockturtle::compute_aqfp_dag_costs(std::unordered_map<unsigned int, double, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, double> > > const&, std::unordered_map<unsigned int, double, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, double> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int)':
~/SCFlow/third-party/mockturtle/include/mockturtle/algorithms/aqfp_resynthesis/detail/db_utils.hpp:95: multiple definition of `mockturtle::compute_aqfp_dag_costs(std::unordered_map<unsigned int, double, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, double> > > const&, std::unordered_map<unsigned int, double, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, double> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int)'
../aqfp/libscflow.a(Synthesis.cpp.o):~/SCFlow/third-party/mockturtle/include/mockturtle/algorithms/aqfp_resynthesis/detail/db_utils.hpp:95: first defined here
../aqfp/libscflow.a(MajOpt.cpp.o): In function `mockturtle::generate_aqfp_db(std::unordered_map<unsigned int, double, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, double> > > const&, std::unordered_map<unsigned int, double, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, double> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int)':
~/SCFlow/third-party/mockturtle/include/mockturtle/algorithms/aqfp_resynthesis/detail/db_utils.hpp:155: multiple definition of `mockturtle::generate_aqfp_db(std::unordered_map<unsigned int, double, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, double> > > const&, std::unordered_map<unsigned int, double, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, double> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int)'
../aqfp/libscflow.a(Synthesis.cpp.o):~/SCFlow/third-party/mockturtle/include/mockturtle/algorithms/aqfp_resynthesis/detail/db_utils.hpp:155: first defined here
../aqfp/libscflow.a(MajOpt.cpp.o): In function `mockturtle::generate_aqfp_db(mockturtle::dag_generator_params const&, std::unordered_map<unsigned int, double, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, double> > > const&, std::unordered_map<unsigned int, double, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, double> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int)':
~/SCFlow/third-party/mockturtle/include/mockturtle/algorithms/aqfp_resynthesis/detail/db_utils.hpp:264: multiple definition of `mockturtle::generate_aqfp_db(mockturtle::dag_generator_params const&, std::unordered_map<unsigned int, double, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, double> > > const&, std::unordered_map<unsigned int, double, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, double> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int)'
../aqfp/libscflow.a(Synthesis.cpp.o):~/SCFlow/third-party/mockturtle/include/mockturtle/algorithms/aqfp_resynthesis/detail/db_utils.hpp:264: first defined here
../aqfp/libscflow.a(MajOpt.cpp.o): In function `mockturtle::self_dualize_aig(mockturtle::aig_network const&)':
~/SCFlow/third-party/mockturtle/include/mockturtle/generators/self_dualize.hpp:57: multiple definition of `mockturtle::self_dualize_aig(mockturtle::aig_network const&)'
../aqfp/libscflow.a(Synthesis.cpp.o):~/SCFlow/third-party/mockturtle/include/mockturtle/generators/self_dualize.hpp:57: first defined here
collect2: error: ld returned 1 exit status
I've seen the documentation and I did add the include directory of mockturtule to my include directory but just simply including mock turtule by #include <mockturtle/mockturtle.hpp>
doesn't work because of the source code dependency on other library like "lorina".
It would be good if once we have a mig_network or lut_network or... we can compare if two nets
are equivalent using the abcsat or other flows.
What is the easiest way to check equivalence in mockturtle?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.