From ae253af15f9968a85e46c9dd6f5cf4132fa61f03 Mon Sep 17 00:00:00 2001 From: filifa Date: Sat, 24 Jan 2026 16:42:48 -0500 Subject: [PATCH] add convolve command --- cmd/common.go | 32 ++++++++++++ cmd/convolve.go | 110 +++++++++++++++++++++++++++++++++++++++ cmd/shoelace.go | 11 ---- internal/lib/convolve.go | 32 ++++++++++++ 4 files changed, 174 insertions(+), 11 deletions(-) create mode 100644 cmd/common.go create mode 100644 cmd/convolve.go create mode 100644 internal/lib/convolve.go diff --git a/cmd/common.go b/cmd/common.go new file mode 100644 index 0000000..2ab9efa --- /dev/null +++ b/cmd/common.go @@ -0,0 +1,32 @@ +/* +Copyright © 2026 filifa + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +package cmd + +import ( + "bufio" + "os" +) + +func splitLines(file *os.File) []string { + slice := make([]string, 0) + scanner := bufio.NewScanner(file) + for scanner.Scan() { + slice = append(slice, scanner.Text()) + } + + return slice +} diff --git a/cmd/convolve.go b/cmd/convolve.go new file mode 100644 index 0000000..7ce2573 --- /dev/null +++ b/cmd/convolve.go @@ -0,0 +1,110 @@ +/* +Copyright © 2026 filifa + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +package cmd + +import ( + "bufio" + "fmt" + "os" + "strconv" + + "github.com/spf13/cobra" + "scm.dairydemon.net/filifa/mathtools/internal/lib" +) + +var convolveA string +var convolveB string + +func readSequenceFromFile(filepath string) ([]complex128, error) { + // initial length 1 so index math works + seq := make([]complex128, 1) + file, err := os.Open(filepath) + if err != nil { + return seq, err + } + defer file.Close() + + lines := splitLines(file) + for _, line := range lines { + x, err := strconv.ParseComplex(line, 128) + if err != nil { + return seq, err + } + + seq = append(seq, x) + } + + return seq, nil +} + +func convolve(cmd *cobra.Command, args []string) { + a, err := readSequenceFromFile(convolveA) + if err != nil { + cobra.CheckErr(err) + } + + b, err := readSequenceFromFile(convolveB) + if err != nil { + cobra.CheckErr(err) + } + + bufStdout := bufio.NewWriter(os.Stdout) + defer bufStdout.Flush() + + for i, n := range lib.DirichletConvolve(a, b) { + if i == 0 { + continue + } + + if imag(n) == 0 { + fmt.Fprintln(bufStdout, real(n)) + } else { + fmt.Fprintln(bufStdout, n) + } + } +} + +// convolveCmd represents the convolve command +var convolveCmd = &cobra.Command{ + Use: "convolve", + Short: "Compute the Dirichlet convolution of two sequences", + Long: `Compute the Dirichlet convolution of two sequences. + +Each sequence is provided as a file, where line k of the file gives the kth term of the sequence. +`, + Run: convolve, +} + +func init() { + rootCmd.AddCommand(convolveCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // convolveCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // convolveCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + convolveCmd.Flags().StringVarP(&convolveA, "first", "a", "", "first sequence") + convolveCmd.MarkFlagRequired("first") + + convolveCmd.Flags().StringVarP(&convolveB, "second", "b", "", "second sequence") + convolveCmd.MarkFlagRequired("second") +} diff --git a/cmd/shoelace.go b/cmd/shoelace.go index 6652267..c76ec38 100644 --- a/cmd/shoelace.go +++ b/cmd/shoelace.go @@ -17,7 +17,6 @@ along with this program. If not, see . package cmd import ( - "bufio" "fmt" "os" "strconv" @@ -29,16 +28,6 @@ import ( var shoelaceFile string -func splitLines(file *os.File) []string { - slice := make([]string, 0) - scanner := bufio.NewScanner(file) - for scanner.Scan() { - slice = append(slice, scanner.Text()) - } - - return slice -} - func readFromFile(filepath string) ([]lib.Point, error) { points := make([]lib.Point, 0) file, err := os.Open(filepath) diff --git a/internal/lib/convolve.go b/internal/lib/convolve.go new file mode 100644 index 0000000..2931ff1 --- /dev/null +++ b/internal/lib/convolve.go @@ -0,0 +1,32 @@ +/* +Copyright © 2026 filifa + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +package lib + +func DirichletConvolve(a, b []complex128) []complex128 { + c := make([]complex128, min(len(a), len(b))) + for i, x := range a { + for j, y := range b { + if i*j >= len(c) { + break + } + + c[i*j] += x * y + } + } + + return c +}