Skip to content

Commit 481d8b6

Browse files
committed
is_associativity issue to review
1 parent 91cc61c commit 481d8b6

File tree

7 files changed

+300
-112
lines changed

7 files changed

+300
-112
lines changed

include/graphblas/base/internalops.hpp

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ namespace grb {
5656
* - \b OperatorType: The internal::operator type to negate.
5757
*/
5858
template<
59-
class Op,
59+
typename Op,
6060
enum Backend implementation = config::default_backend
6161
>
6262
class logical_not {
@@ -83,9 +83,7 @@ namespace grb {
8383
* associative when assuming equivalent data types for \a IN1, \a IN2,
8484
* and \a OUT, as well as assuming exact arithmetic, no overflows, etc.
8585
*/
86-
static constexpr bool is_associative = is_lnegated< Op >::value
87-
? Op::OperatorType::is_associative
88-
: false;
86+
static constexpr bool is_associative = Op::OperatorType::is_associative;
8987

9088
/**
9189
* Whether this operator is \em mathematically commutative; that is,
@@ -3054,16 +3052,6 @@ namespace grb {
30543052

30553053
public:
30563054

3057-
/** @return Whether this operator is mathematically associative. */
3058-
static constexpr bool is_associative() {
3059-
return OP::is_associative;
3060-
}
3061-
3062-
/** @return Whether this operator is mathematically commutative. */
3063-
static constexpr bool is_commutative() {
3064-
return OP::is_commutative;
3065-
}
3066-
30673055
/**
30683056
* Straightforward application of this operator. Computes \f$ x \odot y \f$
30693057
* and stores the result in \a z.

include/graphblas/ops.hpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ namespace grb {
4848
class Op,
4949
enum Backend implementation = config::default_backend
5050
>
51-
class logical_not : public internal::Operator< internal::logical_not< Op > > {
51+
class logical_not : public internal::Operator<
52+
internal::logical_not< Op >
53+
> {
54+
5255
public:
5356

5457
template< class A >
@@ -1264,26 +1267,25 @@ namespace grb {
12641267
OP,
12651268
typename std::enable_if< is_operator< OP >::value, void >::type
12661269
> {
1267-
static constexpr const bool value = OP::is_associative();
1270+
static constexpr const bool value = is_logically_negated<OP>::value ? false : OP::OperatorType::is_associative;
12681271
};
12691272

12701273
template< typename OP >
12711274
struct is_commutative<
12721275
OP,
12731276
typename std::enable_if< is_operator< OP >::value, void >::type
12741277
> {
1275-
static constexpr const bool value = OP::is_commutative();
1278+
static constexpr const bool value = OP::OperatorType::is_commutative();
12761279
};
12771280

12781281
template< typename OP >
1279-
struct is_lnegated<
1282+
struct is_logically_negated<
12801283
operators::logical_not< OP >,
12811284
typename std::enable_if< is_operator< OP >::value, void >::type
12821285
> {
1283-
static constexpr const bool value = true;
1286+
static constexpr const bool value = not is_logically_negated< OP >::value;
12841287
};
12851288

1286-
12871289
// internal type traits follow
12881290

12891291
namespace internal {

include/graphblas/type_traits.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ namespace grb {
237237
* \ingroup typeTraits
238238
*/
239239
template< typename T, typename = void >
240-
struct is_lnegated {
240+
struct is_logically_negated {
241241

242242
static_assert( is_operator< T >::value,
243243
"Template argument should be an ALP binary operator." );

tests/unit/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ add_grb_executables( mxv mxv.cpp
247247
BACKENDS reference_omp bsp1d hybrid hyperdags nonblocking
248248
)
249249

250-
add_grb_executables( operator_logical_not operator_logical_not.cpp
250+
add_grb_executables( logical_operators logical_operators.cpp
251251
BACKENDS reference reference_omp hyperdags nonblocking bsp1d hybrid
252252
)
253253

tests/unit/logical_operators.cpp

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
2+
/*
3+
* Copyright 2021 Huawei Technologies Co., Ltd.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include <iostream>
19+
#include <sstream>
20+
#include <unordered_map>
21+
#include <vector>
22+
#include <string>
23+
24+
#include <graphblas.hpp>
25+
#include <graphblas/ops.hpp>
26+
27+
using namespace grb;
28+
using namespace grb::operators;
29+
30+
constexpr std::array< std::pair< bool, bool >, 4 > test_values = {
31+
std::make_pair( false, false ),
32+
std::make_pair( false, true ),
33+
std::make_pair( true, false ),
34+
std::make_pair( true, true )
35+
};
36+
37+
template<
38+
Descriptor descr = descriptors::no_operation,
39+
typename OP
40+
>
41+
void test_apply(
42+
RC &rc,
43+
std::array< bool, 4 > &values,
44+
const std::array< bool, 4 > &expected
45+
) {
46+
rc = apply< descr, OP >( values[0], false, false );
47+
rc = rc ? rc : apply< descr, OP >( values[1], false, true );
48+
rc = rc ? rc : apply< descr, OP >( values[2], true, false );
49+
rc = rc ? rc : apply< descr, OP >( values[3], true, true );
50+
if( ! std::equal( values.cbegin(), values.cend(), expected.cbegin() ) ) {
51+
rc = FAILED;
52+
}
53+
}
54+
55+
template<
56+
Descriptor descr = descriptors::no_operation,
57+
typename OP
58+
>
59+
void test_foldl(
60+
RC &rc,
61+
std::array< bool, 4 > &values,
62+
const std::array< bool, 4 > &expected
63+
) {
64+
values[0] = false;
65+
rc = foldl< descr, OP >( values[0], false );
66+
values[1] = false;
67+
rc = rc ? rc : foldl< descr, OP >( values[1], true );
68+
values[2] = true;
69+
rc = rc ? rc : foldl< descr, OP >( values[2], false );
70+
values[3] = true;
71+
rc = rc ? rc : foldl< descr, OP >( values[3], true );
72+
if( ! std::equal( values.cbegin(), values.cend(), expected.cbegin() ) ) {
73+
rc = FAILED;
74+
}
75+
}
76+
77+
template<
78+
Descriptor descr = descriptors::no_operation,
79+
typename OP
80+
>
81+
void test_foldr(
82+
RC &rc,
83+
std::array< bool, 4 > &values,
84+
const std::array< bool, 4 > &expected
85+
) {
86+
values[0] = false;
87+
rc = foldr< descr, OP >( false, values[0] );
88+
values[1] = false;
89+
rc = rc ? rc : foldr< descr, OP >( true, values[1] );
90+
values[2] = true;
91+
rc = rc ? rc : foldr< descr, OP >( false, values[2] );
92+
values[3] = true;
93+
rc = rc ? rc : foldr< descr, OP >( true, values[3] );
94+
if( ! std::equal( values.cbegin(), values.cend(), expected.cbegin() ) ) {
95+
rc = FAILED;
96+
}
97+
}
98+
99+
template<
100+
Descriptor descr = descriptors::no_operation,
101+
typename OP
102+
>
103+
void test_operator(
104+
RC &rc,
105+
const std::array< bool, 4 > &expected,
106+
const bool expected_associative,
107+
const typename std::enable_if<
108+
grb::is_operator< OP >::value,
109+
void
110+
>::type* = nullptr
111+
) {
112+
113+
if( grb::is_associative< OP >::value != expected_associative ) {
114+
std::cerr << "Operator associtativity property is "
115+
<< grb::is_associative< OP >::value << ", should be "
116+
<< expected_associative << "\n";
117+
rc = FAILED;
118+
return;
119+
}
120+
121+
std::array< bool, 4 > values;
122+
123+
test_apply< descr, OP >( rc, values, expected );
124+
if( rc != SUCCESS ) {
125+
std::cerr << "Test_apply FAILED\n";
126+
std::cerr << "values ?= expected\n";
127+
for( size_t i = 0; i < 4; i++ ) {
128+
std::cerr << "OP( " << test_values[i].first << ";"
129+
<< test_values[i].second << " ): "<< values[i] << " ?= "
130+
<< expected[i] << "\n";
131+
}
132+
return;
133+
}
134+
test_foldl< descr, OP >( rc, values, expected );
135+
if( rc != SUCCESS ) {
136+
std::cerr << "Test_foldl FAILED\n";
137+
std::cerr << "values ?= expected\n";
138+
for( size_t i = 0; i < 4; i++ ) {
139+
std::cerr << "OP( " << test_values[i].first << ";"
140+
<< test_values[i].second << " ): "<< values[i] << " ?= "
141+
<< expected[i] << "\n";
142+
}
143+
return;
144+
}
145+
test_foldr< descr, OP >( rc, values, expected );
146+
if( rc != SUCCESS ) {
147+
std::cerr << "Test_foldr FAILED\n";
148+
std::cerr << "values ?= expected\n";
149+
for( size_t i = 0; i < 4; i++ ) {
150+
std::cerr << "OP( " << test_values[i].first << ";"
151+
<< test_values[i].second << " ): "<< values[i] << " ?= "
152+
<< expected[i] << "\n";
153+
}
154+
return;
155+
}
156+
}
157+
158+
void grb_program( const size_t&, grb::RC &rc ) {
159+
rc = SUCCESS;
160+
161+
// Logical operators
162+
{ // logical_and< bool >
163+
std::cout << "Testing operator: logical_and<bool>" << std::endl;
164+
const std::array<bool, 4> expected = { false, false, false, true };
165+
bool expected_associative = true;
166+
test_operator<
167+
descriptors::no_operation,
168+
logical_and< bool >
169+
>( rc, expected, expected_associative );
170+
}
171+
{ // logical_or< bool >
172+
std::cout << "Testing operator: logical_or<bool>" << std::endl;
173+
const std::array<bool, 4> expected = { false, true, true, true };
174+
bool expected_associative = true;
175+
test_operator<
176+
descriptors::no_operation,
177+
logical_or< bool >
178+
>( rc, expected, expected_associative );
179+
}
180+
{ // logical_xor< bool >
181+
std::cout << "Testing operator: logical_xor<bool>" << std::endl;
182+
const std::array<bool, 4> expected = { false, true, true, false };
183+
bool expected_associative = true;
184+
test_operator<
185+
descriptors::no_operation,
186+
logical_xor< bool >
187+
>( rc, expected, expected_associative );
188+
}
189+
190+
// Negated operators
191+
{ // logical_not< logical_and< bool > >
192+
std::cout << "Testing operator: logical_not< logical_and< bool > >" << std::endl;
193+
const std::array<bool, 4> expected = { true, true, true, false };
194+
bool expected_associative = false;
195+
test_operator<
196+
descriptors::no_operation,
197+
logical_not< logical_and< bool > >
198+
>( rc, expected, expected_associative );
199+
}
200+
{ // logical_not< logical_or< bool > >
201+
std::cout << "Testing operator: logical_not< logical_or< bool > >" << std::endl;
202+
const std::array<bool, 4> expected = { true, false, false, false };
203+
bool expected_associative = false;
204+
test_operator<
205+
descriptors::no_operation,
206+
logical_not< logical_or< bool > >
207+
>( rc, expected, expected_associative );
208+
}
209+
{ // logical_not< logical_xor< bool > >
210+
std::cout << "Testing operator: logical_not< logical_xor< bool > >" << std::endl;
211+
const std::array<bool, 4> expected = { true, false, false, true };
212+
bool expected_associative = false;
213+
test_operator<
214+
descriptors::no_operation,
215+
logical_not< logical_xor< bool > >
216+
>( rc, expected, expected_associative );
217+
}
218+
219+
// Double-negated operators
220+
{ // logical_not< logical_not < logical_and< bool > > >
221+
std::cout << "Testing operator: logical_not< logical_not < logical_and< bool > > >" << std::endl;
222+
const std::array<bool, 4> expected = { false, false, false, true };
223+
bool expected_associative = true;
224+
test_operator<
225+
descriptors::no_operation,
226+
logical_not< logical_not< logical_and< bool > > >
227+
>( rc, expected, expected_associative );
228+
}
229+
{ // logical_not< logical_not < logical_or< bool > > >
230+
std::cout << "Testing operator: logical_not< logical_not < logical_or< bool > > >" << std::endl;
231+
const std::array<bool, 4> expected = { false, true, true, true };
232+
bool expected_associative = true;
233+
test_operator<
234+
descriptors::no_operation,
235+
logical_not< logical_not< logical_or< bool > > >
236+
>( rc, expected, expected_associative );
237+
}
238+
{ // logical_not< logical_not < logical_xor< bool > > >
239+
std::cout << "Testing operator: logical_not< logical_not < logical_xor< bool > > >" << std::endl;
240+
const std::array<bool, 4> expected = { false, true, true, false };
241+
bool expected_associative = true;
242+
243+
std::cout << "Is lnegated: " << grb::is_logically_negated< logical_not< logical_not < logical_xor< bool > > > >::value << std::endl;
244+
std::cout << "Is lnegated: " << grb::is_logically_negated< logical_not< logical_xor< bool > > >::value << std::endl;
245+
std::cout << "Is lnegated: " << grb::is_logically_negated< logical_xor< bool > >::value << std::endl;
246+
247+
std::cout << "Is associative: " <<
248+
is_associative< logical_not< logical_not < logical_xor< bool > > > >::value << std::endl;
249+
std::cout << "Is associative: " <<
250+
is_associative< logical_not< logical_xor< bool > > >::value << std::endl;
251+
std::cout << "Is associative: " <<
252+
is_associative< logical_xor< bool > >::value << std::endl;
253+
254+
test_operator<
255+
descriptors::no_operation,
256+
logical_not< logical_not< logical_xor< bool > > >
257+
>( rc, expected, expected_associative );
258+
}
259+
}
260+
261+
int main( int argc, char ** argv ) {
262+
// error checking
263+
if( argc > 2 ) {
264+
std::cerr << "Usage: " << argv[ 0 ] << "\n";
265+
return 1;
266+
}
267+
268+
std::cout << "This is functional test " << argv[ 0 ] << "\n";
269+
270+
grb::Launcher< AUTOMATIC > launcher;
271+
RC out = SUCCESS;
272+
size_t unused = 0;
273+
if( launcher.exec( &grb_program, unused, out, true ) != SUCCESS ) {
274+
std::cerr << "Launching test FAILED\n";
275+
return 255;
276+
}
277+
if( out != SUCCESS ) {
278+
std::cerr << std::flush;
279+
std::cout << "Test FAILED (" << grb::toString( out ) << ")\n" << std::flush;
280+
} else {
281+
std::cout << "Test OK\n" << std::flush;
282+
}
283+
return 0;
284+
}

0 commit comments

Comments
 (0)