• xor operator

    From Dom Grigonis@21:1/5 to All on Mon Nov 13 10:49:37 2023
    Hi All,

    I think it could be useful to have `xor` builtin, which has API similar to the one of `any` and `all`.

    * Also, it could have optional second argument `n=1`, which indicates how many positives indicates `True` return.
    * For complete flexibility 3rd argument could indicate if `the number` is equal, greater, less, ... than `n`

    I find I sometimes need it when dealing with pub-sub filters and multiple predicates in general.

    What is the current situation that led me to writing this e-mail?
    Dealing with circular import in low level component space: library builtins depend on validation utilities, while validation utilities want to use xor from library builtins.

    Not a big issue, but seen there are fairly large threads in stack everyone inventing their own `xor`. And surprisingly there aren’t many good solutions. Almost none of them deal with short-circuiting well. And those that do contain loops that result in
    very poor performance.


    Regards,
    DG

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Barry@21:1/5 to All on Mon Nov 13 17:42:14 2023
    On 13 Nov 2023, at 15:16, Dom Grigonis via Python-list <python-list@python.org> wrote:

    I think it could be useful to have `xor` builtin, which has API similar to the one of `any` and `all`.

    I do not understand how xor(iterator) works.
    I thought xor takes exactly 2 args.

    I also do not understand how xor can be short circuited.
    For AND or OR only looking at the first arg works.
    But that does not work for xor right?

    Barry

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dom Grigonis@21:1/5 to All on Mon Nov 13 19:47:50 2023
    Well yes, I don’t think naming is very accurate. If iterable has 2 elements, then it is `xor`, otherwise it is something else - it checks the number of truth values in iterable.

    Short circuiting happens, when:
    xor([True, True, False, False], n=1)
    At index 1 it is clear that the answer is false.

    Regards,
    DG

    On 13 Nov 2023, at 19:42, Barry <barry@barrys-emacs.org> wrote:



    On 13 Nov 2023, at 15:16, Dom Grigonis via Python-list <python-list@python.org> wrote:

    I think it could be useful to have `xor` builtin, which has API similar to the one of `any` and `all`.

    I do not understand how xor(iterator) works.
    I thought xor takes exactly 2 args.

    I also do not understand how xor can be short circuited.
    For AND or OR only looking at the first arg works.
    But that does not work for xor right?

    Barry



    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Barry@21:1/5 to All on Mon Nov 13 21:03:12 2023
    On 13 Nov 2023, at 17:48, Dom Grigonis <dom.grigonis@gmail.com> wrote:

    Short circuiting happens, when:
    xor([True, True, False, False], n=1)
    At index 1 it is clear that the answer is false.

    Can you share an example with 4 values that is true?
    And explain why it is xor.

    Barry

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Axel Reichert@21:1/5 to Barry on Mon Nov 13 22:23:53 2023
    Barry <barry@barrys-emacs.org> writes:

    I do not understand how xor(iterator) works.
    I thought xor takes exactly 2 args.

    See

    https://mathworld.wolfram.com/XOR.html

    for some background (I was not aware of any generalizations for more
    than 2 arguments either).

    I also do not understand how xor can be short circuited.

    Me neither, but that could be related to the meaning of n (which I did
    not get) in the OP's question. Maybe he can clarify.

    Best regards

    Axel

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From MRAB@21:1/5 to Barry via Python-list on Mon Nov 13 21:25:42 2023
    On 2023-11-13 21:03, Barry via Python-list wrote:


    On 13 Nov 2023, at 17:48, Dom Grigonis <dom.grigonis@gmail.com> wrote:

    Short circuiting happens, when:
    xor([True, True, False, False], n=1)
    At index 1 it is clear that the answer is false.

    Can you share an example with 4 values that is true?
    And explain why it is xor.

    I think what the OP wants is something that stops after finding n true
    items.

    It's a more general form of what 'any' and 'all' do - 'any' stops when
    it finds 1 true item and 'all' stops when it finds 1 false item.

    In general, you might want to stop when you find n true items or n false
    items, or whatever.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael Speer@21:1/5 to python-list@python.org on Mon Nov 13 16:20:27 2023
    I don't think an exclusive-or/truthy-entries-count-checker needs to be a builtin by any stretch.

    def xor( iterable, n = 1 ):
    ... return sum( map( bool, iterable ) ) == n

    Or if you insist on short circuiting:

    def xor_ss( iterable, n = 1 ):
    ... for intermediate in itertools.accumulate( iterable, (lambda x, y: x + bool(y)), initial = 0 ):
    ... if intermediate > n:
    ... return False
    ... return intermediate == n



    On Mon, Nov 13, 2023 at 4:05 PM Barry via Python-list < python-list@python.org> wrote:



    On 13 Nov 2023, at 17:48, Dom Grigonis <dom.grigonis@gmail.com> wrote:

    Short circuiting happens, when:
    xor([True, True, False, False], n=1)
    At index 1 it is clear that the answer is false.

    Can you share an example with 4 values that is true?
    And explain why it is xor.

    Barry

    --
    https://mail.python.org/mailman/listinfo/python-list


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to python-list@python.org on Tue Nov 14 09:01:15 2023
    On Tue, 14 Nov 2023 at 08:57, Axel Reichert via Python-list <python-list@python.org> wrote:

    Barry <barry@barrys-emacs.org> writes:

    I do not understand how xor(iterator) works.
    I thought xor takes exactly 2 args.

    See

    https://mathworld.wolfram.com/XOR.html

    for some background (I was not aware of any generalizations for more
    than 2 arguments either).


    Generalization to more arguments usually means calculating parity -
    that is, it tells you whether you have an odd or even number of true
    results. Which means that short-circuiting is nonsensical.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dom Grigonis@21:1/5 to All on Mon Nov 13 23:35:32 2023
    xor([True, False, False, False], n=1)
    xor([False, False, False, True], n=1)
    Both of the above would evaluate to true.

    Well, it depends how you interpret it.
    In binary case it reads: “exclusively one positive bit or the other, but not both”
    In this case one could read: “exclusively one positive set of certain length, but not more than one such set at the same time"

    But I completely see how one could argue, that “exclusive” refers to slightly different thing. And multivariate `xor` is a function which defines fixed subsets out of which only one is true, but not the others, but this is theoretical, as in practice
    each set would need to always have all values switched on or off, which boils down to my proposed `xor` with `n=1`.

    But the point is if there is a need for such function or I am the only one who happens to use it.

    DG

    On 13 Nov 2023, at 23:03, Barry <barry@barrys-emacs.org> wrote:



    On 13 Nov 2023, at 17:48, Dom Grigonis <dom.grigonis@gmail.com> wrote:

    Short circuiting happens, when:
    xor([True, True, False, False], n=1)
    At index 1 it is clear that the answer is false.

    Can you share an example with 4 values that is true?
    And explain why it is xor.

    Barry


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dom Grigonis@21:1/5 to All on Tue Nov 14 00:11:30 2023
    Benchmarks:
    test1 = [False] * 100 + [True] * 2
    test2 = [True] * 100 + [False] * 2

    TIMER.repeat([
    lambda: xor(test1), # 0.0168
    lambda: xor(test2), # 0.0172
    lambda: xor_ss(test1), # 0.1392
    lambda: xor_ss(test2), # 0.0084
    lambda: xor_new(test1), # 0.0116
    lambda: xor_new(test2), # 0.0074
    lambda: all(test1), # 0.0016
    lambda: all(test2) # 0.0046
    ])
    Your first function is fairly slow.
    Second one deals with short-circuiting, but is super slow on full search.

    `xor_new` is the best what I could achieve using python builtins.

    But builtin `all` has the best performance.

    DG

    On 13 Nov 2023, at 23:20, Michael Speer <knomenet@gmail.com> wrote:

    I don't think an exclusive-or/truthy-entries-count-checker needs to be a builtin by any stretch.

    def xor( iterable, n = 1 ):
    ... return sum( map( bool, iterable ) ) == n

    Or if you insist on short circuiting:

    def xor_ss( iterable, n = 1 ):
    ... for intermediate in itertools.accumulate( iterable, (lambda x, y: x + bool(y)), initial = 0 ):
    ... if intermediate > n:
    ... return False
    ... return intermediate == n



    On Mon, Nov 13, 2023 at 4:05 PM Barry via Python-list <python-list@python.org <mailto:python-list@python.org>> wrote:


    On 13 Nov 2023, at 17:48, Dom Grigonis <dom.grigonis@gmail.com <mailto:dom.grigonis@gmail.com>> wrote:

    Short circuiting happens, when:
    xor([True, True, False, False], n=1)
    At index 1 it is clear that the answer is false.

    Can you share an example with 4 values that is true?
    And explain why it is xor.

    Barry

    --
    https://mail.python.org/mailman/listinfo/python-list <https://mail.python.org/mailman/listinfo/python-list>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Grant Edwards@21:1/5 to Dom Grigonis via Python-list on Mon Nov 13 14:51:05 2023
    On 2023-11-13, Dom Grigonis via Python-list <python-list@python.org> wrote:
    Hi All,

    I think it could be useful to have `xor` builtin, which has API similar to the one of `any` and `all`.

    * Also, it could have optional second argument `n=1`, which
    * indicates how many positives indicates `True` return. For
    * complete flexibility 3rd argument could indicate if `the number`
    * is equal, greater, less, ... than `n`

    I would expect "xor" to return true if there are an odd number of
    trues, and false if there are an even number of trues. It's not clear
    to me what you're asking for.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to python-list@python.org on Tue Nov 14 10:12:56 2023
    On Tue, 14 Nov 2023 at 10:00, Dom Grigonis via Python-list <python-list@python.org> wrote:

    I am not asking. Just inquiring if the function that I described could be useful for more people.

    Which is: a function with API that of `all` and `any` and returns `True` if specified number of elements is True.

    It is not a generalised `xor` in strict programatic space. I.e. NOT bitwise xor applied to many bits.
    This is more in line with cases that `any` and `all` builtins are used.


    A generalization of XOR is exactly what Grant and I said, though: a
    parity check. See for example:

    https://en.wikipedia.org/wiki/Exclusive_or https://reference.wolfram.com/language/ref/Xor.html

    It tells you whether you have an odd or even number of true values.

    Now, if you want something that short-circuits a counting function,
    that's definitely doable, but it's a sum-and-compare, not xor. Also,
    it's quite specialized so it's unlikely to end up in the stdlib.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dom Grigonis@21:1/5 to All on Tue Nov 14 00:58:58 2023
    I am not asking. Just inquiring if the function that I described could be useful for more people.

    Which is: a function with API that of `all` and `any` and returns `True` if specified number of elements is True.

    It is not a generalised `xor` in strict programatic space. I.e. NOT bitwise xor applied to many bits.
    This is more in line with cases that `any` and `all` builtins are used.

    On 14 Nov 2023, at 00:51, Grant Edwards via Python-list <python-list@python.org> wrote:

    On 2023-11-13, Dom Grigonis via Python-list <python-list@python.org> wrote:
    Hi All,

    I think it could be useful to have `xor` builtin, which has API similar to the one of `any` and `all`.

    * Also, it could have optional second argument `n=1`, which
    * indicates how many positives indicates `True` return. For
    * complete flexibility 3rd argument could indicate if `the number`
    * is equal, greater, less, ... than `n`

    I would expect "xor" to return true if there are an odd number of
    trues, and false if there are an even number of trues. It's not clear
    to me what you're asking for.



    --
    https://mail.python.org/mailman/listinfo/python-list

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dom Grigonis@21:1/5 to All on Tue Nov 14 01:24:19 2023
    I am not arguing that it is a generalised xor.

    I don’t want anything, I am just gauging if it is specialised or if there is a need for it. So just thought could suggest it as I have encountered such need several times already.

    It is fairly clear by now that it is not a common one given it took some time to even convey what I mean. Bad naming didn’t help ofc, but if it was something that is needed I think it would have clicked much faster.

    Thanks,
    DG

    On 14 Nov 2023, at 01:12, Chris Angelico via Python-list <python-list@python.org> wrote:

    On Tue, 14 Nov 2023 at 10:00, Dom Grigonis via Python-list <python-list@python.org> wrote:

    I am not asking. Just inquiring if the function that I described could be useful for more people.

    Which is: a function with API that of `all` and `any` and returns `True` if specified number of elements is True.

    It is not a generalised `xor` in strict programatic space. I.e. NOT bitwise xor applied to many bits.
    This is more in line with cases that `any` and `all` builtins are used.


    A generalization of XOR is exactly what Grant and I said, though: a
    parity check. See for example:

    https://en.wikipedia.org/wiki/Exclusive_or https://reference.wolfram.com/language/ref/Xor.html

    It tells you whether you have an odd or even number of true values.

    Now, if you want something that short-circuits a counting function,
    that's definitely doable, but it's a sum-and-compare, not xor. Also,
    it's quite specialized so it's unlikely to end up in the stdlib.

    ChrisA
    --
    https://mail.python.org/mailman/listinfo/python-list

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael Speer@21:1/5 to python-list@python.org on Mon Nov 13 19:36:09 2023
    AFAICT, it's not nothing at all to do with 'xor' in any sense.

    As much as I agree that the function needn't be in the base of python, I
    can easily follow the OP's logic on the function name.

    With two items in the iterator, it is a standard binary exclusive or.

    It is true if one of but not both of the items is true.

    OP then generalized this to is exclusively one of any number of these
    options are true, which is different than the repetitious binary operator application, certainly, but is still very much an 'or' that excludes the
    case of other options being true.

    OP then generalized this from exclusively one truth in the set of variables
    to some other specific number of truths that need be.

    I expect the OP could then generalize this to a range of truthiness for the
    set with a minimum and maximum allowable truthiness, and probably a key function to extract some facet from the iterable for consideration.

    I understand why you find it disagreeable, but I cannot find it necessarily illogical, and it is easy, I think, to see what it has to do with xor.

    A better name for OP's generalization, however, could likely be 'aut', from
    the Latin exclusive or.


    On Mon, Nov 13, 2023 at 7:20 PM Grant Edwards via Python-list < python-list@python.org> wrote:

    On 2023-11-13, Dom Grigonis via Python-list <python-list@python.org>
    wrote:

    I am not asking. Just inquiring if the function that I described
    could be useful for more people.

    Which is: a function with API that of `all` and `any` and returns
    `True` if specified number of elements is True.

    I've got no objection to a function that counts True objects returned
    by an iterator and returns True IFF count == <N>.

    I've got no objection to a function that counts True objects returned
    by an iterator and returns True IFF count >= <N>.

    I've got no objection if that latter function short-circuits by
    stopping the iteration and returning True when it has seen <N> true
    objects.

    I don't recall ever having a need for such a function in the 25 years
    I've been writing Python code, but I'm not going to claim that nobody
    else has a need for such a function.

    I would object to that being called 'xor', and would fight to the
    death (yes, I'm being hyperbolic) the addition of a builtin with the
    name 'xor' that does what you describe.

    It is not a generalised `xor` in strict programatic space.

    AFAICT, it's not nothing at all to do with 'xor' in any sense.

    I.e. NOT bitwise xor applied to many bits. This is more in line
    with cases that `any` and `all` builtins are used.

    Except the 'any' and 'all' builtins are _exactly_ the same as bitwise
    or and and applided to many bits. To do something "in line" with that
    using the 'xor' operator would return True for an odd number of True
    values and False for an even Number of True values.

    --
    Grant
    --
    https://mail.python.org/mailman/listinfo/python-list


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dom Grigonis@21:1/5 to All on Tue Nov 14 02:28:12 2023
    Except the 'any' and 'all' builtins are _exactly_ the same as bitwise
    or and and applided to many bits. To do something "in line" with that
    using the 'xor' operator would return True for an odd number of True
    values and False for an even Number of True values.

    Fair point.

    Have you ever encountered the need for xor for many bits (the one that I am NOT referring to)? Would be interested in what sort of case it could be useful.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Mats Wichmann@21:1/5 to Dom Grigonis via Python-list on Mon Nov 13 17:33:06 2023
    On 11/13/23 16:24, Dom Grigonis via Python-list wrote:
    I am not arguing that it is a generalised xor.

    I don’t want anything, I am just gauging if it is specialised or if there is a need for it. So just thought could suggest it as I have encountered such need several times already.

    It is fairly clear by now that it is not a common one given it took some time to even convey what I mean. Bad naming didn’t help ofc, but if it was something that is needed I think it would have clicked much faster.

    There are things that If You Need Them You Know, and If You Do Not You
    Do Not Understand - and you seem to have found one. The problem is that forums like this are not a statistically great sampling mechanism - a
    few dozen people, perhaps, chime in on many topics; there are millions
    of people using Python. Still, the folks here like to think they're at
    least somewhat representative :)

    Hardware and software people may have somewhat different views of xor,
    so *maybe* the topic title added a bit to the muddle. To me (one of
    those millions), any/all falsy, any/all truthy have some interest, and
    Python does provide those. Once you get into How Many True question -
    whether that's the odd-is-true, even-is-false model, or the bail-after-X-truthy-values model, it's not terribly interesting to me:
    once it gets more complex than an all/any decision, I need to check for particular combinations specifically. Two-of-six means nothing to me
    until I know which combination of two it is.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Grant Edwards@21:1/5 to Dom Grigonis via Python-list on Mon Nov 13 16:18:18 2023
    On 2023-11-13, Dom Grigonis via Python-list <python-list@python.org> wrote:

    I am not asking. Just inquiring if the function that I described
    could be useful for more people.

    Which is: a function with API that of `all` and `any` and returns
    `True` if specified number of elements is True.

    I've got no objection to a function that counts True objects returned
    by an iterator and returns True IFF count == <N>.

    I've got no objection to a function that counts True objects returned
    by an iterator and returns True IFF count >= <N>.

    I've got no objection if that latter function short-circuits by
    stopping the iteration and returning True when it has seen <N> true
    objects.

    I don't recall ever having a need for such a function in the 25 years
    I've been writing Python code, but I'm not going to claim that nobody
    else has a need for such a function.

    I would object to that being called 'xor', and would fight to the
    death (yes, I'm being hyperbolic) the addition of a builtin with the
    name 'xor' that does what you describe.

    It is not a generalised `xor` in strict programatic space.

    AFAICT, it's not nothing at all to do with 'xor' in any sense.

    I.e. NOT bitwise xor applied to many bits. This is more in line
    with cases that `any` and `all` builtins are used.

    Except the 'any' and 'all' builtins are _exactly_ the same as bitwise
    or and and applided to many bits. To do something "in line" with that
    using the 'xor' operator would return True for an odd number of True
    values and False for an even Number of True values.

    --
    Grant

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to python-list@python.org on Tue Nov 14 11:40:38 2023
    On Tue, 14 Nov 2023 at 11:29, Dom Grigonis via Python-list <python-list@python.org> wrote:


    Except the 'any' and 'all' builtins are _exactly_ the same as bitwise
    or and and applided to many bits. To do something "in line" with that
    using the 'xor' operator would return True for an odd number of True
    values and False for an even Number of True values.

    Fair point.

    Have you ever encountered the need for xor for many bits (the one that I am NOT referring to)? Would be interested in what sort of case it could be useful.

    Yes, parity checking. That's why I namedropped that in my prior
    response - it's an easy thing to search the web for if you want to
    know more about it.

    Here's a couple of excellent videos on error correction, and you'll
    see XOR showing up as a crucial feature:

    https://www.youtube.com/watch?v=X8jsijhllIA https://www.youtube.com/watch?v=h0jloehRKas

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dom Grigonis@21:1/5 to All on Tue Nov 14 03:00:26 2023
    I agree, from perspective of standard `all` and `any` use cases this does not seem very useful.

    However, in my experience it has its usages. E.g.:
    * If sum(map(bool, iterable) [> | <] n can be useful. Counting dead processes and similar, optimisation problems where need to re-initialise if less than certain number of nodes reached certain threshold.
    * If sum(map(bool, iterable) [== | !=] n is an edge case. Can’t even think of an example
    * Finally, it would be a convenient shorthand for `bool(a) ^ bool(b)`

    I sometimes think that there is also a case when certain function is not in one’s mind he doesn’t see the usefulness, but sometimes the sheer knowledge of its existence can twist certain situations in a positive manner.

    What about an alternative, which does seem more useful:

    def count_compare(iterable, n):
    return np.sign(sum(map(bool, iterable)) - n)

    print(count_compare([False, False, False], 1))
    As I am here, I will dare to ask if there is no way that `sign` function is going to be added to `math` or `builtins`. `np.sign` does the trick, but it is very slow to be used on a single number. And yes, I know that `copysign` exists, it just doesn’t
    do the same thing.

    DG

    On 14 Nov 2023, at 02:33, Mats Wichmann via Python-list <python-list@python.org> wrote:

    On 11/13/23 16:24, Dom Grigonis via Python-list wrote:
    I am not arguing that it is a generalised xor.
    I don’t want anything, I am just gauging if it is specialised or if there is a need for it. So just thought could suggest it as I have encountered such need several times already.
    It is fairly clear by now that it is not a common one given it took some time to even convey what I mean. Bad naming didn’t help ofc, but if it was something that is needed I think it would have clicked much faster.

    There are things that If You Need Them You Know, and If You Do Not You Do Not Understand - and you seem to have found one. The problem is that forums like this are not a statistically great sampling mechanism - a few dozen people, perhaps, chime in on
    many topics; there are millions of people using Python. Still, the folks here like to think they're at least somewhat representative :)

    Hardware and software people may have somewhat different views of xor, so *maybe* the topic title added a bit to the muddle. To me (one of those millions), any/all falsy, any/all truthy have some interest, and Python does provide those. Once you get
    into How Many True question - whether that's the odd-is-true, even-is-false model, or the bail-after-X-truthy-values model, it's not terribly interesting to me: once it gets more complex than an all/any decision, I need to check for particular
    combinations specifically. Two-of-six means nothing to me until I know which combination of two it is.


    --
    https://mail.python.org/mailman/listinfo/python-list

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Alan Gauld@21:1/5 to Mats Wichmann via Python-list on Tue Nov 14 01:08:26 2023
    On 14/11/2023 00:33, Mats Wichmann via Python-list wrote:
    Hardware and software people may have somewhat different views of xor

    I've come at it from both sides. I started life as a telecomms
    technician and we learned about xor in the context of switching
    and relays and xor was a wiring configuration for scenarios where
    you wanted any single change of switch state to toggle the
    entire system (think a stairwell with switches on every
    landing).

    Later, I got into software engineering and we studied Boolean
    algebra and xor was an odd number of Truth values, used in
    parity tests (and in encryption).

    But from both perspectives xor is pretty clearly defined
    in how it operates and not, I suspect, what the OP really
    wants in this case.

    --
    Alan G
    Author of the Learn to Program web site
    http://www.alan-g.me.uk/
    http://www.amazon.com/author/alan_gauld
    Follow my photo-blog on Flickr at:
    http://www.flickr.com/photos/alangauldphotos

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to python-list@python.org on Tue Nov 14 12:05:02 2023
    On Tue, 14 Nov 2023 at 12:02, Dom Grigonis via Python-list <python-list@python.org> wrote:
    As I am here, I will dare to ask if there is no way that `sign` function is going to be added to `math` or `builtins`.


    https://docs.python.org/3/library/math.html#math.copysign

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Chris Angelico@21:1/5 to Chris Angelico on Tue Nov 14 12:14:04 2023
    On Tue, 14 Nov 2023 at 11:40, Chris Angelico <rosuav@gmail.com> wrote:
    Here's a couple of excellent videos on error correction, and you'll
    see XOR showing up as a crucial feature:

    https://www.youtube.com/watch?v=X8jsijhllIA https://www.youtube.com/watch?v=h0jloehRKas


    I just flipped through that 3blue1brown video again, and as it turns
    out, the actual part where he talks about multi-argument XOR happens
    in part two (it's barely touched on at the very end as he's
    introducing part two).

    https://www.youtube.com/watch?v=b3NxrZOu_CE

    Honestly though, the full video is well worth watching. More modern
    error correction systems are slightly different, but will still be
    built on many of the same principles.

    ChrisA

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Grant Edwards@21:1/5 to Dom Grigonis via Python-list on Mon Nov 13 17:19:10 2023
    On 2023-11-14, Dom Grigonis via Python-list <python-list@python.org> wrote:

    Except the 'any' and 'all' builtins are _exactly_ the same as bitwise
    or and and applided to many bits. To do something "in line" with that
    using the 'xor' operator would return True for an odd number of True
    values and False for an even Number of True values.

    Fair point.

    Have you ever encountered the need for xor for many bits (the one
    that I am NOT referring to)? Would be interested in what sort of
    case it could be useful.

    Yes, it's used all the time in low-level communications protocols,
    where it's often implemented in hardware. But, it is also not at all
    unusual to implement it in software.

    It's also not that unusual for the "count-ones" part of the function
    you're asking for to be implemented in hardware by a CPU having an
    instruction that counts the number of 1 bits in a register.

    GCC has a low-level builtins called __builtin_popcount() and __builtin-popcountl() that counts the number of 1's in an unsigned
    (long) int.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From avi.e.gross@gmail.com@21:1/5 to Dom Grigonis via Python-list on Mon Nov 13 21:27:16 2023
    I was going to ask a dumb question. Has any other language you know of made something available that does what is being asked for and included it in the main program environment rather than an add-on?

    A secondary mention here has been whether short-circuiting functions like
    "any" and "all" have been augmented with something like "has_n" that
    evaluates arguments till it has found n or perhaps n+1 of what it wants then skips the rest. Does any language supply something like that? What would
    such a function return and does it have an "any" or an "all" side?

    It sounds like if I asked if a list of integers has at least n prime numbers
    in "any" mode, it should ignore any that are not primes till it finds n
    primes or fails and returns true or false. If in "all" mode, I assume it
    would have to be the first n items without a failure.

    Fine, but then someone may want to know WHERE you stopped or for you to
    return the sublist of the ones that made the match, or even return
    everything that was skipped so you can later process that. Consider a long
    list of jurors you process to place a dozen that qualify on a jury and then later you want to choose from among the rest for another jury.

    Human minds can come up with an amazing number of ideas including for
    "useful" functions or features but I find the vast majority would rarely be used as nobody remembers it is available and some fairly simple method using other functions can easily be cobbled together.

    -----Original Message-----
    From: Python-list <python-list-bounces+avi.e.gross=gmail.com@python.org> On Behalf Of Grant Edwards via Python-list
    Sent: Monday, November 13, 2023 8:19 PM
    To: python-list@python.org
    Subject: Re: xor operator

    On 2023-11-14, Dom Grigonis via Python-list <python-list@python.org> wrote:

    Except the 'any' and 'all' builtins are _exactly_ the same as bitwise
    or and and applided to many bits. To do something "in line" with that
    using the 'xor' operator would return True for an odd number of True
    values and False for an even Number of True values.

    Fair point.

    Have you ever encountered the need for xor for many bits (the one
    that I am NOT referring to)? Would be interested in what sort of
    case it could be useful.

    Yes, it's used all the time in low-level communications protocols,
    where it's often implemented in hardware. But, it is also not at all
    unusual to implement it in software.

    It's also not that unusual for the "count-ones" part of the function
    you're asking for to be implemented in hardware by a CPU having an
    instruction that counts the number of 1 bits in a register.

    GCC has a low-level builtins called __builtin_popcount() and __builtin-popcountl() that counts the number of 1's in an unsigned
    (long) int.


    --
    https://mail.python.org/mailman/listinfo/python-list

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter J. Holzer@21:1/5 to Dom Grigonis via Python-list on Wed Nov 15 01:34:15 2023
    On 2023-11-14 00:11:30 +0200, Dom Grigonis via Python-list wrote:
    Benchmarks:
    test1 = [False] * 100 + [True] * 2
    test2 = [True] * 100 + [False] * 2

    TIMER.repeat([
    lambda: xor(test1), # 0.0168
    lambda: xor(test2), # 0.0172
    lambda: xor_ss(test1), # 0.1392
    lambda: xor_ss(test2), # 0.0084
    lambda: xor_new(test1), # 0.0116
    lambda: xor_new(test2), # 0.0074
    lambda: all(test1), # 0.0016
    lambda: all(test2) # 0.0046
    ])
    Your first function is fairly slow.
    Second one deals with short-circuiting, but is super slow on full search.

    `xor_new` is the best what I could achieve using python builtins.

    But builtin `all` has the best performance.

    One question worth asking is if a list of bool is the best data
    structure for the job. This is essentially a bitmap, and a bitmap is
    equivalent to a set of integers. len(s) == 1 is also a fairly quick
    operation if s is small. On my system, len(test1s) == 1 (where test1s is
    {100, 101}) is about as fast as all(test1) and len(test2s) == 1 (where
    test2s is set(range(100))) is about twice as fast as all(test2).

    If you are willing to stray from the standard library, you could e.g.
    use pyroaring instead of sets: This is about as fast as all(test1)
    whether there are two bits set or a hundred.

    hp

    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ | challenge!"

    -----BEGIN PGP SIGNATURE-----

    iQIzBAABCgAdFiEETtJbRjyPwVTYGJ5k8g5IURL+KF0FAmVUEgIACgkQ8g5IURL+ KF3jpg/9GnZpVo6AEqRH+s6YWyBXKYSJ+0YhvesaDHwIgxOflZ8JsZprnFofXtNC JWWpeWjHWmNXncupjzvlLr5cqAv+I/V1VuAGXUkmFZjl6bcAJhYF+OqOjz2U2fch lvZpwEp8O3VhajJ5lmw4wQRtD19b6aHo7MHpn2GGvmXFlk+/sFN9VlHKHKARu19d c/UR8ENuUztMRxyC9uPdAV6b4hEIxrCjksNqSyU/pn2lnSsRNKJlGbl9LhyTmGLY SscUzWBQLYICCu8/2kZdBErtHFnxjtiwWzqoggQAodwAL5cfQCD9vUTFRSnkD/fJ qiByeHZLlfAlwpPhc92ay/R2wN9ZMFdjxYSqUTKN8Tx8muoLZreYWFpOg3f4kYjQ WRuBX1ww5732GBadC53JezRcF2tSHQZB1U2XzRf2ziArTCr7KAwBs2iHhHB2zWDN 0i8jGDxAiOHHTasSBQUAtMowOSje269+P5+jVEgHjTipaAOQA07Ff1UaGLjpI1oL 63fWw6B3uw5HFTJl6ZIQN0MXo0kO0106S+HdnXu+GK0SzUF1/xeROOXECZCrk2q8 s2DQ82CtOs4HU4ObijZ7+u2ve1eVemJkb8cVTQ9cU3c1JUOuAlmHuDPz7pEn96UV h2zOBNmFvMNIzlbZLLwNNovOq2v97lLPcZ05Ujr
  • From Dom Grigonis@21:1/5 to All on Wed Nov 15 12:26:32 2023
    Thank you,

    test2 = [True] * 100 + [False] * 2
    test2i = list(range(100))

    %timeit len(set(test2i)) == 1 # 1.6 µs ± 63.6 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
    %timeit all(test2) # 386 ns ± 9.58 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

    test2s = set(test2i)
    %timeit len(test2s) == 1 # 46.1 ns ± 1.65 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
    If you pre-convert to set it is obviously faster. However, set operation is most likely going to be part of the procedure. In which case it ends up to be significantly slower.

    Regards,
    DG


    On 15 Nov 2023, at 02:34, Peter J. Holzer via Python-list <python-list@python.org> wrote:

    On 2023-11-14 00:11:30 +0200, Dom Grigonis via Python-list wrote:
    Benchmarks:
    test1 = [False] * 100 + [True] * 2
    test2 = [True] * 100 + [False] * 2

    TIMER.repeat([
    lambda: xor(test1), # 0.0168
    lambda: xor(test2), # 0.0172
    lambda: xor_ss(test1), # 0.1392
    lambda: xor_ss(test2), # 0.0084
    lambda: xor_new(test1), # 0.0116
    lambda: xor_new(test2), # 0.0074
    lambda: all(test1), # 0.0016
    lambda: all(test2) # 0.0046
    ])
    Your first function is fairly slow.
    Second one deals with short-circuiting, but is super slow on full search.

    `xor_new` is the best what I could achieve using python builtins.

    But builtin `all` has the best performance.

    One question worth asking is if a list of bool is the best data
    structure for the job. This is essentially a bitmap, and a bitmap is equivalent to a set of integers. len(s) == 1 is also a fairly quick
    operation if s is small. On my system, len(test1s) == 1 (where test1s is {100, 101}) is about as fast as all(test1) and len(test2s) == 1 (where
    test2s is set(range(100))) is about twice as fast as all(test2).

    If you are willing to stray from the standard library, you could e.g.
    use pyroaring instead of sets: This is about as fast as all(test1)
    whether there are two bits set or a hundred.

    hp

    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at <mailto:hjp@hjp.at> | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ <http://www.hjp.at/> | challenge!"
    --
    https://mail.python.org/mailman/listinfo/python-list <https://mail.python.org/mailman/listinfo/python-list>

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Peter J. Holzer@21:1/5 to Dom Grigonis on Wed Nov 15 18:16:50 2023
    On 2023-11-15 12:26:32 +0200, Dom Grigonis wrote:

    Thank you,


    test2 = [True] * 100 + [False] * 2
    test2i = list(range(100))

    %timeit len(set(test2i)) == 1 # 1.6 s 63.6 ns per loop (mean std. dev. of 7 runs, 1,000,000 loops each)
    %timeit all(test2) # 386 ns 9.58 ns per loop (mean std. dev. of 7 runs, 1,000,000 loops each)

    test2s = set(test2i)
    %timeit len(test2s) == 1 # 46.1 ns 1.65 ns per loop (mean std. dev. of 7 runs, 10,000,000 loops each)

    If you pre-convert to set it is obviously faster. However, set
    operation is most likely going to be part of the procedure. In which
    case it ends up to be significantly slower.

    Obviously, if you convert a list to a set just to count the elements
    it's going to be slow. My suggestion was to use the set *instead* of the
    list. I don't know whether that's possible in your situation, because
    you haven't told us anything about it. All I'm suggesting is taking a
    step back and reconsider your choice of data structure.

    hp
    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ | challenge!"

    -----BEGIN PGP SIGNATURE-----

    iQIzBAABCgAdFiEETtJbRjyPwVTYGJ5k8g5IURL+KF0FAmVU/P4ACgkQ8g5IURL+ KF0T0hAAmUd1kiHEGFj+aYMI8GaBnGWPwXQNybLvhzB/XPi9oQPV7lid+f/oxIJJ HD0M3bByID5BtD0f63Pp5nd5MjmmpWPHsH9fwgo+YK2DuBIOPhmObM15aYRNXlp5 Na1LT3vnCoFp8i4grAHLB3rFzlLekPLwOAxya0lDQUTOEOfs42DwKpBfZ0BclSYF xtzYhJj8YhBVvSx+UBls7bd+AmHtQEfZmYIiux98yE3B+yBiJEcdb5q1FdUhZTij fVqZzQBTZjHnoNG+iNYFJVaEV1Vlx6wTwt9gVB623WYxqYWEV50Bc/KN9/2pZFz0 /gYly7LxbmCDj+a+HcAt17uypOH0u5uRU31OV95IjpXryEQijQ1tzwK3abY7aM6J lIGKsJwvi+5dJP8NEb2Jbo1/ulH+ogleJCz0xRZB+oGxUMNPlIaIIgTgiyji3Av9 /nJ/HoKWOjFuaVP6owA3WBltgRlL6GMFW7ZyvjrkKJY60hRewB1jrpJnxJeuyF1p bPCVo7VcNNQcdarkEXrFlkU7z/V2Eu9ba9m+eTyo8OKCEnkTre3WIlzkj5opR7Zf VEecMNBioWROsb7+jZ0W6P3gh0Np8JwvV3AeCnpplm+zmlcuhgq+7Tz4+9gyLpw6 8vrphUr68EXXQwHBn7j+WtenEjY+oo/ufiFEuC8
  • From Dom Grigonis@21:1/5 to All on Wed Nov 15 20:13:50 2023
    The specific situation was related to truth values and following out of that my considerations regarding equivalent of all and any for counting `truths`.

    So one of the specific examples:
    class Publisher:
    def __init__(self):
    self.subscribers = dict()

    def subscribe(self, sub, criteria, agg=all):
    self.subscribers[sub] = (criteria, agg)

    def publish(self, msg):
    for sub, criteria in self.subscribers.items():
    if criteria(msg):
    sub.handle(msg)

    p = Publisher()
    p.subscribe(sub, lambda x: all(r > 3 for r in x.ratings))

    # So what I needed is:
    p.subscribe(sub, lambda x: set(r > 3 for r in x.ratings) > 50)
    # Note, that elements might not necessarily be bool.
    # E.g. at least 51 non-empty pages
    p.subscribe(sub, lambda x: set(bool(p) for p in x.pages) > 50)
    # So the function:
    p.subscribe(sub, lambda x: xor_more_than(x.pages, 50)
    # would ideally deal with truth values too.
    The question is: can you construct a function? which:
    a) performs: lambda x: set(bool(el) for el in iterable) > n
    b) is in line with performance of python’s `all`

    Then, as I said the case where one would need `set() == n` is hard to think of, but it seems fairly probable to need `set() > n` and `set() < n`.

    Regards,
    DG

    On 15 Nov 2023, at 19:16, Peter J. Holzer via Python-list <python-list@python.org> wrote:

    On 2023-11-15 12:26:32 +0200, Dom Grigonis wrote:

    Thank you,


    test2 = [True] * 100 + [False] * 2
    test2i = list(range(100))

    %timeit len(set(test2i)) == 1 # 1.6 µs ± 63.6 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
    %timeit all(test2) # 386 ns ± 9.58 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

    test2s = set(test2i)
    %timeit len(test2s) == 1 # 46.1 ns ± 1.65 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)

    If you pre-convert to set it is obviously faster. However, set
    operation is most likely going to be part of the procedure. In which
    case it ends up to be significantly slower.

    Obviously, if you convert a list to a set just to count the elements
    it's going to be slow. My suggestion was to use the set *instead* of the list. I don't know whether that's possible in your situation, because
    you haven't told us anything about it. All I'm suggesting is taking a
    step back and reconsider your choice of data structure.

    hp
    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ | challenge!"
    --
    https://mail.python.org/mailman/listinfo/python-list

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Dom Grigonis@21:1/5 to All on Wed Nov 15 21:00:06 2023
    In case someone is actually going to execute the code, there is a bug:

    `set` need to be wrapped in `len` for criteria args.

    On 15 Nov 2023, at 20:13, Dom Grigonis <dom.grigonis@gmail.com> wrote:


    The specific situation was related to truth values and following out of that my considerations regarding equivalent of all and any for counting `truths`.

    So one of the specific examples:
    class Publisher:
    def __init__(self):
    self.subscribers = dict()

    def subscribe(self, sub, criteria, agg=all):
    self.subscribers[sub] = (criteria, agg)

    def publish(self, msg):
    for sub, criteria in self.subscribers.items():
    if criteria(msg):
    sub.handle(msg)

    p = Publisher()
    p.subscribe(sub, lambda x: all(r > 3 for r in x.ratings))

    # So what I needed is:
    p.subscribe(sub, lambda x: set(r > 3 for r in x.ratings) > 50)
    # Note, that elements might not necessarily be bool.
    # E.g. at least 51 non-empty pages
    p.subscribe(sub, lambda x: set(bool(p) for p in x.pages) > 50)
    # So the function:
    p.subscribe(sub, lambda x: xor_more_than(x.pages, 50)
    # would ideally deal with truth values too.
    The question is: can you construct a function? which:
    a) performs: lambda x: set(bool(el) for el in iterable) > n
    b) is in line with performance of python’s `all`

    Then, as I said the case where one would need `set() == n` is hard to think of, but it seems fairly probable to need `set() > n` and `set() < n`.

    Regards,
    DG

    On 15 Nov 2023, at 19:16, Peter J. Holzer via Python-list <python-list@python.org <mailto:python-list@python.org>> wrote:

    On 2023-11-15 12:26:32 +0200, Dom Grigonis wrote:

    Thank you,


    test2 = [True] * 100 + [False] * 2
    test2i = list(range(100))

    %timeit len(set(test2i)) == 1 # 1.6 µs ± 63.6 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
    %timeit all(test2) # 386 ns ± 9.58 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)

    test2s = set(test2i)
    %timeit len(test2s) == 1 # 46.1 ns ± 1.65 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)

    If you pre-convert to set it is obviously faster. However, set
    operation is most likely going to be part of the procedure. In which
    case it ends up to be significantly slower.

    Obviously, if you convert a list to a set just to count the elements
    it's going to be slow. My suggestion was to use the set *instead* of the
    list. I don't know whether that's possible in your situation, because
    you haven't told us anything about it. All I'm suggesting is taking a
    step back and reconsider your choice of data structure.

    hp
    --
    _ | Peter J. Holzer | Story must make more sense than reality.
    |_|_) | |
    | | | hjp@hjp.at <mailto:hjp@hjp.at> | -- Charles Stross, "Creative writing
    __/ | http://www.hjp.at/ <http://www.hjp.at/> | challenge!"
    --
    https://mail.python.org/mailman/listinfo/python-list <https://mail.python.org/mailman/listinfo/python-list>


    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)