@staticmethod<EOL><INDENT>def pseudo_join(s, b, smart_join=True):<DEDENT>
assert s.bits == b.bits<EOL>w = s.bits<EOL>if s._reversed != b._reversed:<EOL><INDENT>logger.warning('<STR_LIT>', s, b)<EOL><DEDENT>uninit_flag = s.uninitialized | b.uninitialized<EOL>if s.is_empty:<EOL><INDENT>return b<EOL><DEDENT>if b.is_empty:<EOL><INDENT>return s<EOL><DEDENT>if s.is_integer and b.is_integer:<EOL><INDENT>u = max(s.upper_bound, b.upper_bound) if smart_join else b.upper_bound<EOL>l = min(s.lower_bound, b.lower_bound) if smart_join else s.lower_bound<EOL>stride = abs(u - l)<EOL>return StridedInterval(bits=w, stride=stride, lower_bound=l, upper_bound=u, uninitialized=uninit_flag)<EOL><DEDENT>if s._is_surrounded(b):<EOL><INDENT>new_stride = StridedInterval.gcd(s.stride, b.stride) if s.is_interval else b.stride<EOL>new_stride = StridedInterval.gcd(new_stride, s._modular_sub(s.lower_bound, b.lower_bound, w))<EOL>return StridedInterval(bits=w, stride=new_stride, lower_bound=b.lower_bound,<EOL>upper_bound=b.upper_bound, uninitialized=uninit_flag)<EOL><DEDENT>elif b._is_surrounded(s):<EOL><INDENT>new_stride = StridedInterval.gcd(s.stride, b.stride) if b.is_interval else s.stride<EOL>new_stride = StridedInterval.gcd(new_stride, s._modular_sub(b.lower_bound, s.lower_bound, w))<EOL>return StridedInterval(bits=w, stride=new_stride, lower_bound=s.lower_bound,<EOL>upper_bound=s.upper_bound, uninitialized=uninit_flag)<EOL><DEDENT>elif (s._surrounds_member(b.lower_bound) and s._surrounds_member(b.upper_bound) and<EOL>b._surrounds_member(s.lower_bound) and b._surrounds_member(s.upper_bound)):<EOL><INDENT>return StridedInterval.top(w, uninitialized=uninit_flag)<EOL><DEDENT>elif s._surrounds_member(b.lower_bound):<EOL><INDENT>new_stride = StridedInterval.gcd(s.stride, b.stride)<EOL>new_stride = StridedInterval.gcd(new_stride, s._modular_sub(b.lower_bound, s.lower_bound, w))<EOL>return StridedInterval(bits=w, stride=new_stride, lower_bound=s.lower_bound,<EOL>upper_bound=b.upper_bound, uninitialized=uninit_flag)<EOL><DEDENT>elif b._surrounds_member(s.lower_bound):<EOL><INDENT>new_stride = StridedInterval.gcd(s.stride, b.stride)<EOL>new_stride = StridedInterval.gcd(new_stride, s._modular_sub(s.lower_bound, b.lower_bound, w))<EOL>return StridedInterval(bits=w, stride=new_stride, lower_bound=b.lower_bound,<EOL>upper_bound=s.upper_bound, uninitialized=uninit_flag)<EOL><DEDENT>else:<EOL><INDENT>if not smart_join:<EOL><INDENT>if s.is_integer:<EOL><INDENT>new_stride = StridedInterval.gcd(b.stride, s._modular_sub(b.lower_bound, s.lower_bound, w))<EOL><DEDENT>elif b.is_integer:<EOL><INDENT>new_stride = StridedInterval.gcd(s.stride, s._modular_sub(b.lower_bound, s.lower_bound, w))<EOL><DEDENT>else:<EOL><INDENT>new_stride = StridedInterval.gcd(s.stride, b.stride)<EOL>new_stride = StridedInterval.gcd(new_stride, StridedInterval._wrapped_cardinality(s.lower_bound, b.lower_bound, w) - <NUM_LIT:1>)<EOL><DEDENT>return StridedInterval(bits=w, stride=new_stride, lower_bound=s.lower_bound, upper_bound=b.upper_bound, uninitialized=uninit_flag)<EOL><DEDENT>if s.is_integer:<EOL><INDENT>new_stride = b.stride<EOL><DEDENT>elif b.is_integer:<EOL><INDENT>new_stride = s.stride<EOL><DEDENT>else:<EOL><INDENT>new_stride = StridedInterval.gcd(s.stride, b.stride)<EOL><DEDENT>new_stride1 = StridedInterval.gcd(new_stride, StridedInterval._wrapped_cardinality(b.lower_bound, s.lower_bound, w) - <NUM_LIT:1>)<EOL>new_stride2 = StridedInterval.gcd(new_stride, StridedInterval._wrapped_cardinality(s.lower_bound, b.lower_bound, w) - <NUM_LIT:1>)<EOL>si1 = StridedInterval(bits=w, stride=new_stride1, lower_bound=b.lower_bound,<EOL>upper_bound=s.upper_bound, uninitialized=uninit_flag)<EOL>si2 = StridedInterval(bits=w, stride=new_stride2, lower_bound=s.lower_bound,<EOL>upper_bound=b.upper_bound, uninitialized=uninit_flag)<EOL>if si1.n_values <= si2.n_values:<EOL><INDENT>return si1<EOL><DEDENT>else:<EOL><INDENT>return si2<EOL><DEDENT><DEDENT>
It two intervals in a way that the resulting SI is the one that has the least
SI cardinality (i.e., which represents the least number of elements) possible if the smart_join flag is enabled,
otherwise it just joins the SI according the order they are passed to the function.

The pseudo-join operation is not associative in wrapping intervals (please refer to section 3.1 paper
'Signedness-Agnostic Program Analysis: Precise Integer Bounds for Low-Level Code'), Therefore the join of three
WI may  give us different results according on the order we join them. All of the results will be sound, though.

Please use the function least_upper_bound as a stub.

:param s:           The first SI
:param b:           The other SI.
:param smart_join:  Enable the smart join behavior. If this flag is set, this function joins the two SI in a way
                    that the resulting Si has least number of elements (more precise). If it is unset, this
                    function will join the two SI according on the order they are passed to the function.
:return:            A new StridedInterval