diff --git a/FsharpSln.sln b/FsharpSln.sln index a9c1631..f244678 100644 --- a/FsharpSln.sln +++ b/FsharpSln.sln @@ -9,6 +9,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "LibHw2", "src\LibHw2\LibHw2 EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Test", "Test\Test.fsproj", "{363D4F3B-6E01-4E01-9616-7C95DFB0F5B6}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "LibHw7", "src\LibHw7\LibHw7.fsproj", "{50335321-2C50-43C0-8F8F-436AAEDF2D43}" +EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "ImageProcessing", "src\ImageProcessing\ImageProcessing.fsproj", "{3C564DE7-3B68-4DAE-AD09-F1987066BA36}" EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "LibHw3", "src\LibHw3\LibHw3.fsproj", "{E63C1F63-167B-47D5-A94C-6C00CDAC9104}" @@ -32,13 +34,13 @@ Global {363D4F3B-6E01-4E01-9616-7C95DFB0F5B6}.Debug|Any CPU.Build.0 = Debug|Any CPU {363D4F3B-6E01-4E01-9616-7C95DFB0F5B6}.Release|Any CPU.ActiveCfg = Release|Any CPU {363D4F3B-6E01-4E01-9616-7C95DFB0F5B6}.Release|Any CPU.Build.0 = Release|Any CPU - {3C564DE7-3B68-4DAE-AD09-F1987066BA36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3C564DE7-3B68-4DAE-AD09-F1987066BA36}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3C564DE7-3B68-4DAE-AD09-F1987066BA36}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3C564DE7-3B68-4DAE-AD09-F1987066BA36}.Release|Any CPU.Build.0 = Release|Any CPU + {50335321-2C50-43C0-8F8F-436AAEDF2D43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50335321-2C50-43C0-8F8F-436AAEDF2D43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50335321-2C50-43C0-8F8F-436AAEDF2D43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50335321-2C50-43C0-8F8F-436AAEDF2D43}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {07D1365E-068B-4B9D-999D-4F9C3B544697} = {C3F2792A-709B-4169-ADE4-3D55DC717452} {EEDB2603-0992-464E-B575-A9A5E31DFA3B} = {C3F2792A-709B-4169-ADE4-3D55DC717452} EndGlobalSection -EndGlobal +EndGlobal \ No newline at end of file diff --git a/Test/Test.fsproj b/Test/Test.fsproj index efc6067..33326eb 100644 --- a/Test/Test.fsproj +++ b/Test/Test.fsproj @@ -9,9 +9,7 @@ - - - + @@ -31,10 +29,7 @@ - - - - + diff --git a/Test/TestsHw7.fs b/Test/TestsHw7.fs new file mode 100644 index 0000000..bc3018a --- /dev/null +++ b/Test/TestsHw7.fs @@ -0,0 +1,164 @@ +namespace tests + +open System +open Xunit +open FsCheck +open FsCheck.Xunit +open QuattroMatrix +open QuattroMatrix.Matrix + +module PropertyQtreeTest = + + let toArray (mat: 'T array2d) : 'T array = + let height = Array2D.length1 mat + let width = Array2D.length2 mat + Array.init (height * width) (fun i -> + let row = i / width + let col = i % width + mat.[row, col] + ) + + let multMatr mulFunc addFunc mat1 mat2 = + if Array2D.length1 mat1 <> Array2D.length2 mat2 + then failwith "Matrices have different sizes" + else + let multedMat = Array2D.zeroCreate (Array2D.length1 mat1) (Array2D.length2 mat2) + for i in 0 .. Array2D.length1 mat1 - 1 do + for j in 0 .. Array2D.length2 mat1 - 1 do + for k in 0 .. Array2D.length2 mat2 - 1 do + multedMat[i,j] <- addFunc multedMat[i,j] (mulFunc mat1[i,k] mat2[k,j]) + multedMat + + let createMaped2Matr func matr1 matr2 = + let rmatr1 = toArray matr1 + let rmatr2 = toArray matr2 + let resMatr = Array.map2 func rmatr1 rmatr2 + resMatr + + let createQtree matr = + let sqmatr = createSquareMatrix matr + let qmatr = createQuadMatrix sqmatr 0 0 (Array2D.length1 sqmatr) + qmatr, Array2D.length1 sqmatr + + let createFinalMatrix (qtree: QuadMatrix<'T>) qsize heigth wide = + let qmatr2d = toArray2d qtree qsize + let actmatr = Array2D.create heigth wide Unchecked.defaultof<'T> + for i in 0 .. heigth - 1 do + for j in 0 .. wide - 1 do + actmatr[i, j] <- qmatr2d[i, j] + actmatr + + let matrixGenerator rows cols (elementGen: Gen<'T>) : Gen<'T[,]> = + let genMatrix = + gen { + let! elements = Gen.array2DOfDim (rows, cols) elementGen + return elements + } + genMatrix + + let testMap matr size func = + let heigth = Array2D.length1 matr + let wide = Array2D.length2 matr + let expmatr = Array2D.map func matr + let qmatr, qsize = createQtree matr + let mapedMatr = map func qmatr + let actmatr = createFinalMatrix mapedMatr qsize heigth wide + expmatr, actmatr + + let testMap2 matr1 matr2 size func = + let expmatr = createMaped2Matr func matr1 matr2 + let qmatr1, qsize1 = createQtree matr1 + let qmatr2, qsize2 = createQtree matr2 + let actqmatr = map2 func qmatr1 qmatr2 + let actmatr2d = createFinalMatrix actqmatr qsize1 size size + let actmatr = toArray actmatr2d + let fequal = Array.forall2 (=) actmatr expmatr + fequal + + let testMult matr1 matr2 size mulFunc addFunc = + let expmatr= multMatr mulFunc addFunc matr1 matr2 + let qmatr1, qsize1 = createQtree matr1 + let qmatr2, qsize2 = createQtree matr2 + let actqmatr = multiplyMatrix mulFunc addFunc qmatr1 qsize1 qmatr2 qsize2 + let actmatr = createFinalMatrix actqmatr qsize1 size size + expmatr, actmatr + + [] + type idTests() = + + [] + member _.intTest (matr: int array2d) = + let qmatr, qsize = PropertyQtreeTest.createQtree matr + let mapedMatr = map id qmatr + Assert.Equal(qmatr, mapedMatr) + + [] + member _.floatTest (matr: float32 array2d) = + let qmatr, qsize = PropertyQtreeTest.createQtree matr + let mapedMatr = map id qmatr + Assert.Equal(qmatr, mapedMatr) + + [] + member _.charTest (matr: char array2d) = + let qmatr, qsize = PropertyQtreeTest.createQtree matr + let mapedMatr = map id qmatr + Assert.Equal(qmatr, mapedMatr) + + type mapTest() = + + [] + member _.intTest (size: uint) = + let matr = Gen.sample (int size) 1 (PropertyQtreeTest.matrixGenerator (int size) (int size) (Gen.elements {-100000..100000})) + let expmatr, actmatr = PropertyQtreeTest.testMap matr.[0] (int size) ((+) 1) + Assert.Equal(expmatr, actmatr) + + [] + member _.charTest (size: uint) = + let matr = Gen.sample (int size) 1 (PropertyQtreeTest.matrixGenerator (int size) (int size) (Gen.elements {' '..'~'})) + let expmatr, actmatr = PropertyQtreeTest.testMap matr.[0] (int size) ((+) '1') + Assert.Equal(expmatr, actmatr) + + [] + member _.floatTest (size: uint) = + let matr = Gen.sample (int size) 1 (PropertyQtreeTest.matrixGenerator (int size) (int size) (Gen.elements {-infinityf..infinityf})) + let expmatr, actmatr = PropertyQtreeTest.testMap matr.[0] (int size) ((+) 1f) + Assert.Equal(expmatr, actmatr) + + type map2Test()= + + [] + member _.intTest (size: uint) = + let matr = Gen.sample (int size) 2 (PropertyQtreeTest.matrixGenerator (int size) (int size) (Gen.elements {-100000..100000})) + let fequal = PropertyQtreeTest.testMap2 matr.[0] matr.[1] (int (int size))(+) + Assert.True(fequal) + + [] + member _.charTest (size: uint) = + let matr = Gen.sample (int size) 2 (PropertyQtreeTest.matrixGenerator (int size) (int size) (Gen.elements {' '..'~'})) + let fequal = PropertyQtreeTest.testMap2 matr.[0] matr.[1] (int (int size))(+) + Assert.True(fequal) + + [] + member _.floatTest (size: uint) = + let matr = Gen.sample (int size) 2 (PropertyQtreeTest.matrixGenerator (int size) (int size) (Gen.elements{-infinityf..infinityf})) + let fequal = PropertyQtreeTest.testMap2 matr.[0] matr.[1] (int (int size))(+) + Assert.True(fequal) + + type multTest() = + + [] + member _.intTest (size: uint) = + let matr = Gen.sample (int size) 2 (PropertyQtreeTest.matrixGenerator (int size) (int size) (Gen.elements {-100000..100000})) + let expmatr, actmatr = PropertyQtreeTest.testMult matr.[0] matr.[1] (int (int size)) ( * ) (+) + Assert.Equal(expmatr, actmatr) + + [] + member _.charTest (size: uint) = + let matr = Gen.sample (int size) 2 (PropertyQtreeTest.matrixGenerator (int size) (int size) (Gen.elements {' ' .. '~'})) + let expmatr, actmatr = PropertyQtreeTest.testMult matr.[0] matr.[1] (int (int size)) (fun x y -> char (int x * int y)) (+) + Assert.Equal(expmatr, actmatr) + [] + member _.floatTest (size: uint) = + let matr = Gen.sample (int size) 2 (PropertyQtreeTest.matrixGenerator (int size) (int size) (Gen.elements {-infinityf .. infinityf})) + let expmatr, actmatr = PropertyQtreeTest.testMult matr.[0] matr.[1] (int (int size)) ( * ) (+) + Assert.Equal(expmatr, actmatr) \ No newline at end of file diff --git a/src/LibHw7/LibHw7.fsproj b/src/LibHw7/LibHw7.fsproj new file mode 100644 index 0000000..f81f7f5 --- /dev/null +++ b/src/LibHw7/LibHw7.fsproj @@ -0,0 +1,12 @@ + + + + net8.0 + true + + + + + + + diff --git a/src/LibHw7/Library.fs b/src/LibHw7/Library.fs new file mode 100644 index 0000000..f3ec6e9 --- /dev/null +++ b/src/LibHw7/Library.fs @@ -0,0 +1,179 @@ +namespace QuattroMatrix + +open System + +module Matrix = + type QuadMatrix<'T> = + | Leaf of 'T + | Node of QuadMatrix<'T> * QuadMatrix<'T> * QuadMatrix<'T> * QuadMatrix<'T> + + let createSquareMatrix (inmatr: 'T array2d) = + let logSize = + if Array2D.length2 inmatr = 0 then + 0.0 + else + max (Math.Log2(Array2D.length1 inmatr)) (Math.Log2(Array2D.length2 inmatr)) + + let isSizeCorrect = logSize = float (int logSize) + + if + not isSizeCorrect + || Array2D.length1 inmatr <> Array2D.length2 inmatr + || Array2D.length1 inmatr = 0 + then + let normalSize = pown 2 (int logSize + 1) + + let resMatr: 'T array2d = + Array2D.create normalSize normalSize Unchecked.defaultof<'T> + + for i in 0 .. Array2D.length1 inmatr - 1 do + for j in 0 .. Array2D.length2 inmatr - 1 do + resMatr[i, j] <- inmatr[i, j] + + resMatr + else + let resMatr = inmatr + resMatr + + let rec createQuadMatrix (sqmatr: 'T array2d) icorner jcorner size = + let mutable isEqualMatr = true + let value = sqmatr[icorner, jcorner] + let mutable i = icorner + let mutable j = jcorner + + while i < icorner + size && isEqualMatr do + while j < jcorner + size && isEqualMatr do + if value <> sqmatr[i, j] then + isEqualMatr <- false + + j <- j + 1 + + i <- i + 1 + j <- jcorner + + if isEqualMatr then + Leaf(value) + else + let halfsize = size / 2 + + Node( + createQuadMatrix sqmatr icorner jcorner halfsize, + createQuadMatrix sqmatr icorner (jcorner + halfsize) halfsize, + createQuadMatrix sqmatr (icorner + halfsize) jcorner halfsize, + createQuadMatrix sqmatr (icorner + halfsize) (jcorner + halfsize) halfsize + ) + + let rec map func qtree = + match qtree with + | Leaf(value) -> Leaf(func value) + | Node(t1, t2, t3, t4) -> Node(map func t1, map func t2, map func t3, map func t4) + + let rec map2 func qtree1 qtree2 = + match qtree1, qtree2 with + | Leaf(value1), Leaf(value2) -> Leaf(func value1 value2) + | Leaf(value1), Node(t2_1, t2_2, t2_3, t2_4) -> + Node(map2 func qtree1 t2_1, map2 func qtree1 t2_2, map2 func qtree1 t2_3, map2 func qtree1 t2_4) + | Node(t1_1, t1_2, t1_3, t1_4), Leaf(value2) -> + Node(map2 func t1_1 qtree2, map2 func t1_2 qtree2, map2 func t1_3 qtree2, map2 func t1_4 qtree2) + | Node(t1_1, t1_2, t1_3, t1_4), Node(t2_1, t2_2, t2_3, t2_4) -> + Node(map2 func t1_1 t2_1, map2 func t1_2 t2_2, map2 func t1_3 t2_3, map2 func t1_4 t2_4) + + let rec add addFunc qtree1 size1 qtree2 size2 = + match qtree1, qtree2 with + | Leaf(value1), Leaf(value2) -> Leaf(addFunc value1 value2) + | Leaf(value1), Node(t2_1, t2_2, t2_3, t2_4) -> + Node( + add addFunc qtree1 (size1 / 2) t2_1 (size2 / 2), + add addFunc qtree1 (size1 / 2) t2_2 (size2 / 2), + add addFunc qtree1 (size1 / 2) t2_3 (size2 / 2), + add addFunc qtree1 (size1 / 2) t2_4 (size2 / 2) + ) + | Node(t1_1, t1_2, t1_3, t1_4), Leaf(value2) -> + Node( + add addFunc t1_1 (size1 / 2) qtree2 (size2 / 2), + add addFunc t1_2 (size1 / 2) qtree2 (size2 / 2), + add addFunc t1_3 (size1 / 2) qtree2 (size2 / 2), + add addFunc t1_4 (size1 / 2) qtree2 (size2 / 2) + ) + | Node(t1_1, t1_2, t1_3, t1_4), Node(t2_1, t2_2, t2_3, t2_4) -> + Node( + add addFunc t1_1 (size1 / 2) t2_1 (size2 / 2), + add addFunc t1_2 (size1 / 2) t2_2 (size2 / 2), + add addFunc t1_3 (size1 / 2) t2_3 (size2 / 2), + add addFunc t1_4 (size1 / 2) t2_4 (size2 / 2) + ) + + let rec multiplyMatrix mulFunc addFunc qtree1 size1 qtree2 size2 = + match qtree1, qtree2 with + | Leaf(value1), Leaf(value2) -> Leaf(mulFunc value1 value2) + | Leaf(value1), Node(t2_1, t2_2, t2_3, t2_4) -> + let a = multiplyMatrix mulFunc addFunc qtree1 (size1 / 2) t2_1 (size2 / 2) + let b = multiplyMatrix mulFunc addFunc qtree1 (size1 / 2) t2_3 (size2 / 2) + let c = multiplyMatrix mulFunc addFunc qtree1 (size1 / 2) t2_2 (size2 / 2) + let d = multiplyMatrix mulFunc addFunc qtree1 (size1 / 2) t2_4 (size2 / 2) + let e = multiplyMatrix mulFunc addFunc qtree1 (size1 / 2) t2_1 (size2 / 2) + let f = multiplyMatrix mulFunc addFunc qtree1 (size1 / 2) t2_3 (size2 / 2) + let g = multiplyMatrix mulFunc addFunc qtree1 (size1 / 2) t2_2 (size2 / 2) + let h = multiplyMatrix mulFunc addFunc qtree1 (size1 / 2) t2_4 (size2 / 2) + + Node( + add addFunc a (size1 / 2) b (size2 / 2), + add addFunc c (size1 / 2) d (size2 / 2), + add addFunc e (size1 / 2) f (size2 / 2), + add addFunc g (size1 / 2) h (size2 / 2) + ) + | Node(t1_1, t1_2, t1_3, t1_4), Leaf(value2) -> + let a = multiplyMatrix mulFunc addFunc t1_1 (size1 / 2) qtree2 (size2 / 2) + let b = multiplyMatrix mulFunc addFunc t1_2 (size1 / 2) qtree2 (size2 / 2) + let c = multiplyMatrix mulFunc addFunc t1_1 (size1 / 2) qtree2 (size2 / 2) + let d = multiplyMatrix mulFunc addFunc t1_2 (size1 / 2) qtree2 (size2 / 2) + let e = multiplyMatrix mulFunc addFunc t1_3 (size1 / 2) qtree2 (size2 / 2) + let f = multiplyMatrix mulFunc addFunc t1_4 (size1 / 2) qtree2 (size2 / 2) + let g = multiplyMatrix mulFunc addFunc t1_3 (size1 / 2) qtree2 (size2 / 2) + let h = multiplyMatrix mulFunc addFunc t1_4 (size1 / 2) qtree2 (size2 / 2) + + Node( + add addFunc a (size1 / 2) b (size2 / 2), + add addFunc c (size1 / 2) d (size2 / 2), + add addFunc e (size1 / 2) f (size2 / 2), + add addFunc g (size1 / 2) h (size2 / 2) + ) + | Node(t1_1, t1_2, t1_3, t1_4), Node(t2_1, t2_2, t2_3, t2_4) -> + let a = multiplyMatrix mulFunc addFunc t1_1 (size1 / 2) t2_1 (size2 / 2) + let b = multiplyMatrix mulFunc addFunc t1_2 (size1 / 2) t2_3 (size2 / 2) + let c = multiplyMatrix mulFunc addFunc t1_1 (size1 / 2) t2_2 (size2 / 2) + let d = multiplyMatrix mulFunc addFunc t1_2 (size1 / 2) t2_4 (size2 / 2) + let e = multiplyMatrix mulFunc addFunc t1_3 (size1 / 2) t2_1 (size2 / 2) + let f = multiplyMatrix mulFunc addFunc t1_4 (size1 / 2) t2_3 (size2 / 2) + let g = multiplyMatrix mulFunc addFunc t1_3 (size1 / 2) t2_2 (size2 / 2) + let h = multiplyMatrix mulFunc addFunc t1_4 (size1 / 2) t2_4 (size2 / 2) + + Node( + add addFunc a (size1 / 2) b (size2 / 2), + add addFunc c (size1 / 2) d (size2 / 2), + add addFunc e (size1 / 2) f (size2 / 2), + add addFunc g (size1 / 2) h (size2 / 2) + ) + + let rec toArray2d (qtree: QuadMatrix<'T>) sizem = + match qtree with + | Leaf(value) -> + let matr = Array2D.create sizem sizem value + matr + | Node(t1, t2, t3, t4) -> + let topleft = toArray2d t1 (sizem / 2) + let topright = toArray2d t2 (sizem / 2) + let botleft = toArray2d t3 (sizem / 2) + let botright = toArray2d t4 (sizem / 2) + let size = Array2D.length1 topleft + + let resmatr = Array2D.create sizem sizem Unchecked.defaultof<'T> + + for i in 0 .. size - 1 do + for j in 0 .. size - 1 do + resmatr[i, j] <- topleft[i, j] + resmatr[i, j + size] <- topright[i, j] + resmatr[i + size, j] <- botleft[i, j] + resmatr[i + size, j + size] <- botright[i, j] + + resmatr \ No newline at end of file