Skip to content

Commit 8b95d21

Browse files
committed
Implementation of xor operator
1 parent e4816ac commit 8b95d21

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed

include/graphblas/base/internalops.hpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1943,6 +1943,109 @@ namespace grb {
19431943

19441944
};
19451945

1946+
/**
1947+
* The logical or operator, \f$ x \lxor y \f$.
1948+
*
1949+
* Assumes that the xor operator is defined on the given input types.
1950+
*/
1951+
template<
1952+
typename IN1, typename IN2, typename OUT,
1953+
enum Backend implementation = config::default_backend
1954+
>
1955+
class logical_xor {
1956+
1957+
public:
1958+
1959+
/** Alias to the left-hand input data type. */
1960+
typedef IN1 left_type;
1961+
1962+
/** Alias to the right-hand input data type. */
1963+
typedef IN2 right_type;
1964+
1965+
/** Alias to the output data type. */
1966+
typedef OUT result_type;
1967+
1968+
/** Whether this operator has an in-place foldl. */
1969+
static constexpr bool has_foldl = true;
1970+
1971+
/** Whether this operator has an in-place foldr. */
1972+
static constexpr bool has_foldr = true;
1973+
1974+
/**
1975+
* Whether this operator is \em mathematically associative; that is,
1976+
* associative when assuming equivalent data types for \a IN1, \a IN2,
1977+
* and \a OUT, as well as assuming exact arithmetic, no overflows, etc.
1978+
*/
1979+
static constexpr bool is_associative = true;
1980+
1981+
/**
1982+
* Whether this operator is \em mathematically commutative; that is,
1983+
* commutative when assuming equivalent data types for \a IN1, \a IN2,
1984+
* and \a OUT, as well as assuming exact arithmetic, no overflows, etc.
1985+
*/
1986+
static constexpr bool is_commutative = true;
1987+
1988+
/**
1989+
* Out-of-place application of this operator.
1990+
*
1991+
* @param[in] a The left-hand side input. Must be pre-allocated and
1992+
* initialised.
1993+
* @param[in] b The right-hand side input. Must be pre-allocated and
1994+
* initialised.
1995+
* @param[out] c The output. Must be pre-allocated.
1996+
*
1997+
* At the end of the operation, \f$ c = \min\{a,b\} \f$.
1998+
*/
1999+
static void apply(
2000+
const left_type * __restrict__ const a,
2001+
const right_type * __restrict__ const b,
2002+
result_type * __restrict__ const c
2003+
) {
2004+
if( *a xor *b ) {
2005+
*c = static_cast< OUT >( true );
2006+
} else {
2007+
*c = static_cast< OUT >( false );
2008+
}
2009+
}
2010+
2011+
/**
2012+
* In-place left-to-right folding.
2013+
*
2014+
* @param[in] a Pointer to the left-hand side input data.
2015+
* @param[in,out] c Pointer to the right-hand side input data. This also
2016+
* dubs as the output memory area.
2017+
*/
2018+
static void foldr(
2019+
const left_type * __restrict__ const a,
2020+
result_type * __restrict__ const c
2021+
) {
2022+
if( *a xor *c ) {
2023+
*c = static_cast< result_type >( true );
2024+
} else {
2025+
*c = static_cast< result_type >( false );
2026+
}
2027+
}
2028+
2029+
/**
2030+
* In-place right-to-left folding.
2031+
*
2032+
* @param[in,out] c Pointer to the left-hand side input data. This also
2033+
* dubs as the output memory area.
2034+
* @param[in] b Pointer to the right-hand side input data.
2035+
*/
2036+
static void foldl(
2037+
result_type * __restrict__ const c,
2038+
const right_type * __restrict__ const b
2039+
) {
2040+
if( *b xor *c ) {
2041+
*c = static_cast< result_type >( true );
2042+
} else {
2043+
*c = static_cast< result_type >( false );
2044+
}
2045+
}
2046+
2047+
};
2048+
19462049
/**
19472050
* The logical-and operator, \f$ x \land y \f$.
19482051
*

include/graphblas/ops.hpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,34 @@ namespace grb {
490490
logical_or() {}
491491
};
492492

493+
/**
494+
* The logical xor.
495+
*
496+
* It returns <tt>true</tt> whenever one and one only of its inputs
497+
* evaluate <tt>true</tt>, and returns <tt>false</tt> otherwise.
498+
*
499+
* If the output domain is not Boolean, then the returned value is
500+
* <tt>true</tt> or <tt>false</tt> cast to the output domain.
501+
*
502+
* \warning Thus both input domains and the output domain must be
503+
* \em castable to <tt>bool</tt>.
504+
*/
505+
template<
506+
typename D1, typename D2 = D1, typename D3 = D2,
507+
enum Backend implementation = config::default_backend
508+
>
509+
class logical_xor : public internal::Operator<
510+
internal::logical_xor< D1, D2, D3, implementation >
511+
> {
512+
513+
public:
514+
515+
template< typename A, typename B, typename C, enum Backend D >
516+
using GenericOperator = logical_xor< A, B, C, D >;
517+
518+
logical_xor() {}
519+
};
520+
493521
/**
494522
* The logical and.
495523
*
@@ -1082,6 +1110,11 @@ namespace grb {
10821110
static const constexpr bool value = true;
10831111
};
10841112

1113+
template< typename D1, typename D2, typename D3, enum Backend implementation >
1114+
struct is_operator< operators::logical_xor< D1, D2, D3, implementation > > {
1115+
static const constexpr bool value = true;
1116+
};
1117+
10851118
template< typename D1, typename D2, typename D3, enum Backend implementation >
10861119
struct is_operator< operators::logical_and< D1, D2, D3, implementation > > {
10871120
static const constexpr bool value = true;
@@ -1191,6 +1224,11 @@ namespace grb {
11911224
static const constexpr bool value = true;
11921225
};
11931226

1227+
template< typename D1, typename D2, typename D3 >
1228+
struct is_idempotent< operators::logical_xor< D1, D2, D3 >, void > {
1229+
static const constexpr bool value = true;
1230+
};
1231+
11941232
template< typename D1, typename D2, typename D3 >
11951233
struct is_idempotent< operators::logical_and< D1, D2, D3 >, void > {
11961234
static const constexpr bool value = true;

0 commit comments

Comments
 (0)