How can I find the maximum element in a set of numbers (nat) in Isabelle. The max function doesn't work, as it is only defined to take the maximum of two elements. I have an idea of how I could implement it using a reduce like function, but I don't know how to pick one random element from a set.
The function you are looking for is called Max. If you are looking for basic constants the guide What's in Main from the official Isabelle documentation is often useful. There is also the find_consts command which can be used to search for functions by type.
If you follow the definition of Max to theory Big_Operators in the main HOL library, you will see that it is defined like this:
Max = fold1 max
The combinator fold1 is your "reduce like function" that works on finite sets.
See also theory Finite_Set and its locale folding for the mathematical background that is required here to fold over arbitrary sets, instead of concrete lists.
Related
As I'm learning Julia, I am wondering how to properly do things I might have done in Python, Java or C++ before. For example, previously I might have used an abstract base class (or interface) to define a family of models through classes. Each class might then have a method like calculate. So to call it I might have model.calculate(), where the model is an object from one of the inheriting classes.
I get that Julia uses multiple dispatch to overload functions with different signatures such as calculate(model). The question I have is how to create different models. Do I use the type system for that and create different types like:
abstract type Model end
type BlackScholes <: Model end
type Heston <: Model end
where BlackScholes and Heston are different types of model? If so, then I can overload different calculate methods:
function calculate(model::BlackScholes)
# code
end
function calculate(model::Heston)
# code
end
But I'm not sure if this is a proper and idiomatic use of types in Julia. I will greatly appreciate your guidance!
This is a hard question to answer. Julia offers a wide range of tools to solve any given problem, and it would be hard for even a core developer of the language to assert that one particular approach is "right" or even "idiomatic".
For example, in the realm of simulating and solving stochastic differential equations, you could look at the approach taken by Chris Rackauckas (and many others) in the suite of packages under the JuliaDiffEq umbrella. However, many of these people are extremely experienced Julia coders, and what they do may be somewhat out of reach for less experienced Julia coders who just want to model something in a manner that is reasonably sensible and attainable for a mere mortal.
It is is possible that the only "right" answer to this question is to direct users to the Performance Tips section of the docs, and then assert that as long as you aren't violating any of the recommendations there, then what you are doing is probably okay.
I think the best way I can answer this question from my own personal experience is to provide an example of how I (a mere mortal) would approach the problem of simulating different Ito processes. It is actually not too far off what you have put in the question, although with one additional layer. To be clear, I make no claim that this is the "right" way to do things, merely that it is one approach that utilizes multiple dispatch and Julia's type system in a reasonably sensible fashion.
I start off with an abstract type, for nesting specific subtypes that represent specific models.
abstract type ItoProcess ; end
Now I define some specific model subtypes, e.g.
struct GeometricBrownianMotion <: ItoProcess
mu::Float64
sigma::Float64
end
struct Heston <: ItoProcess
mu::Float64
kappa::Float64
theta::Float64
xi::Float64
end
Note, in this case I don't need to add constructors that convert arguments to Float64, since Julia does this automatically, e.g. GeometricBrownianMotion(1, 2.0) will work out-of-the-box, as Julia will automatically convert 1 to 1.0 when constructing the type.
However, I might want to add some constructors for common parameterizations, e.g.
GeometricBrownianMotion() = GeometricBrownianMotion(0.0, 1.0)
I might also want some functions that return useful information about my models, e.g.
number_parameter(model::GeometricBrownianMotion) = 2
number_parameter(model::Heston) = 4
In fact, given how I've defined the models above, I could actually be a bit sneaky and define a method that works for all subtypes:
number_parameter(model::T) where {T<:ItoProcess} = length(fieldnames(typeof(model)))
Now I want to add some code that allows me to simulate my models:
function simulate(model::T, numobs::Int, stval) where {T<:ItoProcess}
# code here that is common to all subtypes of ItoProcess
simulate_inner(model, somethingelse)
# maybe more code that is common to all subtypes of ItoProcess
end
function simulate_inner(model::GeometricBrownianMotion, somethingelse)
# code here that is specific to GeometricBrownianMotion
end
function simulate_inner(model::Heston, somethingelse)
# code here that is specific to Heston
end
Note that I have used the abstract type to allow me to group all code that is common to all subtypes of ItoProcess in the simulate function. I then use multiple dispatch and simulate_inner to run any code that needs to be specific to a particular subtype of ItoProcess. For the aforementioned reasons, I hesitate to use the phrase "idiomatic", but let me instead say that the above is quite a common pattern in typical Julia code.
The one thing to be careful of in the above code is to ensure that the output type of the simulate function is type-stable, that is, the output type can be uniquely determined by the input types. Type stability is usually an important factor in ensuring performant Julia code. An easy way in this case to ensure type-stability is to always return Matrix{Float64} (if the output type is fixed for all subtypes of ItoProcess then obviously it is uniquely determined). I examine a case where the output type depends on input types below for my estimate example. Anyway, for simulate I might always return Matrix{Float64} since for GeometricBrownianMotion I only need one column, but for Heston I will need two (the first for price of the asset, the second for the volatility process).
In fact, depending on how the code is used, type-stability is not always necessary for performant code (see eg using function barriers to prevent type-instability from flowing through to other parts of your program), but it is a good habit to be in (for Julia code).
I might also want routines to estimate these models. Again, I can follow the same approach (but with a small twist):
function estimate(modeltype::Type{T}, data)::T where {T<:ItoProcess}
# again, code common to all subtypes of ItoProcess
estimate_inner(modeltype, data)
# more common code
return T(some stuff generated from function that can be used to construct T)
end
function estimate_inner(modeltype::Type{GeometricBrownianMotion}, data)
# code specific to GeometricBrownianMotion
end
function estimate_inner(modeltype::Type{Heston}, data)
# code specific to Heston
end
There are a few differences from the simulate case. Instead of inputting an instance of GeometricBrownianMotion or Heston, I instead input the type itself. This is because I don't actually need an instance of the type with defined values for the fields. In fact, the values of those fields is the very thing I am attempting to estimate! But I still want to use multiple dispatch, hence the ::Type{T} construct. Note also I have specified an output type for estimate. This output type is dependent on the ::Type{T} input, and so the function is type-stable (output type can be uniquely determined by input types). But common with the simulate case, I have structured the code so that code that is common to all subtypes of ItoProcess only needs to be written once, and code that is specific to the subtypes is separted out.
This answer is turning into an essay, so I should tie it off here. Hopefully this is useful to the OP, as well as anyone else getting into Julia. I just want to finish by emphasizing that what I have done above is only one approach, there are others that will be just as performant, but I have personally found the above to be useful from a structural perspective, as well as reasonably common across the Julia ecosystem.
I am not familiar with sage,(I dont know anythink about it) but I have very basic question. I need the generators of primitive group(15,2) for my reaserch., could anyone give me the generators of primitive group(15,2) ,with using Sage? I would be appreciate
You must be referring to The primitive group from the GAP tables of primitive groups. Interestingly, it's not clear to me whether these are in exact correspondence with "primitive permutation groups", though I assume they are.
Anyway, since you are using that notation, I assume that this will do it for you:
sage: P = PrimitiveGroup(15,2)
sage: P.gens()
[(1,4,5)(2,8,10)(3,12,15)(6,13,11)(7,9,14), (1,15,7,5,12)(2,9,13,14,8)(3,6,10,11,4)]
Note that although P apparently is isomorphic to the alternating group on six elements, nonetheless it appears (as you probably wish) as a permutation group on 15 elements.
I am trying to compute two finite sets of some enumerable type (let's say char) using a least- and greatest- fixpoint computation, respectively. I want my definitions to be extractable to SML, and to be "semi-efficient" when executed. What are my options?
From exploring the HOL library and playing around with code generation, I have the following observations:
I could use the complete_lattice.lfp and complete_lattice.gfp constants with a pair of additional monotone functions to compute my sets, which in fact I currently am doing. Code generation does work with these constants, but the code produced is horribly inefficient, and if I understand the generated SML code correctly is performing an exhaustive search over every possible set in the powerset of characters. Any use, no matter how simple, of these two constants at type char therefore causes a divergence when executed.
I could try to make use of the iterative fixpoint described by the Kleene fixpoint theorem in directed complete partial orders. From exploring, there's a ccpo_class.fixp constant in the theory Complete_Partial_Order, but the underlying iterates constant that this is defined in terms of has no associated code equations, and so code cannot be extracted.
Are there any existing fixpoint combinators hiding somewhere, suitable for use with finite sets, that produce semi-efficient code with code generation that I have missed?
None of the general fixpoint combinators in Isabelle's standard library is meant to used directly for code extraction because their construction is too general to be usable in practice. (There is another one in the theory ~~/src/HOL/Library/Bourbaki_Witt_Fixpoint.) But the theory ~~/src/HOL/Library/While_Combinator connects the lfp and gfp fixpoints to the iterative implementation you are looking for, see theorems lfp_while_lattice and gfp_while_lattice. These characterisations have the precondition that the function is monotone, so they cannot be used as code equations directly. So you have two options:
Use the while combinator instead of lfp/gfp in your code equations and/or definitions.
Tell the code preprocessor to use lfp_while_lattice as a [code_unfold] equation. This works if you also add all the rules that the preprocessor needs to prove the assumptions of these equations for the instances at which it should apply. Hence, I recommend that you also add as [code_unfold] the monotonicity statement of your function and the theorem to prove the finiteness of char set, i.e., finite_class.finite.
I have confusion. Semantically we can construct 2^(2^n) boolean functions, but I read in Digital Electronics Morris Mano that we can construct 2^2n combinations of minterm/maxterm. How?
Samsamp, could you point to a specific place in the book or even better provide an exact quote? In the copy I found over the Internet I was not able to find such a claim after a fast glance over. The closest thing I found is:
Since the function can be either I or 0 for each minterm, and since there
are 2^n min terms, one can calculate the possible functions that can be formed with n variables to be 2^2^n.
which looks OK to me.
While I was reading about lambda calculus, came across the word Lambda definability. Can someone please explain what that is as I couldn't find any good resources on that.
Thanks
More generally, there is a line of research seeking to characterize "lambda definability" over a broad class of languages. "lambda definability" itself is typically relative to a semantics of a language given in terms of sets. For a type T in our language, write |T| for its interpretation as a set. Now, take an element of |T| -- call it e. We want to know if there is a term in our language -- call it x : T (x of type T), such that |x| is e. If there is such a term, then we say that t is lambda-definable.
Now, in our perfect world, when we interpret a language into sets, we would like to say that the sets associated with each type are precisely those that contain the lambda-definable elements of that type and only the lambda-definable elements (completeness). It would also be nice, perhaps to say that we can provide an algorithm to determine if a claimed element of a set has an associated lambda term (decidability).
Now, often we don't just model into sets, but into other funny mathematical constructions. And we don't model just from the lambda calculus, but from other related systems such as Plotkin's PCF or the like. But the property under study is typically still called "lambda-definability".
After decades of research there are still many open problems and questions in this regard -- while certain lower-order terms have been shown to have decidable lambda-definability (the classic results involve terms up to second-order), many terms do not yield so easily. This paper ("The Undecidability of lambda-Definability" by Ralph Loader) gives an important such undecidability result and characterizes some consequences: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.36.6860
See the Church-Turing thesis, where lambda-definable functions (from Church) are those that give us "effectively computable" functions. Turing showed that programs implementable on a Turing machine are equivalent to lambda-definable functions.