Referencing current assumptions in Isabelle - isabelle

When I have a lot of assumptions, sometimes I end up with a lot of temporary names that clutter the proof.
I'm talking about things like this:
lemma foo: ...
proof
assume P: ... and Q: ... and R: ...
then have ...
then have ... using P ...
then have ... using P R ...
then show ...
proof
assume A: ... and B: ... and C: ...
then have ...
then have ... using B C ...
...
and can you imagine how that evolves. A lot of names for statements that, in the grand scheme of things, are not worthy of naming, but are named nonetheless because we need to reference them some lines later.
If we used all current assumptions on the other hand, the superfluous names wouldn't clutter the proof:
lemma foo: ...
proof
assume ... and ... and ...
then have ...
then have ... using assumptions ...
then have ... using assumptions ...
then show ...
proof
assume ... and ... and ...
then have ...
then have ... using assumptions ...
...
Of course, using assumptions is not a valid statement in Isabelle. I know about assms, which references the assumes clause, but I don't know if there exists such a thing for assume.
Is there a way to reference the all current assumptions created by assume?

In case you really need it...
If all you want are the last assumptions that you made (and not all of them), you can simulate the effect presented by using a name convention (e.g. assumptions or assmps) and bundling the assumptions together (i.e using ""..." "..." "..."" instead of ""..." and "..." and "...""):
lemma foo: ...
proof
assume assumptions: "..." "..." "..."
then have ...
then have ... using assumptions ...
then have ... using assumptions ...
then show ...
proof
assume assumptions: "..." "..." "..."
then have ...
then have ... using assumptions ...
...
In the example above, the second assume assumptions shadows the first one, so if you always name your assumptions "assumptions" (or whatever naming convention you prefer), then using assumptions will always refer to the last set of assumptions.
Notice that once you close a subproof with qed, any assume assumptions in the current scope is forgot, so as expected, you can continue using it the previous assumptions after you finish the subproof.
The downside of this method is that, since every new name shadows the rest, only your most recent assumptions in the scope are accessible, which may be a problem if you intend to use any assumptions made before the most recent ones.
... but you probably don't need it.
Although you can use that, Isabelle has other constructs that may solve the same problem in a better way, depending on the situation. Here's some useful tools to keep in mind:
You can bundle assumptions together by using assume A: "..." "..." "...", without and
You can accumulate statements with moreover ... ultimately ...
You can derive multiple statements in one shot with have ... and ... and ... by ...
If your assumptions are at lemma level, you can use lemma foo: assumes ... shows ... and they will be available to you as assms
You can directly quote previous facts with ‹...›
Using 1. already vastly reduces the clutter:
lemma foo: ...
proof
assume A: "..." "..." "..."
then have ...
then have ... using A ...
then have ... using A ...
then show ...
proof
assume B: "..." "..." "..."
then have ...
then have ... using B ...
...
Alternatively, using 2. and 3. you can format it as such:
lemma foo: ...
proof
assume "..." "..." "..."
moreover from calculation have ...
moreover from calculation have ...
ultimately have ...
then show ...
proof
assume "..." "..." "..."
moreover from this have ...
ultimately have ... and ...
...
Or alternatively, using 4. and 5.:
lemma foo:
assumes: "..." "..." "..."
shows: ...
proof
have ... using assms ...
then have ... using assms ...
then have ... using assms ...
then show ...
proof
assume "..." "..." "..."
then have ...
then have ... using ‹...› ‹...› ...

Related

zsh accepts syntactically incorrect loop construct

By mistake, I typed something like this:
for f in a b; echo a; echo x
The output produced was
a
a
x
as if I had written
for f in a b; do echo a; done; echo x
Could someone explain, why my code produced this example? Checking the man page, it clearly says that the required syntax has to be
for name ... [ in word ... ] term do list done
No shortcut explains that I could leave out the do or done.
I'm running zsh 5.8
Somewhat confusingly, that syntax is not described in the section that introduces the for loop. Instead it's listed with some other short command versions, in a separate part of the zshmisc man page titled ALTERNATE FORMS FOR COMPLEX COMMANDS.
for name ... [ in word ... ] term sublist
where term is at least one newline or ;. Another short form of for.
The introduction to the section mentions some caveats:
Many of zsh's complex commands have alternate forms. These
are non-standard and are likely not to be obvious even to seasoned
shell programmers; they should not be used anywhere that portability
of shell code is a concern.
The short versions below only work if sublist is of the form `{ list
}' or if the SHORT_LOOPS option is set.

Python 3.7 nested dataclass mypy type check error

#dataclass
class A:
one: int = 0
two: str = ""
#nested_dataclass
class B:
three: A
four: str
#nested_dataclass
class C:
five: B
six: str
obj = C(five={"three":{"one": 23, "two":"narf"}, "four": "zort"}, six="fnord")
print(obj.five.three.two)
This code is correct according to functionality I guess. But, when I run mypy src --ignore-missing-imports, I get the following error:
run.py:50: error: Unexpected keyword argument "five" for "C"
run.py:50: error: Unexpected keyword argument "six" for "C"
Would be lot helpful if someone would help me overcome this. Thanks
Mypy has no idea what a nested_dataclass is -- it doesn't appear to be a decorator that's a standard part of the dataclasses module.
Consequently, mypy won't be able to understand whatever special logic is happening when you try instantiating C. As far as mypy is concerned, C is a regular old class -- and has no constructor.
The two possible solutions you have are to:
Just use #dataclass and drop whatever custom logic you're using.
Write a plugin for mypy that can understand the #nested_dataclass decorator. You can get some examples of what this looks like by looking at the dataclasses plugin that comes baked into mypy.

Divides in function, but doesn't outside. Python 3.4

I have a somewhat weird issue. I'm supposed to take an inputted number, and if it's even divide it until it's odd. But. The code works inside the function, and the while loop, but it doesn't work when I try to return that value. It literally just returns the inputted value.
Code for reference:
num = int(input("Enter a number."))
def makeodd(num):
while num % 2 == 0:
num = num / 2
print(num)
return num
makeodd(num)
print(num)
I apologize that this is a bit basic. I'm looking for more of an explanation then a real solution. Although a solution would be nice. This is python 3.4 for reference. I looked around but couldn't actually find anything that was like this.
Change makeodd(num) to:
num = makeodd(num)
That puts the return value into num.
You could also use the return value directly in the print statement:
print(makeodd(num))

Find the source file containing R function definition

I come from a python background and am trying to get up to speed with R, so please bear with me
I have an R file - util.R with the following lines:
util.add <- function(a,b) a + b
util.sub <- function(a,b) { a - b }
I source it as follows:
source('path/util.R')
I now have two function objects and want to write a function as follows:
getFilePath(util.add)
that would give me this result
[1] "path/util.R"
Digging into the srcref attribute of one of the loaded functions appears to work, if you go deep enough ...
source("tmp/tmpsrc.R")
str(util.add)
## function (a, b)
## - attr(*, "srcref")=Class 'srcref' atomic [1:8] 1 13 1 31 13 31 1 1
## .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment: 0x8fffb18>
srcfile <- attr(attr(util.add,"srcref"),"srcfile")
ls(srcfile)
## [1] "Enc" "filename" "fixedNewlines" "isFile"
## [5] "lines" "parseData" "timestamp" "wd"
srcfile$filename
## [1] "tmp/tmpsrc.R"
I know this was solved years ago, but I've just come across it and realised that there is a bit more to this if you use the body() function.
The raw function has only the one attribute, "srcref" which contains the code of the function, along with it's own attributes and class of "srcref" (which dictates how it'll get printed).
The body() of a function, such as body(util.add) has three attributes.
"srcref" which contains the body of the function stored as a list of expressions.
"srcfile" which contains the source file of the function (which is what you are looking for in this question)
"wholeSrcref" which points to the entire source file.
This gives you an alternative (although slightly slower) method to extract the source file name attr(body(util.add),"srcfile"), along with being able to see (although not interact with) the sibling functions (i.e. the other functions loaded in the same source file).
Not sure if it's useful, but it could be interesting.
Let's also not forget about the %#% infix operator for accessing attributes using the {purrr} package, with this we could use the more succinct (although again, slower) piece of code as:
util.add%#%srcref%#%srcfile

Using type classes to overload notation for constructors (now a namespace issue)

This is a derivative question of Existing constants (e.g. constructors) in type class instantiations.
The short question is this: How can I prevent the error that occurs due to free_constructors, so that I can combine the two theories that I include below.
I've been sitting on this for months. The other question helped me move forward (it appears). Thanks to the person who deserves thanks.
The real issue here is about overloading notation, though it looks like I now just have a namespace problem.
At this point, it's not a necessity, just an inconvenience that two theories have to be used. If the system allows, all this will disappear, but I ask anyway to make it possible to get a little extra information.
The big explanation here comes in explaining the motivation, which may lead to getting some extra information. I explain some, then include S1.thy, make a few comments, and then include S2.thy.
Motivation: using syntactic type classes for overloading notation of multiple binary datatypes
The basic idea is that I might have 5 different forms of binary words that have been defined with datatype, and I want to define some binary and hexadecimal notation that's overloaded for all 5 types.
I don't know what all is possible, but the past tells me (by others telling me things) that if I want code generation, then I should use type classes, to get the magic that comes with type classes.
The first theory, S1
Next is the theory S1.thy. What I do is instantiate bool for the type classes zero and one, and then use free_constructors to set up the notation 0 and 1 for use as the bool constructors True and False. It seems to work. This in itself is something I specifically wanted, but didn't know how to do.
I then try to do the same thing with an example datatype, BitA. It doesn't work because constant case_BitA is created when BitA is defined with datatype. It causes a conflict.
Further comments of mine are in the THY.
theory S1
imports Complex_Main
begin
declare[[show_sorts]]
(*---EXAMPLE, NAT 0: IT CAN BE USED AS A CONSTRUCTOR.--------------------*)
fun foo_nat :: "nat => nat" where
"foo_nat 0 = 0"
(*---SETTING UP BOOL TRUE & FALSE AS 0 AND 1.----------------------------*)
(*
I guess it works, because 'free_constructors' was used for 'bool' in
Product_Type.thy, instead of in this theory, like I try to do with 'BitA'.
*)
instantiation bool :: "{zero,one}"
begin
definition "zero_bool = False"
definition "one_bool = True"
instance ..
end
(*Non-constructor pattern error at this point.*)
fun foo1_bool :: "bool => bool" where
"foo1_bool 0 = False"
find_consts name: "case_bool"
free_constructors case_bool for "0::bool" | "1::bool"
by(auto simp add: zero_bool_def one_bool_def)
find_consts name: "case_bool"
(*found 2 constant(s):
Product_Type.bool.case_bool :: "'a∷type => 'a∷type => bool => 'a∷type"
S1.bool.case_bool :: "'a∷type => 'a∷type => bool => 'a∷type" *)
fun foo2_bool :: "bool => bool" where
"foo2_bool 0 = False"
|"foo2_bool 1 = True"
thm foo2_bool.simps
(*---TRYING TO WORK A DATATYPE LIKE I DID WITH BOOL.---------------------*)
(*
There will be 'S1.BitA.case_BitA', so I can't do it here.
*)
datatype BitA = A0 | A1
instantiation BitA :: "{zero,one}"
begin
definition "0 = A0"
definition "1 = A1"
instance ..
end
find_consts name: "case_BitA"
(*---ERROR NEXT: because there's already S1.BitA.case_BitA.---*)
free_constructors case_BitA for "0::BitA" | "1::BitA"
(*ERROR: Duplicate constant declaration "S1.BitA.case_BitA" vs.
"S1.BitA.case_BitA" *)
end
The second theory, S2
It seems that case_BitA is necessary for free_constructors to set things up, and it occurred to me that maybe I could get it to work by using datatype in one theory, and use free_constructors in another theory.
It seems to work. Is there a way I can combine these two theories?
theory S2
imports S1
begin
(*---HERE'S THE WORKAROUND. IT WORKS BECAUSE BitA IS IN S1.THY.----------*)
(*
I end up with 'S1.BitA.case_BitA' and 'S2.BitA.case_BitA'.
*)
declare[[show_sorts]]
find_consts name: "BitA"
free_constructors case_BitA for "0::BitA" | "1::BitA"
unfolding zero_BitA_def one_BitA_def
using BitA.exhaust
by(auto)
find_consts name: "BitA"
fun foo_BitA :: "BitA => BitA" where
"foo_BitA 0 = A0"
|"foo_BitA 1 = A1"
thm foo_BitA.simps
end
The command free_constructors always creates a new constant of the given name for the case expression and names the generated theorems in the same way as datatype does, because datatype internaly calls free_constructors.
Thus, you have to issue the command free_constructors in a context that changes the name space. For example, use a locale:
locale BitA_locale begin
free_constructors case_BitA for "0::BitA" | "1::BitA" ...
end
interpretation BitA!: BitA_locale .
After that, you can use both A0 and A1 as constructors in pattern matching equations and 0 and 1, but you should not mix them in a single equation. Yet, A0 and 0 are still different constants to Isabelle. This means that you may have to manually convert the one into the other during proofs and code generation works only for one of them. You would have to set up the code generator to replace A0 with 0 and A1 with 1 (or vice versa) in the code equations. To that end, you want to declare the equations A0 = 0 and A1 = 1 as [code_unfold], but you also probably want to write your own preprocessor function in ML that replaces A0 and A1 in left-hand sides of code equations, see the code generator tutorial for details.
Note that if BitA was a polymorphic datatype, packages such as BNF and lifting would continue to use the old set of constructors.
Given these problems, I would really go for the manual definition of the type as described in my answer to another question. This saves you a lot of potential issues later on. Also, if you are really only interested in notation, you might want to consider adhoc_overloading. It works perfectly well with code generation and is more flexible than type classes. However, you cannot talk about the overloaded notation abstractly, i.e., every occurrence of the overloaded constant must be disambiguated to a single use case. In terms of proving, this should not be a restriction, as you assume nothing about the overloaded constant. In terms of definitions over the abstract notation, you would have to repeat the overloading there as well (or abstract over the overloaded definitions in a locale and interpret the locale several times).

Resources