conda
, pip
, docker
oder pipenv
Python
und pip
installierenpip
= package manager für Python, damit installiert man neue nicht Standard-PackagesIJulia
Package installieren, mehr dazu hierMarkdown = der einfachste Weg zur Textformatierung
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6
**bold**
*italics*
- unordered list
- unordered list
- unordered sublist
- unordered sublist
---
> blackquote
1. ordered list
2. ordered list
blackquote
Here is some `inline code`.
A codeblock
```Julia
for i in 1:10
println(i)
end
```
Here is a inline equation $x=5^{23}$ using $\LaTeX$.
Here is a url [my link](www.mylink.com).
Here is some inline code
.
A codeblock
for i in 1:10
println(i)
end
Here is a inline equation $x=5^{23}$ using $\LaTeX$.
Here is a url my link.
Int64
, Float64
etc.square(x::Number) = x^2
funktioniert für Int64, Int32, Float64 etc.?
;
julia
als Befehl aufrufen möchte# an immutable struct - a composit type
struct Poly{T}
# Vector{T} is an alias for Array{T,1},
# all elements have the same Type T, it is 1 dimensional
coeff::Vector{T}
# inner constructor - Julia creates a simple one by default
function Poly(coeff::Vector{T}) where T
# remove zeros from the end of coeff
new{T}(removeTrailingZeros(coeff))
end
end
# outer constructor - convience methods for object creation
# variable number of arguments
function Poly(coeff::T...) where T
# coeff is a tuple, we need to convert it to Vector{T} i.e. Array{T,1}
Poly(collect(coeff))
end
Poly
# a generic function
function removeTrailingZeros(coeff::Vector{T}) where T
if isempty(coeff)
return Vector{T}()
end
i = 0
while coeff[(end - i)] == zero(T)
i += 1
# the array is full of zeros
if i == lastindex(coeff)
return Vector{T}()
end
end
# the last evalueated statement is returned
coeff[1:end - i]
end
removeTrailingZeros (generic function with 1 method)
# Polynomials of the same parametric type Int64 in global scope
# call inner constructor
p = Poly([1,2])
Poly{Int64}([1, 2])
# call outer constructor
q = Poly(2,4,3)
r = Poly(0,1)
Poly{Int64}([0, 1])
# show info about some object
dump(q)
Poly{Int64} coeff: Array{Int64}((3,)) [2, 4, 3]
# show macro, with `;` suppress the output of the cell
@show s = Poly(1,1,0,0,0);
s = Poly(1, 1, 0, 0, 0) = Poly{Int64}([1, 1])
# dot syntax to access members
s.coeff
2-element Array{Int64,1}: 1 1
Poly(0,0,0,0)
Poly{Int64}(Int64[])
# print the type of an object
typeof(s)
Poly{Int64}
# make it behave as an array
# overloading - Multiple dispatch chooses the right method to use
import Base.getindex
# The syntax a[i,j,...] is converted by the compiler to getindex(a, i, j, ...)
function getindex(p::Poly{T}, i::Int) where T
if i <= length(p)
return p.coeff[i]
else
# custom zero based on the type T
return zero(T)
end
end
import Base.length
# overload length
function length(p::Poly{T}) where T
length(p.coeff)
end
length (generic function with 86 methods)
import Base.lastindex
# now we can use p[end]
function lastindex(p::Poly{T}) where T
length(p)
end
import Base.iszero
# check if zero poly
function iszero(p::Poly{T}) where T
isempty(p.coeff)
end
iszero (generic function with 16 methods)
@show q
q[1], q[2], q[end], q[end-1], q[200], typeof(q), length(q), iszero(q)
q = Poly{Int64}([2, 4, 3])
(2, 4, 3, 4, 0, Poly{Int64}, 3, false)
import Base.==
# we removed trailing zeros from coeff at init, OK
function ==(p::Poly{T}, q::Poly{T}) where T
p.coeff == q.coeff
end
== (generic function with 157 methods)
import Base.+
function +(p::Poly{T}, q::Poly{T}) where T
# Arr. comprehension - create math. like arrays, we use the inner constructor and range 1:X (iterable)
Poly([p[i] + q[i] for i in 1:max(length(p), length(q))])
end
import Base.-
# define inverse elements
function -(p::Poly{T}) where T
Poly(- p.coeff)
end
function -(p::Poly{T}, q::Poly{T}) where T
p + (-q)
end
- (generic function with 176 methods)
# overload the zero and one function for polynomials
import Base.zero, Base.one
# additive identity element for the type of x, zero(x)
# define function with f(x) = ...
# var name left out, important is to know T, dispatch on type
zero(::Type{Poly{T}}) where T = Poly(Vector{T}())
one(::Type{Poly{T}}) where T = Poly([one(T)])
one (generic function with 18 methods)
zero(Poly{Float64}), one(Poly{Float64}), one(Poly{Int64})
(Poly{Float64}(Float64[]), Poly{Float64}([1.0]), Poly{Int64}([1]))
import Base.*
# mult. polynoms of the same type (!)
function *(p::Poly{T}, q::Poly{T}) where T
# p or q is a zero polynomial => p*q = zero poly.
if iszero(p) || iszero(q)
return zero(Poly{T})
else
# Vector of type T with the right length
newCoeff = Vector{T}(undef, length(p) + length(q) - 1)
for i in 1:length(newCoeff)
newCoeff[i] = sum([ p[j] * q[i-j + 1] for j in 1:i])
end
return Poly(newCoeff)
end
end
* (generic function with 358 methods)
# a small test of our implementation
# properties of a commutative group
# associative +
@show (p + q) + r == p + (q + r)
# defining property of the identity element wrt +
@show zero(Poly{Int64}) + p == p
# defining property of an inverse element wrt +
@show (-p) + p == zero(Poly{Int64})
# commutative +
@show p + q == q + p;
(p + q) + r == p + (q + r) = true zero(Poly{Int64}) + p == p = true -p + p == zero(Poly{Int64}) = true p + q == q + p = true
# further properties of a commutative ring
# associative *
@show (p*q)*r == p*(q*r)
# defining property of the neutral element wrt *
@show one(Poly{Int64}) * p == p * one(Poly{Int64}) == p
# distributive property
@show p*(q + r) == p * q + p * r
# commutative *
@show p * q == q * p
# logical consequences
@show zero(Poly{Int64}) * p == zero(Poly{Int64})
@show (-p) * q == p * (-q) == -(p*q);
(p * q) * r == p * (q * r) = true one(Poly{Int64}) * p == p * one(Poly{Int64}) == p = true p * (q + r) == p * q + p * r = true p * q == q * p = true zero(Poly{Int64}) * p == zero(Poly{Int64}) = true -p * q == p * -q == -(p * q) = true
# Yay a polynomial ring over "Z" (well not quite Z but ok..)
(p * q + r * s ) * (p - q * r) + zero(typeof(s)) - p * one(typeof(p))
Poly{Int64}([1, 7, 4, -36, -75, -60, -18])
# pretty printing for Poly
import Base.show
# When you print an object, Julia invokes the show function
function show(io::IO, p::Poly{T}) where T
# get type with typeof(x)
if iszero(p)
print(io, "0" )
elseif length(p) == 1
print(io, "(", repr( p[1]), ")")
else
print(io, "(", repr( p[1]), ") +")
for i in 2:(length(p) - 1)
# use string interpolation as in Perl using $
print(io, " (", repr(p[i]), ")", "x^$(i - 1) +" )
end
print(io, " (", repr(p[length(p)]), ")", "x^$(length(p) - 1)" )
end
end
show (generic function with 234 methods)
@show u = Poly(1,2,3);
u = Poly(1, 2, 3) = (1) + (2)x^1 + (3)x^2
q
(2) + (4)x^1 + (3)x^2
# callable struct - functions are just callables
# evaluate at x
# with * between T and N we promote them to a common "greater" type
# we can evaluate an Int64 poly at Float64 value
function (p::Poly{T})(x::N) where {T, N}
if iszero(p)
return zero(x)
else
# a dot product of transposed coeff and x^i
# one coud also use LinearAlgebra.dot as ⋅ (\cdot<tab>)
p.coeff' * [x^(i) for i in 0:(length(p)-1)]
end
end
@show u;
u = (1) + (2)x^1 + (3)x^2
# full support for unicode characters (\Gamma<tab> for Γ etc.)
# use ∘ (\circ<tab>) for function composition
u(0), u(1), u(0.5), p(q(s(π))), (p ∘ q ∘ s)(π)
(1, 6, 2.75, 141.04947947833202, 141.04947947833202)
# multiple dispatch checks the function definition (signature),
# we could provide "promotion rules" to convert to common type
Poly(1,2) * Poly(1.1,1.2)
MethodError: no method matching *(::Poly{Int64}, ::Poly{Float64}) Closest candidates are: *(::Any, ::Any, !Matched::Any, !Matched::Any...) at operators.jl:529 *(::Poly{T}, !Matched::Poly{T}) where T at In[17]:5 Stacktrace: [1] top-level scope at In[27]:1
# how about a 2x2 matrix ring over a polynomial ring ???
A = [p s; p s]
B = [s p; r q]
# *, + are for Matrix type defined by default
X = A * B + B
2×2 Array{Poly{Int64},2}: (2) + (5)x^1 + (3)x^2 (4) + (12)x^1 + (11)x^2 + (3)x^3 (1) + (5)x^1 + (3)x^2 (5) + (14)x^1 + (14)x^2 + (3)x^3
# broadcasting
f(x) = x^2
f.([1,2,3])
3-element Array{Int64,1}: 1 4 9
# basic math functions are included
sin.([-π, 1/6 * π])
2-element Array{Float64,1}: -1.2246467991473532e-16 0.49999999999999994
# a callable polynomial u
# transpose with a sigle quote
u.([1,2,3,4])'
1×4 LinearAlgebra.Adjoint{Int64,Array{Int64,1}}: 6 17 34 57
# defined only for T subtype Number
function doubleCoeff(p::Poly{T}) where T <: Number
Poly( 2 * p.coeff)
end
doubleCoeff (generic function with 1 method)
doubleCoeff(Poly(1,2,3))
(2) + (4)x^1 + (6)x^2
@which 2 * p.coeff
X
2×2 Array{Poly{Int64},2}: (2) + (5)x^1 + (3)x^2 (4) + (12)x^1 + (11)x^2 + (3)x^3 (1) + (5)x^1 + (3)x^2 (5) + (14)x^1 + (14)x^2 + (3)x^3
# broadcast across more dimensions
doubleCoeff.(X)
2×2 Array{Poly{Int64},2}: (4) + (10)x^1 + (6)x^2 (8) + (24)x^1 + (22)x^2 + (6)x^3 (2) + (10)x^1 + (6)x^2 (10) + (28)x^1 + (28)x^2 + (6)x^3
# most operators are just functions with support for special syntax
2 .* [1,2,3]
3-element Array{Int64,1}: 2 4 6
# How about a scalar multiplication??
# Can we generalize doubleCoeff ??
# use dot syntax to access memebers of a module
# define behaviour for Poly when broadcasted
# -> behave as a scalar do not broatcast any further
Base.broadcastable(x::Poly{T}) where T = Ref(x)
# overload *
function *(s::T, p::Poly{T}) where T
# beautiful syntax using .
Poly(s .* p.coeff)
end
* (generic function with 359 methods)
# and how about a polynomial ring over a polynomial ring ???
# p,q,r,s are Poly over "Z", now used as coeff.
τ = Poly(p,q,r,s)
μ = Poly(p, p, r)
ν = Poly(q,r)
ρ = τ * μ + ν - μ + one(typeof(ν))
((3) + (6)x^1 + (7)x^2) + ((2) + (11)x^1 + (15)x^2 + (6)x^3)x^1 + ((2) + (9)x^1 + (15)x^2 + (6)x^3)x^2 + ((1) + (6)x^1 + (8)x^2 + (3)x^3)x^3 + ((1) + (3)x^1 + (3)x^2)x^4 + ((0) + (1)x^1 + (1)x^2)x^5
# scalar mulitplication
@show μ
@show μ == Poly(1) * μ
# "mult. by the scalar g(x)=x" ≡ "mult. by Poly(0,1)"
@show Poly(0,1) * μ;
μ = ((1) + (2)x^1) + ((1) + (2)x^1)x^1 + ((0) + (1)x^1)x^2 μ == Poly(1) * μ = true Poly(0, 1) * μ = ((0) + (1)x^1 + (2)x^2) + ((0) + (1)x^1 + (2)x^2)x^1 + ((0) + (0)x^1 + (1)x^2)x^2
@show p
@show p * μ;
p = (1) + (2)x^1 p * μ = ((1) + (4)x^1 + (4)x^2) + ((1) + (4)x^1 + (4)x^2)x^1 + ((0) + (1)x^1 + (2)x^2)x^2
# Can we call evaluate our polynomial over a polynomial at some polynomial ????
# overwrite / define new behavior for Poly{T}
# what is Poly{T}^n ??
# Integer is an abstract type that includes Int64, Int32 etc.
import Base.^
function ^(p::Poly{T}, n::Integer) where T
# we may get an error here..
un = Unsigned(n)
# we assume at this point one(T) has an implentation
res = Poly(one(T))
for i in 1:n
res *= p
end
res
end
import LinearAlgebra
LinearAlgebra.dot(p::Poly{N},q::Poly{N}) where N = p * q
zero(p::Poly{N}) where N = zero(Poly{N})
zero (generic function with 18 methods)
@show μ
@show q
@show μ(q)
@show μ(q) == μ[1] + μ[2] * q + μ[3] * q^2;
μ = ((1) + (2)x^1) + ((1) + (2)x^1)x^1 + ((0) + (1)x^1)x^2 q = (2) + (4)x^1 + (3)x^2 μ(q) = (3) + (14)x^1 + (27)x^2 + (34)x^3 + (24)x^4 + (9)x^5 μ(q) == μ[1] + μ[2] * q + μ[3] * q ^ 2 = true
using Plots;
@show q
interval = -10:0.1:10
plot(interval, q.(interval), label="q")
q = (2) + (4)x^1 + (3)x^2