Created the initial version

main
oabrivard 2 years ago
parent 2146ba3e57
commit 79a3989812

2
.gitignore vendored

@ -1,5 +1,7 @@
.DS_Store .DS_Store
settings.json
# ---> Go # ---> Go
# If you prefer the allow list template instead of the deny list, see community template: # If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore

@ -0,0 +1,50 @@
package container
type Queue[T any] struct {
data []T
len int
}
// New creates an empty queue
func NewQueue[T any]() Queue[T] {
q := Queue[T]{
[]T{},
0,
}
return q
}
// Enqueue adds an element to the end of the queue.
// It appends the given value to the queue's data slice and increments the length of the queue.
func (q *Queue[T]) Enqueue(v T) {
q.data = append(q.data, v)
q.len++
}
// Dequeue removes and returns the element at the front of the queue.
// It panics if the queue is empty.
func (q *Queue[T]) Dequeue() T {
if !q.HasElement() {
panic("called Dequeue() on an empty queue")
}
value := q.data[0]
var zeroValue T
q.data[0] = zeroValue
q.data = q.data[1:]
q.len--
return value
}
// HasElement returns true if the queue has at least one element, otherwise false.
func (q *Queue[T]) HasElement() bool {
return q.len > 0
}
// GetData returns the data stored in the queue.
func (q *Queue[T]) GetData() []T {
return q.data
}

@ -0,0 +1,66 @@
package container
import (
"testing"
)
func TestQueueDequeue(t *testing.T) {
// Create a new queue
q := NewQueue[int]()
// Enqueue some elements
q.Enqueue(1)
q.Enqueue(2)
q.Enqueue(3)
// Dequeue the elements and check if they match the expected values
value := q.Dequeue()
if value != 1 {
t.Errorf("Expected dequeued value to be 1, but got %v", value)
}
value = q.Dequeue()
if value != 2 {
t.Errorf("Expected dequeued value to be 2, but got %v", value)
}
value = q.Dequeue()
if value != 3 {
t.Errorf("Expected dequeued value to be 3, but got %v", value)
}
// Try to dequeue from an empty queue and expect a panic
defer func() {
if r := recover(); r == nil {
t.Errorf("Expected Dequeue() to panic, but it didn't")
}
}()
q.Dequeue()
}
func TestQueueHasElement(t *testing.T) {
// Create a new queue
q := NewQueue[int]()
// Check if the queue has elements, expect false
if q.HasElement() {
t.Errorf("Expected HasElement() to return false, but got true")
}
// Enqueue an element
q.Enqueue(1)
// Check if the queue has elements, expect true
if !q.HasElement() {
t.Errorf("Expected HasElement() to return true, but got false")
}
// Dequeue the element
q.Dequeue()
// Check if the queue has elements, expect false
if q.HasElement() {
t.Errorf("Expected HasElement() to return false, but got true")
}
}

@ -0,0 +1,76 @@
/*
Copyright 2022 Olivier Abrivard
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
package container
type Stack[T any] struct {
data []T
}
// New creates an empty stack
func NewStack[T any]() Stack[T] {
result := Stack[T]{
[]T{},
}
return result
}
// Push pushes the value v on top of stack s.
func (s *Stack[T]) Push(v T) {
s.data = append(s.data, v)
}
// Pop removes the value v from the top of stack s and returns it.
func (s *Stack[T]) Pop() T {
if !s.HasElement() {
panic("called Pop() on an empty stack")
}
value := s.data[len(s.data)-1]
s.data = s.data[0 : len(s.data)-1]
return value
}
// HasElement returns true if the stack s contains at least one element.
func (s *Stack[T]) HasElement() bool {
return len(s.data) > 0
}
// Count returns the number of elements contained in s.
func (s *Stack[T]) Count() int {
return len(s.data)
}
// Reversed returns a new stack built from stack s, with its elements in reverse order.
// s will be emptied by this operation.
func (s *Stack[T]) Reversed() Stack[T] {
result := Stack[T]{
make([]T, len(s.data)),
}
for s.HasElement() {
result.Push(s.Pop())
}
return result
}

@ -0,0 +1,103 @@
/*
Copyright 2022 Olivier Abrivard
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
package container
import "testing"
func TestEmpty(t *testing.T) {
defer func() { _ = recover() }() // turn off the panic
s := NewStack[int]()
s.Pop()
// Never reaches here if Pop() panics.
t.Errorf("Pop() on empty stack should panic")
}
func TestHasElements(t *testing.T) {
s := NewStack[int]()
if s.HasElement() {
t.Errorf("HasElement() should return false for empty stack")
}
s.Push(1)
if !s.HasElement() {
t.Errorf("HasElement() should return true for non empty stack")
}
}
func TestCount(t *testing.T) {
s := NewStack[int]()
if s.Count() != 0 {
t.Errorf("Count() should be 0 for empty stack")
}
s.Push(1)
if s.Count() != 1 {
t.Errorf("Count() should be 1 for stack with as single element")
}
}
func TestPushPop(t *testing.T) {
s1 := NewStack[int]()
s1.Push(1)
s1.Push(2)
s1.Push(3)
var expectedValues = []int{3, 2, 1}
for _, expected := range expectedValues {
got := s1.Pop()
if expected != got {
t.Errorf("got %d, want %d", got, expected)
}
}
}
func TestReversed(t *testing.T) {
s1 := NewStack[int]()
s1.Push(1)
s1.Push(2)
s1.Push(3)
s2 := s1.Reversed()
if s1.Count() != 0 {
t.Errorf("Reversed() should emty the stack it is called upon")
}
var expectedValues = []int{1, 2, 3}
for _, expected := range expectedValues {
got := s2.Pop()
if expected != got {
t.Errorf("got %d, want %d", got, expected)
}
}
}

@ -0,0 +1,58 @@
package container
type Vector[T any] []T
// PushBack adds an element to the end of the vector.
// Complexity O(1) + array extesnion
func (v *Vector[T]) PushBack(e T) {
*v = append(*v, e)
}
// PopBack removes and returns the last element from the vector.
// If the vector is empty, it will panic.
// Complexity O(1)
func (v *Vector[T]) PopBack() T {
if !v.HasElement() {
panic("called PopBack() on an empty vector")
}
value := (*v)[len(*v)-1]
*v = (*v)[0 : len(*v)-1]
return value
}
// Len returns the length of the vector.
// It returns an integer representing the number of elements in the vector.
func (v Vector[T]) Len() int {
return len(v)
}
// HasElement returns true if the vector v contains at least one element.
func (v Vector[T]) HasElement() bool {
return v.Len() > 0
}
// PushFront adds an element to the front of the vector.
// Complexity O(n)
func (v *Vector[T]) PushFront(e T) {
newVect := make([]T, v.Len()+1)
copy(newVect[1:], *v)
newVect[0] = e
*v = newVect
}
// PopFront removes and returns the element at the front of the vector.
// It panics if the vector is empty.
// Complexity O(1)
func (v *Vector[T]) PopFront() T {
if !v.HasElement() {
panic("called PopFront() on an empty vector")
}
value := (*v)[0]
var zeroValue T
(*v)[0] = zeroValue
*v = (*v)[1:]
return value
}

@ -0,0 +1,118 @@
package container
import (
"reflect"
"testing"
)
func TestVectorPushBack(t *testing.T) {
v := Vector[int]{1, 2, 3}
e := 4
v.PushBack(e)
expected := Vector[int]{1, 2, 3, 4}
if !reflect.DeepEqual(v, expected) {
t.Errorf("PushBack() failed, expected %v, got %v", expected, v)
}
if v.Len() != 4 {
t.Errorf("expected a length of 4, got %v", v.Len())
}
}
func TestVectorPopBack(t *testing.T) {
v := Vector[int]{1, 2, 3, 4}
expectedValue := 4
value := v.PopBack()
if value != expectedValue {
t.Errorf("PopBack() failed, expected %v, got %v", expectedValue, value)
}
expectedVector := Vector[int]{1, 2, 3}
if !reflect.DeepEqual(v, expectedVector) {
t.Errorf("PopBack() failed, expected vector %v, got %v", expectedVector, v)
}
if v.Len() != 3 {
t.Errorf("expected a length of 3, got %v", v.Len())
}
// Test panic on empty vector
emptyVector := Vector[int]{}
defer func() {
if r := recover(); r == nil {
t.Errorf("PopBack() did not panic on empty vector")
}
}()
emptyVector.PopBack()
}
func TestVectorLen(t *testing.T) {
v := Vector[int]{1, 2, 3}
expected := 3
result := v.Len()
if result != expected {
t.Errorf("Len() failed, expected %d, got %d", expected, result)
}
}
func TestVectorHasElement(t *testing.T) {
v := Vector[int]{1, 2, 3}
hasElement := v.HasElement()
expected := true
if hasElement != expected {
t.Errorf("HasElement() failed, expected %v, got %v", expected, hasElement)
}
v = Vector[int]{}
hasElement = v.HasElement()
expected = false
if hasElement != expected {
t.Errorf("HasElement() failed, expected %v, got %v", expected, hasElement)
}
}
func TestVectorPushFront(t *testing.T) {
v := Vector[int]{1, 2, 3}
e := 4
v.PushFront(e)
expected := Vector[int]{4, 1, 2, 3}
if !reflect.DeepEqual(v, expected) {
t.Errorf("PushFront() failed, expected %v, got %v", expected, v)
}
if v.Len() != 4 {
t.Errorf("expected a length of 4, got %v", v.Len())
}
}
func TestVectorPopFront(t *testing.T) {
v := Vector[int]{1, 2, 3, 4}
expectedValue := 1
expectedVector := Vector[int]{2, 3, 4}
value := v.PopFront()
if value != expectedValue {
t.Errorf("PopFront() failed, expected value %v, got %v", expectedValue, value)
}
if !reflect.DeepEqual(v, expectedVector) {
t.Errorf("PopFront() failed, expected vector %v, got %v", expectedVector, v)
}
if v.Len() != 3 {
t.Errorf("expected a length of 3, got %v", v.Len())
}
}

@ -0,0 +1,40 @@
package fp
// Fold applies a function to each element in the slice and accumulates the result.
// It takes a slice of type T, an initial value of type A, and a function that combines the accumulator value with each element of the slice.
// The function returns the final accumulated value.
func Fold[A any, T any](s []T, a A, f func(A, T) A) A {
for i := range s {
a = f(a, s[i])
}
return a
}
// Map applies the function f to each element of the slice s and returns a new slice
// containing the results.
//
// The returned slice will contain elements of type M, which is the result
// type of the function f.
//
// Example usage:
//
// numbers := []int{1, 2, 3, 4, 5}
// doubled := Map(numbers, func(n int) int {
// return n * 2
// })
// // doubled is now []int{2, 4, 6, 8, 10}
//
// names := []string{"Alice", "Bob", "Charlie"}
// lengths := Map(names, func(name string) int {
// return len(name)
// })
// // lengths is now []int{5, 3, 7}
//
// Note: The input slice s is not modified by this function.
func Map[T, M any](s []T, f func(T) M) []M {
res := []M{}
for i := range s {
res = append(res, f(s[i]))
}
return res
}

@ -0,0 +1,89 @@
package fp
import (
"reflect"
"testing"
)
func TestMap(t *testing.T) {
tests := []struct {
name string
input []int
function func(int) int
want []int
}{
{
name: "multiply by 2",
input: []int{1, 2, 3},
function: func(x int) int { return x * 2 },
want: []int{2, 4, 6},
},
{
name: "add 1",
input: []int{1, 2, 3},
function: func(x int) int { return x + 1 },
want: []int{2, 3, 4},
},
{
name: "subtract 5",
input: []int{10, 15, 20},
function: func(x int) int { return x - 5 },
want: []int{5, 10, 15},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Map(tt.input, tt.function)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Map() = %v, want %v", got, tt.want)
}
})
}
}
func TestFold(t *testing.T) {
tests := []struct {
name string
input []int
accumulator int
function func(int, int) int
want int
}{
{
name: "sum",
input: []int{1, 2, 3},
accumulator: 0,
function: func(a, b int) int { return a + b },
want: 6,
},
{
name: "product",
input: []int{1, 2, 3},
accumulator: 1,
function: func(a, b int) int { return a * b },
want: 6,
},
{
name: "maximum",
input: []int{1, 2, 3},
accumulator: 0,
function: func(a, b int) int {
if a > b {
return a
}
return b
},
want: 3,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Fold(tt.input, tt.accumulator, tt.function)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Fold() = %v, want %v", got, tt.want)
}
})
}
}

@ -0,0 +1,5 @@
module gitea.paas.celticinfo.fr/oabrivard/abrolgo
go 1.21.6
require golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3

@ -0,0 +1,2 @@
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o=
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=

@ -0,0 +1,50 @@
package math
import "math"
type Point struct {
X, Y float64
}
// ShoelaceArea calculates the area of a polygon using the Shoelace formula.
// It takes a slice of Point structs representing the vertices of the polygon.
// If the number of vertices is less than 3, it returns 0.0 indicating that it is not a valid polygon.
func ShoelaceArea(polygon []Point) float64 {
if len(polygon) < 3 {
return 0.0 // Not a polygon
}
var area float64 = 0.0
j := len(polygon) - 1 // The last vertex is the 'previous' one to the first
for i := 0; i < len(polygon); i++ {
area += (polygon[j].X + polygon[i].X) * (polygon[j].Y - polygon[i].Y)
j = i // j is previous vertex to i
}
return 0.5 * math.Abs(area)
}
// floodFill performs a flood fill algorithm on the given matrix starting from the specified row and column.
// It replaces all occurrences of the previous color with the new color.
// The height and width parameters define the dimensions of the matrix.
func floodFill(matrix Matrix[int64], row int, col int, prevColor int64, newColor int64, height int, width int) {
if row < 0 || row >= height || col < 0 || col >= width {
return
}
if matrix[row][col] != prevColor {
return
}
if matrix[row][col] == newColor {
return
}
matrix[row][col] = newColor
floodFill(matrix, row+1, col, prevColor, newColor, height, width)
floodFill(matrix, row-1, col, prevColor, newColor, height, width)
floodFill(matrix, row, col+1, prevColor, newColor, height, width)
floodFill(matrix, row, col-1, prevColor, newColor, height, width)
}

@ -0,0 +1,76 @@
package math
import "testing"
func TestShoelaceArea(t *testing.T) {
tests := []struct {
name string
polygon []Point
want float64
}{
{
name: "Triangle",
polygon: []Point{
{X: 0, Y: 0},
{X: 0, Y: 4},
{X: 3, Y: 0},
},
want: 6.0,
},
{
name: "Quadrilateral",
polygon: []Point{
{X: 0, Y: 0},
{X: 0, Y: 4},
{X: 3, Y: 4},
{X: 3, Y: 0},
},
want: 12.0,
},
{
name: "Invalid Polygon",
polygon: []Point{
{X: 0, Y: 0},
{X: 0, Y: 4},
},
want: 0.0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ShoelaceArea(tt.polygon)
if got != tt.want {
t.Errorf("ShoelaceArea() = %v, want %v", got, tt.want)
}
})
}
}
func TestFloodFill(t *testing.T) {
matrix := Matrix[int64]{
{1, 1, 1, 1},
{1, 0, 0, 1},
{1, 0, 0, 1},
{1, 1, 1, 1},
}
row := 1
col := 1
prevColor := int64(0)
newColor := int64(2)
height := 4
width := 4
floodFill(matrix, row, col, prevColor, newColor, height, width)
expectedMatrix := Matrix[int64]{
{1, 1, 1, 1},
{1, 2, 2, 1},
{1, 2, 2, 1},
{1, 1, 1, 1},
}
if !matrix.Equal(expectedMatrix) {
t.Errorf("FloodFill() failed, expected matrix: %v, got: %v", expectedMatrix, matrix)
}
}

@ -0,0 +1,113 @@
package math
import (
"golang.org/x/exp/constraints"
)
// IsPrime checks if the given number is prime.
// It returns true if the number is prime, and false otherwise.
func IsPrime[T constraints.Integer](n T) bool {
if n <= 1 {
return false
}
if n <= 3 {
return true
}
if n%2 == 0 || n%3 == 0 {
return false
}
for i := T(5); i*i <= n; i += 6 {
if n%i == 0 || n%(i+2) == 0 {
return false
}
}
return true
}
// IntPow calculates the power of an integer.
// It takes two parameters, x and y, and returns the result of x raised to the power of y.
// The type of x and y must be an integer type.
func IntPow[T constraints.Integer](x, y T) T {
result := T(1)
for i := T(0); i < y; i++ {
result *= x
}
return result
}
// Pow2 calculates the power of 2 for the given integer value.
// It performs a bitwise left shift operation on the number 1 by the value of x.
// The result is returned as an integer of the same type as the input.
func Pow2[T constraints.Integer](x T) T {
return 1 << x
}
// GCD calculates the greatest common divisor (GCD) of two integers.
// It uses the Euclidean algorithm to find the GCD.
// The function takes two parameters, 'a' and 'b', which represent the integers.
// It returns the GCD as the result.
func GCD[T constraints.Integer](a, b T) T {
for b != 0 {
t := b
b = a % b
a = t
}
return a
}
// LCM calculates the least common multiple (LCM) of two or more integers.
// It takes two integers, a and b, as the first two arguments, and an optional variadic parameter integers for additional integers.
// The function uses the GCD (greatest common divisor) function to calculate the LCM.
// It returns the LCM as the result.
func LCM[T constraints.Integer](a, b T, integers ...T) T {
result := a * b / GCD(a, b)
for i := 0; i < len(integers); i++ {
result = LCM(result, integers[i])
}
return result
}
// AbsInt returns the absolute value of an integer.
// It takes an integer value x as input and returns the absolute value of x.
func AbsInt[T constraints.Integer](x T) T {
if x >= 0 {
return x
} else {
return -x
}
}
// gaussianElimination performs Gaussian elimination on the given coefficients matrix and right-hand side vector.
// It solves a system of linear equations by transforming the coefficients matrix into row-echelon form.
// The function takes a square matrix of type Matrix[float64] and a vector of type []float64 as input.
// The size of the matrix and the length of the vector should be the same.
// The function modifies the coefficients matrix and the right-hand side vector in place.
// The solution is stored into the rhs vector.
func gaussianElimination(coefficients Matrix[float64], rhs []float64) {
size := len(coefficients)
for i := 0; i < size; i++ {
// Select pivot
pivot := coefficients[i][i]
// Normalize row i
for j := 0; j < size; j++ {
coefficients[i][j] = coefficients[i][j] / pivot
}
rhs[i] = rhs[i] / pivot
// Sweep using row i
for k := 0; k < size; k++ {
if k != i {
factor := coefficients[k][i]
for j := 0; j < size; j++ {
coefficients[k][j] = coefficients[k][j] - factor*coefficients[i][j]
}
rhs[k] = rhs[k] - factor*rhs[i]
}
}
}
}

@ -0,0 +1,271 @@
package math
import (
"testing"
)
func TestIsPrime(t *testing.T) {
tests := []struct {
n int
expected bool
}{
{
n: 0,
expected: false,
},
{
n: 1,
expected: false,
},
{
n: 2,
expected: true,
},
{
n: 3,
expected: true,
},
{
n: 4,
expected: false,
},
{
n: 5,
expected: true,
},
{
n: 6,
expected: false,
},
// Add more test cases as needed
}
for _, tt := range tests {
result := IsPrime(tt.n)
if result != tt.expected {
t.Errorf("IsPrime(%d) = %v, expected %v", tt.n, result, tt.expected)
}
}
}
func TestIntPow(t *testing.T) {
tests := []struct {
x int
y int
expected int
}{
{
x: 2,
y: 3,
expected: 8,
},
{
x: 5,
y: 0,
expected: 1,
},
{
x: 10,
y: 1,
expected: 10,
},
{
x: 3,
y: 4,
expected: 81,
},
{
x: 2,
y: 0,
expected: 1,
},
{
x: 0,
y: 5,
expected: 0,
},
{
x: -2,
y: 3,
expected: -8,
},
}
for _, tt := range tests {
result := IntPow(tt.x, tt.y)
if result != tt.expected {
t.Errorf("IntPow(%d, %d) = %d, expected %d", tt.x, tt.y, result, tt.expected)
}
}
}
func TestPow2(t *testing.T) {
tests := []struct {
x int
expected int
}{
{
x: 0,
expected: 1,
},
{
x: 1,
expected: 2,
},
{
x: 2,
expected: 4,
},
{
x: 3,
expected: 8,
},
}
for _, tt := range tests {
result := Pow2(tt.x)
if result != tt.expected {
t.Errorf("Pow2(%d) = %d, expected %d", tt.x, result, tt.expected)
}
}
}
func TestGCD(t *testing.T) {
tests := []struct {
a int
b int
expected int
}{
{
a: 0,
b: 0,
expected: 0,
},
{
a: 0,
b: 5,
expected: 5,
},
{
a: 10,
b: 5,
expected: 5,
},
{
a: 12,
b: 8,
expected: 4,
},
{
a: 15,
b: 25,
expected: 5,
},
{
a: 21,
b: 14,
expected: 7,
},
{
a: 100,
b: 75,
expected: 25,
},
}
for _, tt := range tests {
result := GCD(tt.a, tt.b)
if result != tt.expected {
t.Errorf("GCD(%d, %d) = %d, expected %d", tt.a, tt.b, result, tt.expected)
}
}
}
func TestLCM(t *testing.T) {
tests := []struct {
a int
b int
integers []int
expected int
}{
{
a: 2,
b: 3,
integers: []int{4, 5},
expected: 60,
},
{
a: 5,
b: 7,
integers: []int{10, 15},
expected: 210,
},
{
a: 12,
b: 18,
integers: []int{24, 36},
expected: 72,
},
}
for _, tt := range tests {
result := LCM(tt.a, tt.b, tt.integers...)
if result != tt.expected {
t.Errorf("LCM(%d, %d, %v) = %d, expected %d", tt.a, tt.b, tt.integers, result, tt.expected)
}
}
}
func TestAbsInt(t *testing.T) {
tests := []struct {
x int
expected int
}{
{
x: 0,
expected: 0,
},
{
x: 5,
expected: 5,
},
{
x: -10,
expected: 10,
},
{
x: 100,
expected: 100,
},
{
x: -50,
expected: 50,
},
}
for _, tt := range tests {
result := AbsInt(tt.x)
if result != tt.expected {
t.Errorf("AbsInt(%d) = %d, expected %d", tt.x, result, tt.expected)
}
}
}
func TestGaussianElimination(t *testing.T) {
coefficients := [][]float64{
{2, 1, -1},
{-3, -1, 2},
{-2, 1, 2},
}
rhs := []float64{8, -11, -3}
expected := []float64{2, 3, -1}
gaussianElimination(coefficients, rhs)
for i := 0; i < len(rhs); i++ {
if rhs[i] != expected[i] {
t.Errorf("GaussianElimination failed. Expected %v, got %v", expected, rhs)
break
}
}
}

@ -0,0 +1,66 @@
package math
type Matrix[T comparable] [][]T
// Transpose returns the transpose of the matrix.
func (m Matrix[T]) Transpose() Matrix[T] {
xl := len(m[0])
yl := len(m)
result := make([][]T, xl)
for i := range result {
result[i] = make([]T, yl)
}
for i := 0; i < xl; i++ {
for j := 0; j < yl; j++ {
result[i][j] = m[j][i]
}
}
return result
}
// RotateClockwise rotates the matrix clockwise by 90 degrees.
// It returns a new matrix with the rotated values.
func (m Matrix[T]) RotateClockwise() Matrix[T] {
xl := len(m[0])
yl := len(m)
result := make([][]T, xl)
for i := range result {
result[i] = make([]T, yl)
}
for row := 0; row < yl; row++ {
for col := 0; col < xl; col++ {
result[col][yl-1-row] = m[row][col]
}
}
return result
}
// Duplicate creates a duplicate of the matrix.
// It returns a new matrix with the same values as the original matrix.
func (m Matrix[T]) Duplicate() Matrix[T] {
duplicate := make([][]T, len(m))
for i := range m {
duplicate[i] = make([]T, len(m[i]))
copy(duplicate[i], m[i])
}
return duplicate
}
// Equal checks if the current matrix is equal to the given matrix.
// It returns true if the matrices are equal, and false otherwise.
func (matrix1 Matrix[T]) Equal(matrix2 Matrix[T]) bool {
if len(matrix1) != len(matrix2) || len(matrix1[0]) != len(matrix2[0]) {
return false
}
for i := 0; i < len(matrix1); i++ {
for j := 0; j < len(matrix1[0]); j++ {
if matrix1[i][j] != matrix2[i][j] {
return false
}
}
}
return true
}

@ -0,0 +1,113 @@
package math
import (
"reflect"
"testing"
)
func TestRotateClockwise(t *testing.T) {
matrix := Matrix[int]{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
expected := Matrix[int]{
{7, 4, 1},
{8, 5, 2},
{9, 6, 3},
}
result := matrix.RotateClockwise()
if !reflect.DeepEqual(result, expected) {
t.Errorf("RotateClockwise() = %v, want %v", result, expected)
}
}
func TestTranspose(t *testing.T) {
matrix := Matrix[int]{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
expected := Matrix[int]{
{1, 4, 7},
{2, 5, 8},
{3, 6, 9},
}
result := matrix.Transpose()
if !reflect.DeepEqual(result, expected) {
t.Errorf("Transpose() = %v, want %v", result, expected)
}
}
func TestDuplicate(t *testing.T) {
matrix := Matrix[int]{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
expected := Matrix[int]{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
result := matrix.Duplicate()
if !reflect.DeepEqual(result, expected) {
t.Errorf("Duplicate() = %v, want %v", result, expected)
}
}
func TestEqual(t *testing.T) {
matrix1 := Matrix[int]{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
matrix2 := Matrix[int]{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
if !matrix1.Equal(matrix2) {
t.Errorf("Equal() = false, want true")
}
matrix3 := Matrix[int]{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
}
matrix4 := Matrix[int]{
{1, 2, 3},
{4, 5, 6},
{7, 8, 0},
}
if matrix3.Equal(matrix4) {
t.Errorf("Equal() = true, want false")
}
matrix5 := Matrix[int]{
{1, 2},
{3, 4},
}
matrix6 := Matrix[int]{
{1, 2, 3},
{4, 5, 6},
}
if matrix5.Equal(matrix6) {
t.Errorf("Equal() = true, want false")
}
}

@ -0,0 +1,71 @@
// Package parse provides utility functions for parsing and reading data from files.
package parse
import (
"bufio"
"log"
"os"
"strconv"
"strings"
"golang.org/x/exp/constraints"
)
// ReadLines reads all lines from a file specified by fileName and returns them as a slice of strings.
func ReadLines(fileName string) []string {
result := []string{}
file, err := os.Open(fileName)
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
result = append(result, scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
return result
}
// ParseIntArray parses a string containing integer values separated by a specified separator and returns a slice of integers.
func ParseIntArray[T constraints.Integer](s string, sep string) []T {
result := []T{}
var vals []string
if sep == " " {
vals = strings.Fields(strings.TrimSpace(s))
} else {
vals = strings.Split(strings.TrimSpace(s), sep)
}
for _, val := range vals {
n, e := strconv.ParseInt(strings.TrimSpace(val), 10, 64)
if e != nil {
log.Fatal(e)
}
result = append(result, T(n))
}
return result
}
// SplitNoBlank splits a string by a specified separator and returns a slice of the non-empty parts.
func SplitNoBlank(s string, sep string) []string {
splitted_line := strings.Split(s, sep)
result := []string{}
for _, part := range splitted_line {
if part != "" {
result = append(result, part)
}
}
return result
}

@ -0,0 +1,136 @@
package parse
import (
"os"
"reflect"
"testing"
)
func TestReadLines(t *testing.T) {
// Create a temporary file and write some lines to it
tmpFile, err := os.CreateTemp("", "testfile")
if err != nil {
t.Fatal(err)
}
defer os.Remove(tmpFile.Name())
lines := []string{
"Line 1",
"Line 2",
"Line 3",
}
for _, line := range lines {
_, err := tmpFile.WriteString(line + "\n")
if err != nil {
t.Fatal(err)
}
}
// Close the file before reading from it
err = tmpFile.Close()
if err != nil {
t.Fatal(err)
}
fileName := tmpFile.Name()
// Call the ReadLines function
result := ReadLines(fileName)
// Check if the lines read from file match the expected lines
for i, line := range result {
if line != lines[i] {
t.Errorf("Expected line %d to be '%s', but got '%s'", i+1, lines[i], line)
}
}
}
func TestParseIntArray(t *testing.T) {
tests := []struct {
name string
input string
separator string
want []int64
expectFail bool
}{
{
name: "space separated",
input: "1 2 3",
separator: " ",
want: []int64{1, 2, 3},
},
{
name: "comma separated",
input: "1,2,3",
separator: ",",
want: []int64{1, 2, 3},
},
{
name: "with leading/trailing spaces",
input: " 1, 2, 3 ",
separator: ",",
want: []int64{1, 2, 3},
},
{
name: "empty string",
input: "",
separator: ",",
want: []int64{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ParseIntArray[int64](tt.input, tt.separator)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ParseIntArray() = %v, want %v",
got, tt.want)
}
})
}
}
func TestSplitNoBlank(t *testing.T) {
tests := []struct {
name string
input string
sep string
want []string
}{
{
name: "no blank",
input: "abc",
sep: "",
want: []string{"a", "b", "c"},
},
{
name: "with blanks",
input: "a b c",
sep: " ",
want: []string{"a", "b", "c"},
},
{
name: "leading/trailing blanks",
input: " a b c ",
sep: " ",
want: []string{"a", "b", "c"},
},
{
name: "empty string",
input: "",
sep: " ",
want: []string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := SplitNoBlank(tt.input, tt.sep)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("SplitNoBlank() = %v, want %v",
got, tt.want)
}
})
}
}
Loading…
Cancel
Save