diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 0000000..9ca65c1
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,18 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "fantomas": {
+ "version": "6.3.15",
+ "commands": [
+ "fantomas"
+ ]
+ },
+ "dotnet-fsharplint": {
+ "version": "0.24.2",
+ "commands": [
+ "dotnet-fsharplint"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 217f7cb..2527e17 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -5,9 +5,7 @@ name: .NET
on:
push:
- branches: [ "main" ]
pull_request:
- branches: [ "main" ]
jobs:
build:
diff --git a/Lectures.sln b/Lectures.sln
index 1b8fc08..983bd57 100644
--- a/Lectures.sln
+++ b/Lectures.sln
@@ -11,6 +11,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{1C9B3502-1
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Tests", "test\Tests\Tests.fsproj", "{DB1BB7B2-4207-4F77-A40E-CE98C7C13A51}"
EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Benchmarks", "benchmarks\Benchmarks.fsproj", "{FF096F73-CAD8-4733-A1B9-C306629C637A}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ImageProcessing", "src\ImageProcessing\ImageProcessing.fsproj", "{DA2F7A21-E6CF-43FA-BFB3-922A8B57B76B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -28,9 +32,18 @@ Global
{DB1BB7B2-4207-4F77-A40E-CE98C7C13A51}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB1BB7B2-4207-4F77-A40E-CE98C7C13A51}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB1BB7B2-4207-4F77-A40E-CE98C7C13A51}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FF096F73-CAD8-4733-A1B9-C306629C637A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FF096F73-CAD8-4733-A1B9-C306629C637A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FF096F73-CAD8-4733-A1B9-C306629C637A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FF096F73-CAD8-4733-A1B9-C306629C637A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DA2F7A21-E6CF-43FA-BFB3-922A8B57B76B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DA2F7A21-E6CF-43FA-BFB3-922A8B57B76B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DA2F7A21-E6CF-43FA-BFB3-922A8B57B76B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DA2F7A21-E6CF-43FA-BFB3-922A8B57B76B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{DCC7AC6B-CA90-4890-B8AB-45BF39157AB2} = {0C857B10-C523-4833-B3FF-6D3A9A7A2099}
{DB1BB7B2-4207-4F77-A40E-CE98C7C13A51} = {1C9B3502-1FB1-452A-B5E7-4951A0D52C86}
+ {DA2F7A21-E6CF-43FA-BFB3-922A8B57B76B} = {0C857B10-C523-4833-B3FF-6D3A9A7A2099}
EndGlobalSection
EndGlobal
diff --git a/benchmarks/Benchmarks.fsproj b/benchmarks/Benchmarks.fsproj
new file mode 100644
index 0000000..19e23ad
--- /dev/null
+++ b/benchmarks/Benchmarks.fsproj
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+ net8.0
+
+
+
+
+
+
+
+
+
+
+
diff --git a/benchmarks/Program.fs b/benchmarks/Program.fs
new file mode 100644
index 0000000..78eaaea
--- /dev/null
+++ b/benchmarks/Program.fs
@@ -0,0 +1,32 @@
+namespace Benchmarks
+
+open BenchmarkDotNet.Running
+open BenchmarkDotNet.Attributes
+
+type SortsBenchmark() =
+
+ static member ArrayLengths = [|10000..10000..100000|]
+ //static member ArrayLengths = [|0..100..1000|]
+
+ member this.Random = System.Random()
+
+ []
+ member val ArrayLength = 0 with get, set
+
+ member val ArrayToSort = [|0.0|] with get, set
+
+ []
+ member this.GetArrayToSort () =
+ this.ArrayToSort <- Array.init this.ArrayLength (fun _ -> this.Random.NextDouble())
+
+ []
+ member this.Benchmark () = Array.sort this.ArrayToSort
+
+module main =
+ []
+ let main argv =
+ let benchmarks =
+ BenchmarkSwitcher [| typeof |]
+
+ benchmarks.Run argv |> ignore
+ 0
\ No newline at end of file
diff --git a/src/Exercises/Exercises.fsproj b/src/Exercises/Exercises.fsproj
index f81f7f5..6b65264 100644
--- a/src/Exercises/Exercises.fsproj
+++ b/src/Exercises/Exercises.fsproj
@@ -1,12 +1,9 @@
-
-
+
net8.0
true
-
-
-
+
\ No newline at end of file
diff --git a/src/Exercises/Library.fs b/src/Exercises/Library.fs
index 486d287..d0adbc8 100644
--- a/src/Exercises/Library.fs
+++ b/src/Exercises/Library.fs
@@ -1,6 +1,11 @@
namespace Exercises
module Say =
+
+ type Compare = Le | Eq | Ge
+
+ type T = A of int | B of int
+
let hello name =
printfn "Hello %s" name
@@ -22,13 +27,9 @@ module Say =
let err_arr = [|"1", "2", "3"|]
let int_lst = [1;2;3]
+
+ let fn x b = (if x then 1 else b) + 7
- let fn x b =
- (if x
- then
- 1
- else b)
- + 7
let fn2 x =
for i in 1..2..10 do
printfn $"{i}"
@@ -42,6 +43,22 @@ module Say =
let count = count + 1
printfn $"{count}"
+
+ (*let sort (arr: 'a[]) (compare: 'a -> 'a -> Compare) =
+ match compare arr.[0] arr.[1] with
+ | Eq -> ..
+ | Le -> ..
+ | Ge -> ..
+*)
+ let compareT x y =
+ match x,y with
+ | A i, A j -> if i < j then Le elif i > j then Ge else Eq
+ | B i, B j -> if i < j then Le elif i > j then Ge else Eq
+ | A _, B _ -> Ge
+ | B _, A _ -> Le
+
+ // let r = sort [|A 10; B 1|] compareT
+
let rec g x = h x
and h y= g y
@@ -57,5 +74,32 @@ module Say =
then n
else fib (n - 1) + fib (n - 2)
+module MyList =
+
+ type MyList<'elem> =
+ | Empty
+ | Cons of 'elem * MyList<'elem>
+
+ let rec len lst =
+ match lst with
+ | Empty -> 0
+ | Cons (_,tl) -> 1 + len tl
+
+ let rec fold f state lst =
+ match lst with
+ | Empty -> state
+ | Cons (hd, tl) -> fold f (f state hd) tl
+ //| Cons (hd, tl) -> f (fold f state tl) hd
+ let rec map f lst =
+ let f state elem =
+ Cons (f elem, state)
+ let state = Empty
+ let lst = lst
+ fold f state lst
+module main =
+ []
+ let main argv =
+ printfn "!!!!"
+ 0
\ No newline at end of file
diff --git a/src/ImageProcessing/ImageProcessing.fs b/src/ImageProcessing/ImageProcessing.fs
new file mode 100644
index 0000000..b873c8b
--- /dev/null
+++ b/src/ImageProcessing/ImageProcessing.fs
@@ -0,0 +1,102 @@
+module ImageProcessing
+
+open System
+open SixLabors.ImageSharp
+open SixLabors.ImageSharp.PixelFormats
+
+[]
+type Image =
+ val Data: array
+ val Width: int
+ val Height: int
+ val Name: string
+
+ new(data, width, height, name) =
+ {
+ Data = data
+ Width = width
+ Height = height
+ Name = name
+ }
+
+let loadAs2DArray (file: string) =
+ let img = Image.Load file
+ let res = Array2D.zeroCreate img.Height img.Width
+
+ for i in 0 .. img.Width - 1 do
+ for j in 0 .. img.Height - 1 do
+ res.[j, i] <- img.Item(i, j).PackedValue
+
+ printfn $"H=%A{img.Height} W=%A{img.Width}"
+ res
+
+let loadAsImage (file: string) =
+ let img = Image.Load file
+
+ let buf = Array.zeroCreate (img.Width * img.Height)
+
+ img.CopyPixelDataTo(Span buf)
+ Image(buf, img.Width, img.Height, System.IO.Path.GetFileName file)
+
+let save2DByteArrayAsImage (imageData: byte[,]) file =
+ let h = imageData.GetLength 0
+ let w = imageData.GetLength 1
+ printfn $"H=%A{h} W=%A{w}"
+
+ let flat2Darray array2D =
+ [|
+ for x in [0 .. (Array2D.length1 array2D) - 1] do
+ for y in [0 .. (Array2D.length2 array2D) - 1] do
+ yield array2D.[x, y]
+ |]
+
+ let img = Image.LoadPixelData(flat2Darray imageData, w, h)
+ img.Save file
+
+let saveImage (image: Image) file =
+ let img = Image.LoadPixelData(image.Data, image.Width, image.Height)
+ img.Save file
+
+let gaussianBlurKernel =
+ [|
+ [| 1; 4; 6; 4; 1 |]
+ [| 4; 16; 24; 16; 4 |]
+ [| 6; 24; 36; 24; 6 |]
+ [| 4; 16; 24; 16; 4 |]
+ [| 1; 4; 6; 4; 1 |]
+ |]
+ |> Array.map (Array.map (fun x -> (float32 x) / 256.0f))
+
+let edgesKernel =
+ [|
+ [| 0; 0; -1; 0; 0 |]
+ [| 0; 0; -1; 0; 0 |]
+ [| 0; 0; 2; 0; 0 |]
+ [| 0; 0; 0; 0; 0 |]
+ [| 0; 0; 0; 0; 0 |]
+ |]
+ |> Array.map (Array.map float32)
+
+let applyFilter (filter: float32[][]) (img: byte[,]) =
+ let imgH = img.GetLength 0
+ let imgW = img.GetLength 1
+
+ let filterD = (Array.length filter) / 2
+
+ let filter = Array.concat filter
+
+ let processPixel px py =
+ let dataToHandle = [|
+ for i in px - filterD .. px + filterD do
+ for j in py - filterD .. py + filterD do
+ if i < 0
+ || i >= imgH
+ || j < 0
+ || j >= imgW
+ then float32 img.[px, py]
+ else float32 img.[i, j]
+ |]
+
+ Array.fold2 (fun s x y -> s + x * y) 0.0f filter dataToHandle
+
+ Array2D.mapi (fun x y _ -> byte (processPixel x y)) img
\ No newline at end of file
diff --git a/src/ImageProcessing/ImageProcessing.fsproj b/src/ImageProcessing/ImageProcessing.fsproj
new file mode 100644
index 0000000..7dd1ceb
--- /dev/null
+++ b/src/ImageProcessing/ImageProcessing.fsproj
@@ -0,0 +1,14 @@
+
+
+ Exe
+ net8.0
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/ImageProcessing/Program.fs b/src/ImageProcessing/Program.fs
new file mode 100644
index 0000000..2e1960e
--- /dev/null
+++ b/src/ImageProcessing/Program.fs
@@ -0,0 +1,35 @@
+open ImageProcessing
+open Argu
+
+let pathToExamples = "/home/gsv/Projects/TestProj2020/src/ImgProcessing/Examples"
+let inputFolder = System.IO.Path.Combine(pathToExamples, "input")
+
+let demoFile =
+ System.IO.Path.Combine(inputFolder, "armin-djuhic-ohc29QXbS-s-unsplash.jpg")
+
+type CmdArgs =
+ | [] Input_File of string
+ | [] Out_File of string
+ interface IArgParserTemplate with
+ member this.Usage =
+ match this with
+ | Input_File _ -> "File to process."
+ | Out_File _ -> "Where to save result."
+
+[]
+let main argv =
+ printfn "%A" argv
+ let parser = ArgumentParser.Create(programName = "ImageProcessing")
+ let usage = parser.PrintUsage()
+ let results = parser.Parse argv
+ let inFile = results.GetResult Input_File
+ let outFile = results.GetResult Out_File
+ let inImage = loadAs2DArray inFile
+ let resultImage =
+ applyFilter gaussianBlurKernel inImage
+ //|> applyFilter gaussianBlurKernel
+ //|> applyFilter gaussianBlurKernel
+ //|> applyFilter gaussianBlurKernel
+ //|> applyFilter edgesKernel
+ save2DByteArrayAsImage resultImage outFile
+ 0
\ No newline at end of file
diff --git a/test/Tests/PropertyTetst.fs b/test/Tests/PropertyTetst.fs
new file mode 100644
index 0000000..b5d45f6
--- /dev/null
+++ b/test/Tests/PropertyTetst.fs
@@ -0,0 +1,32 @@
+namespace Tests
+
+open FsCheck.Xunit
+
+
+(*
+module test =
+ let f x = 2
+*)
+
+
+[]
+type PlusPropertyTest () =
+
+ []
+ member _.``Plus is commutative`` (a: int, b: int) =
+ //printfn $"{a}, {b}"
+ a + b = b + a
+
+ []
+ member _.``Div is commutative`` (a: int, b: int) =
+ //printfn $"{a}, {b}"
+ if b <> 0 && a <> 0 then a / b = b / a else true
+
+ []
+ member _.``Plus is associative`` (a: int, b: int, c: int) = a + b + c = a + (b + c)
+
+
+ []
+ member _.``Double rev is id`` (lst: List) =
+ //printfn $"{a}, {b}"
+ List.rev (List.rev lst) = lst
\ No newline at end of file
diff --git a/test/Tests/Tests.fs b/test/Tests/Tests.fs
index 7fe8a08..452a9dc 100644
--- a/test/Tests/Tests.fs
+++ b/test/Tests/Tests.fs
@@ -1,11 +1,11 @@
namespace Tests
-open System
-open Microsoft.VisualStudio.TestTools.UnitTesting
+open Xunit
-[]
type TestClass () =
- []
+ []
member this.TestMethodPassing () =
- Assert.IsTrue(true);
+ Assert.True(true);
+
+
diff --git a/test/Tests/Tests.fsproj b/test/Tests/Tests.fsproj
index b0f54db..8cd8b9b 100644
--- a/test/Tests/Tests.fsproj
+++ b/test/Tests/Tests.fsproj
@@ -1,27 +1,25 @@
-
-
-
- net8.0
-
- false
- false
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ net8.0
+ false
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
-
-
-
+
+
\ No newline at end of file