Problematic proof by contradiction - first-order-logic

I am trying prove this implication, however I keep getting stuck and I cannot figure out where to go next. I know I will need to do a proof by contradiction.
The steps I already took are:
{¬∀ to ∃} (∃i : 0≤i < n : ¬(b[i]))
{∃ Elimination} [Some K] 0≤k < n ∧ ¬b[k]
I have to prove this:
¬(∀i : 0≤i < n : b[i]) ∧ (∀i : j≤i < n : b[i])
⇒
¬(∀i : 0≤i < j : b[i])
I feel like I should put get a false by getting a b[k] ∧ ¬b[k]. But I cannot figure out how to get that.

You can use implication elimination:
¬(∀i : 0≤i < n : b[i]) ∧ (∀i : j≤i < n : b[i])
⇒
¬(∀i : 0≤i < j : b[i])
≡ ¬[¬(∀i : 0≤i < n : b[i]) ∧ (∀i : j≤i < n : b[i])] ∨ ¬(∀i : 0≤i < j : b[i])
≡ (∀i : 0≤i < n : b[i]) ∨ ¬(∀i : j≤i < n : b[i]) ∨ ¬(∀i : 0≤i < j : b[i])
≡ (∀i : 0≤i < n : b[i]) ∨ (∃i : j≤i < n : ¬b[i]) ∨ (∃i : 0≤i < j : ¬b[i])
Then you can split the first one:
≡ [ (∀i : 0≤i < j : b[i]) ∧ (∀i : j≤i < n : b[i]) ] ∨ (∃i : j≤i < n : ¬b[i]) ∨ (∃i : 0≤i < j : ¬b[i])
≡ [ (∀i : 0≤i < j : b[i]) ∧ (∀i : j≤i < n : b[i]) ] ∨ ¬(∀i : j≤i < n : b[i]) ∨ ¬(∀i : 0≤i < j : b[i])
≡ [ (∀i : 0≤i < j : b[i]) ∧ (∀i : j≤i < n : b[i]) ] ∨ ¬[ (∀i : j≤i < n : b[i]) ∧ (∀i : 0≤i < j : b[i]) ]
≡ A ∨ ¬A
≡ True

Related

Why can't I move a partial box definition into a local binding?

As a followup to this, I realized I need to use a heterogeneous composition to make a lid for a partial box. Here I have removed all the unnecessary cruft:
{-# OPTIONS --cubical #-}
module _ where
open import Cubical.Core.Everything
open import Cubical.Foundations.Everything
postulate
A : Type
P : A → Type
PIsProp : ∀ x → isProp (P x)
prove : ∀ x → P x
x y : A
q : x ≡ y
a = prove x
b = prove y
prf : PathP (λ i → P (q i)) a b
prf = p
where
b′ : P y
b′ = subst P q a
r : PathP _ a b′
r = transport-filler (λ i → P (q i)) a
-- a b
-- ^ ^
-- | |
-- refl | | PIsProp y _ _
-- | |
--- a ---------> b′
-- r
p-faces : (i j : I) → Partial (i ∨ ~ i) (P (q i))
p-faces i j (i = i0) = a
p-faces i j (i = i1) = PIsProp y b′ b j
p : PathP (λ i → P (q i)) a b
p i = comp (λ j → P (q i)) ? (r i)
So here the only remaining hole is in the defintion of p. I'd like to fill it with p-faces i, of course, because that is the reason I defined it. However, this leads to a universe level error:
p : PathP (λ i → P (q i)) a b
p i = comp (λ j → P (q i)) (p-faces i) (r i)
Agda.Primitive.SSet ℓ-zero != Agda.Primitive.SSetω
when checking that the expression p-faces i has type
(i₁ : I) → Partial (i ∨ ~ i) (P (q i))
However, if I inline the definition of p-faces into p, it typechecks; note that this also includes typechecking the definition of p-faces (I don't need to remove it), it is only the usage of p-faces that causes this type error:
p : PathP (λ i → P (q i)) a b
p i = comp (λ j → P (q i)) (λ { j (i = i0) → a; j (i = i1) → PIsProp y b′ b j }) (r i)
What is the issue with using p-faces in the definition of p? To my untrained eyes, it looks like a normal definition never going above Type₀
I see you are using agda/master!
The following would have also worked
p i = comp (λ j → P (q i)) (\ j -> p-faces i j) (r i)
with the introduction of --two-level the types of comp and transp trigger a problem with sort assignment for universe polymorphism, so some eta expansion is needed here to let Agda check the lambda at the sort it wants.
Hopefully we'll find a better solution soon.

Moving an ST computation to a sub-computation

I have the following code running in ST using random numbers:
module Main
import Data.Vect
import Data.Fin
import Control.ST
import Control.ST.Random
%default total
choose : (Monad m) => (rnd : Var) -> (n : Nat) -> Vect (n + k) a -> ST m (Vect n a, Vect k a) [rnd ::: Random]
choose rnd n xs = pure $ splitAt n xs -- Dummy implementation
partitionLen : (a -> Bool) -> Vect n a -> DPair (Nat, Nat) (\(m, k) => (m + k = n, Vect m a, Vect k a))
partitionLen p [] = ((0, 0) ** (Refl, [], []))
partitionLen p (x :: xs) = case partitionLen p xs of
((m, k) ** (prf, lefts, rights)) =>
if p x then
((S m, k) ** (cong prf, x::lefts, rights))
else
((m, S k) ** (trans (plusS m k) (cong prf), lefts, x::rights))
where
plusS : (x : Nat) -> (y : Nat) -> x + (S y) = S (x + y)
plusS Z y = Refl
plusS (S x) y = cong (plusS x y)
generate : (Monad m) => (rnd : Var) -> ST m (Vect 25 (Fin 25)) [rnd ::: Random]
generate rnd = do
(shared, nonshared) <- choose rnd 4 indices
(agents1, nonagents1) <- choose rnd 6 nonshared
(agents2, nonagents2) <- choose rnd 6 nonagents1
(assassins1, others1) <- choose rnd 2 nonagents1
case partitionLen (`elem` assassins1) nonagents2 of
((n, k) ** (prf, xs, ys)) => do
(assassins2, others2') <- choose rnd 2 (agents1 ++ xs)
let prf' = trans (sym $ plusAssociative 4 n k) $ cong {f = (+) 4} prf
let others2 = the (Vect 13 (Fin 25)) $ replace {P = \n => Vect n (Fin 25)} prf' (others2' ++ ys)
pure $ shared ++ agents2 ++ assassins2 ++ others2
where
indices : Vect 25 (Fin 25)
indices = fromList [0..24]
I'd like to refactor generate so that instead of the whole tail of the computation is under a case, I would compute (assassins2, others2) in a sub-computation, i.e. I would like to rewrite it as such:
(assassins2, others2) <- case partitionLen (`elem` assassins1) nonagents2 of
((n, k) ** (prf, xs, ys)) => do
(assassins2, others2') <- choose rnd 2 (agents1 ++ xs)
let prf' = trans (sym $ plusAssociative 4 n k) $ cong {f = (+) 4} prf
let others2 = replace {P = \n => Vect n (Fin 25)} prf' (others2' ++ ys)
pure (assassins2, others2)
pure $ shared ++ agents2 ++ assassins2 ++ others2
I believe this should be an equivalent transformation. However, this second version fails type-checking with:
When checking right hand side of Main.case block in case block in case block in case block in case block in generate with expected type
STrans m
(Vect 25 (Fin 25))
(st2_fn (assassins2, others2))
(\result => [rnd ::: State Integer])
When checking argument ys to function Data.Vect.++:
Type mismatch between
B (Type of others2)
and
Vect n (Fin 25) (Expected type)

What sort of time complexity would be required to solve the RSA Factoring Challenge?

Although the challenge ended a long time ago, I'm kinda bored so I decided to try to factorise some of the numbers.
I initially had an O(n) algorithm, but then, I decided to research big O notation.
Apparently (I could be wrong), O(n) algorithms and O(2n) algorithms basically have the same running time. So do O(n) and O(4n) algorithms. In fact, O(n) and O(cn) algorithms (where c is an integer) essentially have the same running time.
So now, I have an O(8n) algorithm, but it isn't quick enough for 77-bit numbers.
What sort of time complexity would be required to factorise the first few RSA numbers (in under 5-ish minutes)?
My O(8n) algorithm:
import math
num = int(input())
sq = math.sqrt(num)
if num % 2 == 0:
print(2, int(num / 2))
elif sq % 1 == sq:
print(int(sq), int(sq))
else:
sq = round(sq)
a = 3
b = sq + (1 - (sq % 2))
c = ((b + 1) / 2)
d = ((b + 1) / 2)
c -= (1 - (c % 2))
d += (1 - (d % 2))
e = ((c + 1) / 2)
f = ((c + 1) / 2)
e -= (1 - (e % 2))
f += (1 - (f % 2))
g = ((d + 1) / 2) + d
h = ((d + 1) / 2) + d
g -= (1 - (g % 2))
h += (1 - (h % 2))
while a <= sq and num % a != 0 and b > 2 and num % b != 0 and c <= sq and num % c != 0 and d > 2 and num % d != 0 and e <= sq and num % e != 0 and f > 2 and num % f != 0 and g <= sq and num % g != 0 and h > 2 and num % h != 0:
a += 2
b -= 2
c += 2
d -= 2
e += 2
f -= 2
g += 2
h -= 2
if num % a == 0:
print(a, int(num / a))
elif num % b == 0:
print(b, int(num / b))
elif num % c == 0:
print(c, int(num / c))
elif num % d == 0:
print(d, int(num / d))
elif num % e == 0:
print(e, int(num / e))
elif num % f == 0:
print(f, int(num / f))
elif num % g == 0:
print(g, int(num / g))
elif num % h == 0:
print(h, int(num / h))
Your algorithm is poorly-implemented trial division. Throw it away.
Here is my basic prime-number library, using the Sieve of Eratosthenes to enumerate prime numbers, the Miller-Rabin algorithm to recognize primes, and wheel factorization followed by Pollard's rho algorithm to factor composites, which I leave to you to translate to Python:
function primes(n)
i, p, ps, m := 0, 3, [2], n // 2
sieve := makeArray(0..m-1, True)
while i < m
if sieve[i]
ps := p :: ps # insert at head of list
for j from (p*p-3)/2 to m step p
sieve[i] := False
i, p := i+1, p+2
return reverse(ps)
function isPrime(n, k=5)
if n < 2 then return False
for p in [2,3,5,7,11,13,17,19,23,29]
if n % p == 0 then return n == p
s, d = 0, n-1
while d % 2 == 0
s, d = s+1, d/2
for i from 0 to k
x = powerMod(randint(2, n-1), d, n)
if x == 1 or x == n-1 then next i
for r from 1 to s
x = (x * x) % n
if x == 1 then return False
if x == n-1 then next i
return False
return True
function factors(n, limit=10000)
wheel := [1,2,2,4,2,4,2,4,6,2,6]
w, f, fs := 0, 2, []
while f*f <= n and f < limit
while n % f == 0
fs, n := f :: fs, n / f
f, w := f + wheel[w], w+1
if w = 11 then w = 3
if n == 1 return fs
h, t, g, c := 1, 1, 1, 1
while not isPrime(n)
repeat
h := (h*h+c) % n # the hare runs
h := (h*h+c) % n # twice as fast
t := (t*t+c) % n # as the tortoise
g := gcd(t-h, n)
while g == 1
if isPrime(g)
while n % g == 0
fs, n := g :: fs, n / g
h, t, g, c := 1, 1, 1, c+1
return sort(n :: fs)
function powerMod(b, e, m)
x := 1
while e > 0
if e%2 == 1
x, e := (x*b)%m, e-1
else b, e := (b*b)%m, e//2
return x
function gcd(a, b)
if b == 0 then return a
return gcd(b, a % b)
Properly implemented, that algorithm should factor your 79-bit number nearly instantly.
To factor larger numbers, you will have to work harder. Look up "elliptic curve factorization" and "self-initializing quadratic sieve" to find factoring algorithms that you can implement yourself.

Simplification of pseudocode

I am trying to re-write the following pseudocode as the simplest if-else, but am struggling to understand the logic fully.
if (a <= b) then // Here, a <= b.
if (y > b) then P // Here, (a <= b) & (y > b).
else if (x < a) then P // Here, (a <= b) & !(y > b) & (x < a).
else if ((y >= a) & (x <= b)) then Q else R
My interpretations of the pseudocode so far are written in comments above.
I think that I have correctly understood the logic of the first three lines of pseudocode.
However, I am not sure how to interpret the logic of the fourth and last line of the pseudocode.
I would like help to understand the state(s) of the four variables at the fourth line, as well as how to re-write the pseudocode as the simplest if-else.
How to get to the last line:
a <= b has to be true
y > b has to be false
x < a has to be false
so the last line would be:
(a <= b) & !(y > b) & !(x < a) & (y >= a) & (x <= b)
this leads to the following results:
a <= b & a <= x & a <= y -> a has to be the smallest value
b >= a & b >= y & b >= x -> b has to be the greatest value
y <= b & y >= a -> y has to be in between of a and b
x >= a & x <= b -> x has to be in between of a and b
which leads to:
if((x >= a & x <= b) & (y >= a & y <= b))
(but this only works if you just want to get to the last line)

Can you simplify this expression?

One for the mathematicians. This has gone around the office and we want to see who can come up with a better optimised version.
(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) &&
((b - (a + p) == 0) || (b - (a + p) > 1))
Edit: all data is positive int's
Edit: Better == simpler
(a + p <= b) && (a != 1) && (b - a - p != 1);
If the formula works and come from your business rules there is no real need to simplify it. The compiler probably knows better than us how to optimizing the formula.
The only thing you should do is use better variables names which reflect the business logic.
Beware of applying any of the proposed solution before unit testing them.
Refactor for simplicity by introducing more local variables which indicate the meaning of each expression. This is hard for us to do with no idea of what a, b and p mean.
b >= p && b != p+1
EDIT: Ok, that didn't work, but this one does:
a != 1 && b >= a+p && b-a-p != 1
(a!=1) && ((b==a+p) || (b>1+a+p))
It may not the simplest, but should be the one of most readable.
I wouldnt do all math in that expression. Such as b - ( a + p ) is evaluated twice. If possible, split them into variables instead.
Also, writing a polish notiation tree might help you optimize it, everything that you see twice, can be re-used.
Since they are all positive ints a lot of the repetition can be removed:
So as a first step,
(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
becomes
((a+p) <= b) && (a != 1) && (b >= p)) && ((b - (a + p) != 1)
For clarity, this is just replacing the (foo == 0 || foo > 1) pattern with foo != 1
That pattern appears twice above, once with foo = a, and once with foo = (b - (a+p))
Since the ints are unsigned, (a==0 || a>1) can be substituted for (a !=1).
With a first pass, you can reduce it to this:
uint sum = a + p;
return ((sum <= b) && (a != 1) && (b >= p)) && (b - sum != 1);
Also, it would be much more readable if you were able to give more meaningful names to the variables. For instance, if a and p were pressures, then a+p could be substitued as PressureSum.
s = a + p
b >= s && a != 1 && b - s - 1 > 0
Checked, returns the same boolean value as the question.
Program that I have used to check: (had fun writing it)
#include <iostream>
using namespace std;
typedef unsigned int uint;
bool condition(uint a, uint b, uint p)
{
uint s = a + p;
return uint( b >= s && a != 1 && b - s - 1 > 0 )
== uint( (((a+p) <= b) && (a == 0 || a > 1) && (b >= p))
&& ((b - (a + p) == 0) || (b - (a + p) > 1)) );
}
void main()
{
uint i = 0;
uint j = 0;
uint k = 0;
const uint max = 50;
for (uint i = 0; i <= max; ++i)
for (uint j = 0; j <= max; ++j)
for (uint k = 0; k <= max; ++k)
if (condition(i, j, k) == false)
{
cout << "Fails on a = " << i << ", b = " << j;
cout << ", p = " << k << endl;
int wait = 0;
cin >> wait;
}
}
bap = b - (a + p)
bap >= 0 && bap != 1 && a != 1
EDIT: Now I've got -2 for an honest attempt at helping out and also for what seems to me to be a valid answer. For you who can use Python, here are two functions, one with the question and one with my answer:
def question(a, b, p):
return (((a+p) <= b) and (a == 0 or a > 1) and (b >= p)) or ((b - (a + p) == 0) or (b - (a + p) > 1))
def answer(a, b, p):
bap = b - (a + p)
return bap >= 0 and bap != 1 and a != 1
Tested with a,b,p from 0 to 10000:
a != 1 && a != (b-p-1) && a <= (b-p);
I think it can be simplified even more.
This is as simple as I could get it.
def calc(a, b, p):
if (a != 1):
temp = a - b + p
if temp == 0 or temp < -1:
return True
return False
It could also be written as:
def calc(a, b, p):
temp = a - b + p
return a != 1 and (temp == 0 or temp < -1)
Or as:
def calc(a, b, p):
temp = a - b + p
return a != 1 and temp <= 0 and temp != -1
// In one line:
return (a != 1) && ((b-a-p == 0) || (b-a-p > 1))
// Expanded for the compiler:
if(a == 1)
return false;
int bap = b - a - p;
return (bap == 0) || (bap > 1);
If you post the processor you are using, I can optimize for assembly. =]
jjngy up here has it right. Here's a proof that his simplified formula is equivalent to the original using the Coq Proof Assistant.
Require Import Arith.
Require Import Omega.
Lemma eq : forall (a b p:nat),
(((a+p) <= b) /\ ((a = 0) \/ (a > 1)) /\ (b >= p)) /\
((b - (a + p) = 0) \/ (b - (a + p) > 1)) <->
((a + p <= b) /\ ~ (a= 1) /\ ~ (b - a - p = 1)).
Proof. intros; omega. Qed.
my apologies for the mistake in the original derivation. This is what happens when you don't bother to unit test after refactoring!
the corrected derivation follows, in the form of a test program.
The short answer is:
((a > 1) && (skeet == 0)) || ((a > 1) && (jon > 0) && (skeet < -1));
where
jon = (b - p)
skeet = (a - jon);
class Program
{
static void Main(string[] args)
{
bool ok = true;
for (int a = 1; a < 100; a++)
{
Console.Write(a.ToString());
Console.Write("...");
for (int b = 1; b < 100; b++)
{
for (int p = 1; p < 100; p++)
{
bool[] results = testFunctions(a, b, p);
if (!allSame(results))
{
Console.WriteLine(string.Format(
"Fails for {0},{1},{2}", a, b, p));
for (int i = 1; i <= results.Length; i++)
{
Console.WriteLine(i.ToString() + ": " +
results[i-1].ToString());
}
ok = false;
break;
}
}
if (!ok) { break; }
}
if (!ok) { break; }
}
if (ok) { Console.WriteLine("Success"); }
else { Console.WriteLine("Failed!"); }
Console.ReadKey();
}
public static bool allSame(bool[] vals)
{
bool firstValue = vals[0];
for (int i = 1; i < vals.Length; i++)
{
if (vals[i] != firstValue)
{
return false;
}
}
return true;
}
public static bool[] testFunctions(int a, int b, int p)
{
bool [] results = new bool[16];
//given: all values are positive integers
if (a<=0 || b<=0 || p<=0)
{
throw new Exception("All inputs must be positive integers!");
}
//[1] original expression
results[0] = (((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) &&
((b - (a + p) == 0) || (b - (a + p) > 1));
//[2] a==0 cannot be true since a is a positive integer
results[1] = (((a+p) <= b) && (a > 1) && (b >= p)) &&
((b - (a + p) == 0) || (b - (a + p) > 1));
//[3] rewrite (b >= p) && ((a+p) <= b)
results[2] = (b >= p) && (b >= (a+p)) && (a > 1) &&
((b - (a + p) == 0) || (b - (a + p) > 1));
//[4] since a is positive, (b>=p) guarantees (b>=(p+a)) so we
//can drop the latter term
results[3] = (b >= p) && (a > 1) &&
((b - (a + p) == 0) || (b - (a + p) > 1));
//[5] separate the two cases b>=p and b=p
results[4] = ((b==p) && (a > 1) && ((b - (a + p) == 0) ||
(b - (a + p) > 1))) || ((b > p) && (a > 1) &&
((b - (a + p) == 0) || (b - (a + p) > 1)));
//[6] rewrite the first case to eliminate p (since b=p
//in that case)
results[5] = ((b==p) && (a > 1) && ((-a == 0) ||
(-a > 1))) || ((b > p) && (a > 1) &&
(((b - a - p) == 0) || ((b - a - p) > 1)));
//[7] since a>0, neither (-a=0) nor (-a>1) can be true,
//so the case when b=p is always false
results[6] = (b > p) && (a > 1) && (((b - a - p) == 0) ||
((b - a - p) > 1));
//[8] rewrite (b>p) as ((b-p)>0) and reorder the subtractions
results[7] = ((b - p) > 0) && (a > 1) && (((b - p - a) == 0) ||
((b - p - a) > 1));
//[9] define (b - p) as N temporarily
int N = (b - p);
results[8] = (N > 0) && (a > 1) && (((N - a) == 0) || ((N - a) > 1));
//[10] rewrite the disjunction to isolate a
results[9] = (N > 0) && (a > 1) && ((a == N) || (a < (N - 1)));
//[11] expand the disjunction
results[10] = ((N > 0) && (a > 1) && (a == N)) ||
((N > 0) && (a > 1) && (a < (N - 1)));
//[12] since (a = N) in the first subexpression we can simplify to
results[11] = ((a == N) && (a > 1)) ||
((N > 0) && (a > 1) && (a < (N - 1)));
//[13] extract common term (a > 1) and replace N with (b - p)
results[12] = (a > 1) && ((a == (b - p)) ||
(((b - p) > 0) && (a < (b - p - 1))));
//[14] extract common term (a > 1) and replace N with (b - p)
results[13] = (a > 1) && (((a - b + p) == 0) ||
(((b - p) > 0) && ((a - b + p) < -1)));
//[15] replace redundant subterms with intermediate
//variables (to make Jon Skeet happy)
int jon = (b - p);
int skeet = (a - jon); //(a - b + p) = (a - (b - p))
results[14] = (a > 1) && ((skeet == 0) ||
((jon > 0) && (skeet < -1)));
//[16] rewrite in disjunctive normal form
results[15] = ((a > 1) && (skeet == 0)) ||
((a > 1) && (jon > 0) && (skeet < -1));
return results;
}
}
Well
((b - (a + p) == 0) || (b - (a + p) > 1))
Would be better writen as:
(b - (a + p) >= 0)
Applying this to the whole string you get:
((a+p) <= b) && (a > 1) && (b >= p)) && (b - (a + p) >= 0)
(a + p) <= b is the same thing as b - (a + p) >= 0
So you can get rid of that leaving:
((a+p) <= b) && (a > 1) && (b >= p))
I added this as a comment to nickf's answer but thought I'd offer it up as an answer on it's own. The good answers all seem to be a variation of his, including mine. But since we're not depending on the compiler for optimization (if the OP were, we wouldn't even be doing this) then boiling this down from 3 ANDs to the following means that there will be values where only 2 of the 3 portions will need to be evaluated. And if this is being done in a script, it would make a difference as opposed to compiled code.
(a != 1) && ((b > (a + p + 1)) || (b == (a + p))))
Based on a comment, I'm going to add this wrt this being better than the AND version:
I guess it depends on whether your true results data set is larger than 50 percent of the input sets. The more often the input is true, the better my variation will be. So, with this equation, it looks like the AND style will be better (at least for my input data set of 0-500).
If a, b and p are positive integers (assuming that the positive range include the 0 value) then the expression (((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
can be reduced to ((a+p)<=b) && (a!=1) && ((b-(a+p))!=1)
Let me demonstrate it:
In the first part of the expression there is a condition, ((a+p)<=b),
that if valuated true render true the second part:
((b - (a + p) == 0) || (b - (a + p) > 1)). If it is true that (b >=(a+p)) then (b - (a+p)) have to be greater or equal to 0, we need to assure that (b-(a+p))!=1.
Put this term aside for awhile and go on.
Now we can concentrate our efforts on the the first part
(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b-(a+p))!=1)
If a is positive then it is always >=0 and so we can drop the test (a == 0 || a > 1) if favor of (a!=1) and reduce first part of the expression to (((a+p) <= b) && (b >= p) && (a!=1)).
For the next step of the reduction you can consider that if b >= (a+p) then, obviously b>=p (a is positive) and the expression can be reduced to
((a+p)<=b) && (a!=1) && ((b-(a+p))!=1)
how is about the following logic, please comment it:
((a == 0 || a > 1) && ((b-p) > 1) )
(((a+p) <= b) && (a == 0 || a > 1) &&
(b >= p)) && ((b - (a + p) == 0)
|| (b - (a + p) > 1))
1) (a == 0 || a > 1) is (a != 1)
2) (b >= p) is (b - p >= 0)
(a + p <= b) is (b - p >= a), which is stronger than (b - p >= 0).
First condition reduced to (a != 1) && (b - p >= a).
3) (b - (a + p) == 0) is (b - a - p == 0) is (b - p == a).
(b - (a + p) > 1) is (b - a - p > 1) is (b - p > 1 + a).
Since we had (b - p >= a) and we're using && operation, we may say that (b - p >= a) covers (b - p == a && b - p > 1 + a).
Hence, the whole condition will be reduced to
(a != 1 && (b - p >= a))
There's a tempation to reduce it further to (b >= p), but this reduction won't cover prohibition of b = p + 1, therefore (a != 1 && (b - p >= a)) is the condition.
This question has been pretty comfortably answered already in practice, but there is one point I mention below which I have not seen anyone else raise yet.
Since we were told to assume a >= 0, and the first condition assures that b - (a + p) >= 0, the bracketed || tests can be turned into tests against inequality with 1:
(a + p <= b) && (a != 1) && (b >= p) && (b - a - p != 1)
It is tempting to remove the check (b >= p), which would give nickf's expression. And this is almost certainly the correct practical solution. Unfortunately, we need to know more about the problem domain before being able to say if it is safe to do that.
For instance, if using C and 32-bit unsigned ints for the types of a, b, and p, consider the case where a = 2^31 + 7, p = 2^31 + 5, b = 13. We have a > 0, (a + p) = 12 < b, but b < p. (I'm using '^' to indicate exponentiation, not C bitwise xor.)
Probably your values will not approach the kind of ranges where this sort of overflow is an issue, but you should check this assumption. And if it turns out to be a possibility, add a comment with that expression explaining this so that some zealous future optimiser does not carelessly remove the (b >= p) test.
I feel (a != 1) && (a + p <= b) && (a + p != b - 1) is slightly more clear.
Another option is:
int t = b-p;
(a != 1 && a <= t && a != t-1)
Basically a is either 0, t, or lies between 2 and t-2 inclusive.
First iteration:
bool bool1 = ((a+p) <= b) && (a == 0 || a > 1) && (b >= p);
bool bool2 = (b - (a + p) == 0) || (b - (a + p) > 1);
return bool1 && bool2;
Second iteration:
int value1 = b - (a + p);
bool bool1 = (value1 >= 0) && (a == 0 || a > 1) && (b >= p);
bool bool2 = (value1 == 0) || (value1 > 1);
return bool1 && bool2;
Third iteration (all positives)
int value1 = b - (a + p);
bool bool1 = (value1 >= 0) && (a != 1) && (b >= p);
bool bool2 = (value1 == 0) || (value1 > 1);
return bool1 && bool2;
4th iteration (all positives)
int value2 = b - p;
int value1 = value2 - a;
bool bool1 = (value1 >= 0) && (a != 1) && (b - p >= 0);
bool bool2 = (value1 == 0) || (value1 > 1);
return bool1 && bool2;
5th iteration:
int value2 = b - p;
int value1 = value2 - a;
bool bool1 = (value1 >= 0) && (a != 1) && (value2 >= 0);
bool bool2 = (value1 == 0) || (value1 > 1);
return bool1 && bool2;
b >= (a+p) && a>=1
even b >= p is redundant as this will always be the case for a >= 1
Alright, I'm hoping that I did my math right here, but if I'm right, then this simplifies quite a bit. Granted it doesn't look the same in the end, but the core logic should be the same.
// Initial equation
(((a + p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
// ((a + p) <= b) iif a = 0 && p = b; therefore, b = p and a = 0 for this to work
(b == p) && ((b - (a + p) == 0) || (b - (a + p) > 1))
// Simplification, assuming that b = p and a = 0
(b == p) && (a == 0)
However, if we are operating under the assumption that zero is neither positive or negative then that implies that any value for a provided to the equation is going to be greater than or equal to one. This in turn means that the equation will always evaluate to false due to the fact that the following:
(a == 0 || a > 1)
Would only evaluate to true when a >= 2; however, if the following is also true:
(b >= p)
Then that means that p is at least equal to b, thus:
((a + p) <= b)
By substitution becomes:
((2 + b) <= b)
Which can clearly never evaluate to true.
a!=1 && ((b == a + p) || (b - p > a + 1))
(((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) || (b - (a + p) > 1))
since a >=0 (positive integers), the term (a == 0 || a > 1) is always true
if ((a+p) <= b) then (b >= p) is true when a,b,p are >=0
therefore ((a+p) <= b) && (a == 0 || a > 1) && (b >= p)) && ((b - (a + p) == 0) reduces to
b>=(a+p)
(b - (a + p) == 0) || (b - (a + p) > 1) is equivalent to b>=(a+p)
therefore the whole equation reduces to
**b>= (a+p)**

Resources