diff --git a/.gitignore b/.gitignore index 9187794..223cdfa 100644 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,6 @@ replay_pid* .DS_Store # Render files -*.pdf *tmp.html # Folders that will not be committed to the repo, even if private diff --git a/CHANGELOG.md b/CHANGELOG.md index a519dfd..3a02fb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,42 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Calendar Versioning](https://calver.org/) of the following form: YYYY.0M.0D. +## 2025.12.09 + +### Added + +- Designed test suite for Neuron component +- Designed two different use cases for Neuron component + +### Updated + +- Edited folder hierarchy to make more sense + +## 2025.11.23 + +### Added + +- Created the kernel implementation for the Artifical Neuron component + +## 2025.11.11 + +### Added + +- Designed kernel and enhanced interfaces for the Artifical Neuron component +- Created an abstract class for Neuron (NeuronSecondary), implementing both common and secondary methods + +### Updated + +- Changed design to include queues representing each set of weights and inputs +- Fixed naming of interfaces to better match the convention +- Changed some data types within methods in order to better execute the component's function + +## 2025.10.17 + +### Added + +- Designed a proof of concept for an Artificial Neuron component + ## 2025.09.21 ### Added diff --git a/README.md b/README.md index 14aa94d..3e74b0c 100644 --- a/README.md +++ b/README.md @@ -1,90 +1,9 @@ -# Portfolio Project +## Artificial Neuron Component -The purpose of this repo is to provide a framework for creating your own -component in the software sequence discipline. If you were unsure whether -or not to make your own, consider the following testimonial: +This component was created following the OSU Software Sequence discipline, as a part of Software 2 (CSE 2231). -> I really enjoyed the portfolio project! It gave me a stronger understanding -> of the OSU software discipline while also giving me the flexibility to -> design something that reflected my interests. This made the experience -> rewarding and enjoyable as I created a product I was proud of! +The Artificial Neuron has roots in early machine learning, where computer scientists created simple "perceptrons" that could output either true/false values according to a statistical formula. When hundreds, or millions, or billions of these perceptrons were put together, machines could recognize patterns and even predict changes. -## Recommended Steps to Get Started +This component takes on this early machine learning concept, modeling the functionality of a perceptron by outputting a true/false value depending on the result of a formula. The formula used is a sigmoid activation function, which is one of the simplest statistical models used in machine learning. -When starting your portfolio project, the following steps should make your life -a bit easier. -### Step 1: Create a Repo From This Template - - - -Assuming you're reading this README from GitHub, you can make use of this -repo by clicking the `Use this template` button in the top-right corner of -this page. If you can't find the button, [this link][use-this-template] -should work as well. Personally, I would recommend using the -`Create a new repository` option, which will allow you to name the -repository after your component. Given that you will be submitting pull -requests to me through Carmen, you'll want to make sure your repository -is public. Then, you can click `Create repository`. After that, you can -go through all the usual steps of cloning a repository on your system to -get to work. I use GitHub Desktop to clone projects, and it has a nice -feature of letting you open a repo directly in VSCode from the -`Repository` menu. - -### Step 2: Install Recommended Plugins - - - -When you open VSCode with this project, you should get a notification in the -bottom right corner that there are some recommended extensions to install. -Click install all. If you ignored this message or it never came up, feel free -to press CTRL+SHIFT+P and type "Show Recommended Extensions". Install all of the -extensions listed. - -### Step 3: Install the Latest JDK - - - -If you do not have an available JDK on your system, you may be prompted to -install one by VSCode. The default seems to be Red Hat's OpenJDK, which seems to -require you to register for an account or to install on the command line. -Regardless, there is no mac support. As a result, I would just recommend -installing the latest JDK [directly from Oracle's site][jdk-downloads]. - -### Step 4: Add Key Libraries to Project - - - -As you are probably all aware at this point, you need the components jar to get -anything running. My advice is to [download it from here][components-jar]. Then, -drop it into the `lib` folder in the project. Git automatically ignores anything -you put here by default, so don't worry about committing it to version control. - -Similarly, you will need the testing APIs (e.g., JUnit). Perhaps the easiest way -to include them in your project is to click the beaker symbol in the left -sidebar; it's right below the extensions button which looks like four squares. -If you do not see this button, try creating a Java file in `src`. From there, -you can click "Enable Java Tests" and then click "JUnit" from the -dropdown. That's it! You should now see the two JUnit libraries in the lib -folder. - -**Note**: if you're using VSCode for class projects, you might be wondering -why you never had to do this. In general, it's bad practice to commit binaries -to version control. However, we have no way of managing dependencies with the -custom `components.jar`, so I included them directly in the template. I did not -include them here, so you could see how it might be done from scratch. If at any -point you're struggling with Step 3, just copy the lib folder from the monorepo -template. - -## Next Steps - - - -Now that you have everything setup, you can begin crafting your component. There -will be deadlines for each step in Carmen, but you're free to complete each step -as early as you'd like. To start, you'll want to visit the [doc](doc/) directory -for each assignment file. - -[components-jar]: https://cse22x1.engineering.osu.edu/common/components.jar -[jdk-downloads]: https://www.oracle.com/java/technologies/downloads/ -[use-this-template]: https://github.com/new?template_name=portfolio-project&template_owner=jrg94 diff --git a/doc/01-component-brainstorming/01-component-brainstorming.pdf b/doc/01-component-brainstorming/01-component-brainstorming.pdf new file mode 100644 index 0000000..f977e74 Binary files /dev/null and b/doc/01-component-brainstorming/01-component-brainstorming.pdf differ diff --git a/doc/02-component-proof-of-concept/02-component-proof-of-concept.md b/doc/02-component-proof-of-concept/02-component-proof-of-concept.md index 6eac4a8..e4f28db 100644 --- a/doc/02-component-proof-of-concept/02-component-proof-of-concept.md +++ b/doc/02-component-proof-of-concept/02-component-proof-of-concept.md @@ -1,13 +1,11 @@ # Portfolio Part 2: Component Proof-of-Concept -- **Name**: -- **Dot Number**: -- **Due Date**: +- **Name**: Grace Metz +- **Dot Number**: Metz.403 +- **Due Date**: 10/9/25 ## Assignment Overview - - Previously, you brainstormed three ideas, and hopefully you got some feedback as well. However, it's impossible to know how reasonable your design actually is without trying to implement it. Because you're only just learning our full @@ -30,8 +28,6 @@ the more work you can put in now, the better. ## Assignment Checklist - - To be sure you have completed everything on this assignment, we have littered this document with TODO comments. You can browse all of them in VSCode by opening the TODOs window from the sidebar. The icon looks like a tree and will @@ -53,8 +49,6 @@ to the tree diagram (you may remove this one as well): ## Assignment Learning Objectives - - Without learning objectives, there really is no clear reason why a particular assessment or activity exists. Therefore, to be completely transparent, here is what we're hoping you will learn through this particular aspect of the portfolio @@ -68,8 +62,6 @@ project. Specifically, students should be able to: ## Assignment Rubric: 10 Points - - Again, to be completely transparent, most of the portfolio project, except the final submission, is designed as a formative assessment. Formative assessments are meant to provide ongoing feedback in the learning process. Therefore, @@ -114,8 +106,7 @@ Below is further rationale/explanation for the rubric items above: > to create a new design. In you do end up picking one at random, you should > disclose that here as well. - +I believe that the artificial neuron is the one that is the most interesting to me personally, and I also believe that, minus some need for research on machine learning algorithms, the component would likely be fairly simple to implement. At the most basic level, it essentially functions as a calculator; evaluating values based on a pre-set formula and outputting a result. > Once you've argued your choice of design, make a branch in your new repo called > something like `proof-of-concept`. There are many ways to do this, but my @@ -126,8 +117,6 @@ new; then delete this comment --> > we'll want a branch that you can later make a pull request from with all > your changes. - - ## Assignment Tasks As stated previously, your goal with this assignment is to produce a Java @@ -153,8 +142,6 @@ completed the assignment. ### Changelog - - At the end of every assignment, you should update the [CHANGELOG.md](../../CHANGELOG.md) file found in the root of the project folder. Here's what I would expect to see at the minimum: diff --git a/doc/03-component-interfaces/03-component-interfaces.md b/doc/03-component-interfaces/03-component-interfaces.md index c1f96cd..82144e8 100644 --- a/doc/03-component-interfaces/03-component-interfaces.md +++ b/doc/03-component-interfaces/03-component-interfaces.md @@ -1,8 +1,8 @@ # Portfolio Part 3: Component Interfaces -- **Name**: -- **Dot Number**: -- **Due Date**: +- **Name**: Grace Metz +- **Dot Number**: metz.403 +- **Due Date**: 10/23 12:40pm ## Assignment Overview @@ -132,7 +132,7 @@ hierarchy diagram using whatever tools you would like. Then, include a picture of it in this folder. You may also embed it just below using markdown syntax (i.e., `![ALT TEXT](path/to/file)`). - +![Interfaces Diagram](doc\03-component-interfaces\Interfaces (1).pdf) To start making your interfaces, make a branch off of main in your new repo called something like `interfaces`. There are many ways to do this, but my @@ -154,8 +154,6 @@ to see them. If you don't like this workflow, you may try following the rebase strategies described [here](https://stackoverflow.com/questions/35790561/working-while-waiting-for-pending-pr) and [here](https://stackoverflow.com/questions/18021888/continue-working-on-a-git-branch-after-making-a-pull-request). - - ## Assignment Tasks Your primary task for this assignment is to draft two interfaces in line with diff --git a/doc/03-component-interfaces/03-component-interfaces.pdf b/doc/03-component-interfaces/03-component-interfaces.pdf new file mode 100644 index 0000000..cb2d624 Binary files /dev/null and b/doc/03-component-interfaces/03-component-interfaces.pdf differ diff --git a/doc/03-component-interfaces/Interfaces.pdf b/doc/03-component-interfaces/Interfaces.pdf new file mode 100644 index 0000000..01a1a0f Binary files /dev/null and b/doc/03-component-interfaces/Interfaces.pdf differ diff --git a/doc/05-component-kernel-implementation/05-component-kernel-implementation.pdf b/doc/05-component-kernel-implementation/05-component-kernel-implementation.pdf new file mode 100644 index 0000000..46a5226 Binary files /dev/null and b/doc/05-component-kernel-implementation/05-component-kernel-implementation.pdf differ diff --git a/doc/06-component-finishing-touches/06-component-finishing-touches.md b/doc/06-component-finishing-touches/06-component-finishing-touches.md index 4a2aeda..372d99d 100644 --- a/doc/06-component-finishing-touches/06-component-finishing-touches.md +++ b/doc/06-component-finishing-touches/06-component-finishing-touches.md @@ -1,8 +1,8 @@ # Portfolio Part 6: Finishing Touches -- **Name**: -- **Dot Number**: -- **Due Date**: +- **Name**: Grace Metz +- **Dot Number**: Metz.403 +- **Due Date**: 12/9/2023 ## Assignment Overview @@ -307,18 +307,18 @@ Take some time to fill them out honestly. > complete the portfolio project, how much better (or worse) do you think you > understand software development and why? - +This project definitely helped me to better understand the software development process, and I hope to continue applying these skills in the future. Even though the material presented in class and throughout the projects may allude to some of the skills needed in the portfolio project, I think that this was a great opportunity to learn more about the software life cycle in a "real world" setting, while still using a familiar API. > Also, did the portfolio project surface any gaps in your own knowledge of > software development. If so, what are those gaps and how did you address them? - +While developing the NeuronSecondary class, I realized that I wasn't too confident in my understanding of abstract classes and how they worked. To remedy this, I looked at examples of abstract classes in the OSU API and compared those implementations with the class slides. > Finally, as a part of completing the portfolio project, to what extent has > your perspective of software development changed, if at all? In other words, > is software development something you still enjoy? If not, why not? - +I enjoy software development still, even though I am excited to see what's out there besides the OSU way of doing things. For my job, I use SQL and Python and enjoy the process of writing programs using those tools. By completing this project, my perspective has changed in the positive direction, but I'd like to continue learning before coming to a final verdict. > One of the challenges of completing the portfolio project is picking up a lot > of skills on your own. Some of these skills are, of course, software skills. @@ -326,25 +326,34 @@ Take some time to fill them out honestly. > this process. Therefore, the first question is what skills did you pick up > through this process? - +Some skills that I picked up: +- Branch handling, making pull requests using GitHub/Git +- Writing software that layers on itself in a way that somehow works +- Using a basic statistical model for artificial neuron activation +- Using an artificial neuron for different tasks +- Updating and maintaining a changelog for projects > The follow-up question is: could you rephrase these skills you picked up > as bullet points that you could put on a resume? Try it below. - +- Utilized Git for version control +- Wrote clean, production-ready software in adherence to OSU Software Sequence principles +- Applied knowledge of statistical models to a machine learning context +- Developed demo programs to showcase the artificial neuron's use cases +- Updated and maintained an accessible changelog and documentation > Next, how has working on this project affected your career trajectory? > In other words, do you now hate the topic you picked? Or, are you even more > interested in it? Both outcomes are valuable to your personal development. - +I am interested in machine learning as I believe that it is a useful field of study that has the potential to help many people. By making an artificial neuron and using it in different ways, I picked up some knowledge on statistics and logic that will be helpful in the future. Overall, I'm excited to continue learning. > Finally, consider the skills you've picked up and your current career > trajectory. What are some things you could do to continue on your > career trajectory? Also, who are some mentors you could contact to help > you stay on your path? - +I currently am working as a Product Intern for a healthcare company, and that is the field that I want to stay in for my future career. To stay up to date on the skills that I need, I can pursue certifications or courses in things like cybersecurity or data science. I can also gain mentorship from my bosses and engineers on my team, as well as other interns who may be further along in college or in their careers than I am. ### Changelog diff --git a/src/NeuronDemoConsole.java b/src/NeuronDemoConsole.java new file mode 100644 index 0000000..22d7459 --- /dev/null +++ b/src/NeuronDemoConsole.java @@ -0,0 +1,61 @@ +import java.util.Scanner; + +import components.neuron.Neuron; +import components.neuron.Neuron1; + +/** + * Very simple implementation of the methods in the Artificial Neuron component. + * This demo uses the console as the source of input/output. + * + * @author Grace Metz + * + */ +public final class NeuronDemoConsole { + + /** + * To prevent instantiation. + */ + private NeuronDemoConsole() { + } + + /** + * Main. + * + * @param args + */ + public static void main(String[] args) { + // Decide whether today is a good day to go windsurfing + // (conditions should be sunny and windy) + + Scanner in = new Scanner(System.in); + + Neuron windsurfingDecider = new Neuron1(); + + System.out.println( + "Please enter a word that describes today's weather: "); + windsurfingDecider.setInput(in.nextLine()); + System.out.println( + "Please enter how good that condition is for windsurfing (-1 to 1): "); + windsurfingDecider.setWeight(Double.parseDouble(in.nextLine())); + + System.out.println("Enter another word? (y/n): "); + String loop = in.nextLine(); + + while (loop.equals("Y")) { + System.out.println( + "Please enter a word that describes today's weather: "); + windsurfingDecider.setInput(in.nextLine()); + System.out.println( + "Please enter how good that condition is for windsurfing (-1 to 1): "); + windsurfingDecider.setWeight( + Double.parseDouble(in.nextLine())); + System.out.println("Enter another word? (y/n): "); + loop = in.nextLine(); + } + + System.out.println("Today is a good day for windsurfing: "); + System.out.println(windsurfingDecider.activate()); + + in.close(); + } +} diff --git a/src/NeuronDemoNetwork.java b/src/NeuronDemoNetwork.java new file mode 100644 index 0000000..8a25005 --- /dev/null +++ b/src/NeuronDemoNetwork.java @@ -0,0 +1,93 @@ +import components.map.Map; +import components.map.Map1L; +import components.neuron.Neuron; +import components.neuron.Neuron1; + +/** + * Demonstration of how multiple neurons may interact, using a {@code Map} for + * input. + * + * A library is trying to decide whether or not they should get rid of a section + * of books. They've condensed each section into the books' titles and weights + * representing their ratings. + * + * A very small neural network will determine whether or not they should get rid + * of one, or multiple, section(s). + * + * @author Grace Metz + * + */ +public final class NeuronDemoNetwork { + + /** + * To prevent instantiation. + */ + private NeuronDemoNetwork() { + } + + /** + * Populate a Neuron object with inputs and weights from a Map. + * + * @param section + * the map of inputs and weights + * @requires {@code |section| >= 0} + * @ensures {@code populateNeurons = + * the corresponding Neuron with inputs and weights populated} + * @return a Neuron with inputs and weights populated according to the + * section Map + */ + public static Neuron populateNeurons(Map section) { + Neuron sectionNeuron = new Neuron1(); + + for (Map.Pair pair : section) { + sectionNeuron.setInput(pair.key()); + sectionNeuron.setWeight(pair.value()); + } + + return sectionNeuron; + } + + /** + * Main. + * + * @param args + */ + public static void main(String[] args) { + Map section1 = new Map1L<>(); + Map section2 = new Map1L<>(); + Map section3 = new Map1L<>(); + + // For the sake of this example, three titles were chosen at + // random from each section, along with their ratings, + // in order to make this decision + String[] section1Titles = { "Lord of the Rings", "Harry Potter", + "Wildwood" }; + String[] section2Titles = { "The Great Gatsby", + "The Catcher in the Rye", "1984" }; + String[] section3Titles = { + "Do Androids Dream of Electric Sheep?", + "Bladerunner", "The Hunger Games" }; + + double[] section1Weights = { 0.5, 1, -0.2 }; + double[] section2Weights = { 0.1, -0.1, 0.2 }; + double[] section3Weights = { 0.3, 0.7, 0.9 }; + + for (int i = 0; i < section1Titles.length; i++) { + section1.add(section1Titles[i], section1Weights[i]); + section2.add(section2Titles[i], section2Weights[i]); + section3.add(section3Titles[i], section3Weights[i]); + } + + Neuron neuronOne = populateNeurons(section1); + Neuron neuronTwo = populateNeurons(section2); + Neuron neuronThree = populateNeurons(section3); + + System.out.println("Should we get rid of a section?: "); + if (neuronOne.activate() && neuronTwo.activate() + && neuronThree.activate()) { + System.out.print("No"); + } else { + System.out.print("Yes"); + } + } +} diff --git a/src/components/neuron/Neuron.java b/src/components/neuron/Neuron.java new file mode 100644 index 0000000..8b1abe2 --- /dev/null +++ b/src/components/neuron/Neuron.java @@ -0,0 +1,40 @@ +package components.neuron; + +/** + * Interface for additional methods within the Artificial Neuron component. + * + * @author Grace Metz + * + */ +public interface Neuron extends NeuronKernel { + + /** + * Using the sigmoid activation function: an output >= 0.5 means a yes, or + * the neuron has fired. + * + * @requires {@code |this.weights| >= 0 && |this.inputs| >= 0} + * @ensures {@code = true || false} + * @return whether the neuron has fired. + */ + boolean activate(); + + /** + * Set an object's weight and ensure that it is usable by the neuron. + * + * @param value + * the weight being entered + * @requires {@code -1 <= value <= 1} + * @ensures {@code this.weights = #this.weights * #value} + */ + void setWeight(double value); + + /** + * Sum the weights. + * + * @requires {@code |this.weights| >= 0} + * @ensures {@code sum = this.weights[0] + ... + this.weights[|this.weights|]} + * @return the sum of the weights. + */ + double sum(); + +} diff --git a/src/components/neuron/Neuron1.java b/src/components/neuron/Neuron1.java new file mode 100644 index 0000000..f208ea1 --- /dev/null +++ b/src/components/neuron/Neuron1.java @@ -0,0 +1,79 @@ +package components.neuron; + +import components.queue.Queue; +import components.queue.Queue1L; + +/** + * {@code Neuron} represented as multiple {@link Queue}s with implementations of + * primary methods. + * + * @convention [$this.inputs is a queue of String inputs] and [$this.weights is + * a queue of double weights] + * @correspondence this = ($this.inputs, $this.weights) + */ +public class Neuron1 extends NeuronSecondary { + + /** + * Queue of Strings to represent the values of each input. + */ + private Queue inputs = new Queue1L<>(); + + /** + * Queue of values to represent the weights of each input. + */ + private Queue weights = new Queue1L<>(); + + /** + * Creator of initial representation. + */ + private void createNewRep() { + this.inputs = new Queue1L<>(); + this.weights = new Queue1L<>(); + } + + /** + * No-argument constructor. + */ + public Neuron1() { + this.createNewRep(); + } + + @Override + public final Queue weights() { + return this.weights; + } + + @Override + public final Queue inputs() { + return this.inputs; + } + + @Override + public final void setInput(String value) { + assert value != null; + this.inputs.enqueue(value); + } + + @Override + public final void clear() { + this.createNewRep(); + } + + @Override + public final Neuron newInstance() { + try { + return this.getClass().getConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new AssertionError( + "Cannot construct object of type " + this.getClass()); + } + } + + @Override + public final void transferFrom(Neuron arg0) { + Neuron local = (Neuron) arg0; + this.inputs = local.inputs(); + this.weights = local.weights(); + local.clear(); + } +} diff --git a/src/components/neuron/NeuronKernel.java b/src/components/neuron/NeuronKernel.java new file mode 100644 index 0000000..95f9030 --- /dev/null +++ b/src/components/neuron/NeuronKernel.java @@ -0,0 +1,43 @@ +package components.neuron; + +import components.queue.Queue; +import components.standard.Standard; + +/** + * Interface for the essential methods and values within the Artificial Neuron + * component. + * + * @author Grace Metz + * + */ +public interface NeuronKernel extends Standard { + + /** + * Retrieve the weight assigned to the inputs within this node. + * + * @requires {@code |weights| >= 0} + * @ensures {@code = weights} + * @return the queue of weight values + */ + Queue weights(); + + /** + * Return the inputs entered into the neuron. + * + * @requires {@code |inputs| >= 0} + * @ensures {@code = inputs} + * @return the queue of input Strings + */ + Queue inputs(); + + /** + * Ensure that inputs are valid and usable by the neuron. + * + * @param value + * the String value being entered + * @requires {@code != null} + * @ensures {@code = #inputs * #value} + */ + void setInput(String value); + +} diff --git a/src/components/neuron/NeuronSecondary.java b/src/components/neuron/NeuronSecondary.java new file mode 100644 index 0000000..0f8f952 --- /dev/null +++ b/src/components/neuron/NeuronSecondary.java @@ -0,0 +1,111 @@ +package components.neuron; + +import components.queue.Queue; +import components.queue.Queue1L; + +/** + * Interface for additional methods within the Artificial Neuron component. + * + * @author Grace Metz + * + */ +public abstract class NeuronSecondary implements Neuron { + + /** + * Queue of Strings to represent the values of each input. + */ + private Queue inputs = new Queue1L(); + + /** + * Queue of values to represent the weights of each input. + */ + private Queue weights = new Queue1L(); + + /** + * Using the sigmoid activation function: an output >= 0.5 means a yes, or + * the neuron has fired. + * + * @requires {@code |this.weights| >= 0 && |this.inputs| >= 0} + * @ensures {@code = true || false} + * @return whether the neuron has fired. + */ + @Override + public boolean activate() { + double s = 1.0 / (1.0 + Math.exp(this.sum())); + boolean fired = false; + + if (s >= 0.5) { + fired = true; + } + + return fired; + } + + /** + * Set an object's weight and ensure they are usable by the neuron. + * + * @param value + * the weight being entered + * @requires {@code -1 <= value <= 1} + * @ensures {@code this.weights = #this.weights * #value} + */ + @Override + public void setWeight(double value) { + assert value >= -1 && value <= 1; + this.weights.enqueue(value); + } + + /** + * Sum the weights. + * + * @return the sum of the weights. + */ + @Override + public double sum() { + double sum = 0; + double weight = 0; + if (this.weights.length() > 0) { + weight = this.weights.dequeue(); + sum = this.sum() + weight; + } + this.weights.enqueue(weight); + + return sum; + } + + /** + * Return the data in the Neuron component as a String. + * + * @return the String representing the Neuron. + */ + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + result.append("Neuron [weights="); + result.append(this.weights.toString()); + result.append("]"); + result.append("[inputs="); + result.append(this.inputs.toString()); + result.append("]"); + return result.toString(); + } + + /** + * Return whether or not this equals an object. + * + * @return whether this equals an object. + */ + @Override + public boolean equals(Object o) { + Neuron object = this.newInstance(); + + if (!(o == null || this.getClass() != o.getClass())) { + object = (Neuron) o; + } + + return this.weights.equals(object.weights()) + && this.inputs.equals(object.inputs()) + && this.weights.length() == object.weights().length() + && this.inputs.length() == object.inputs().length(); + } +} diff --git a/test/components/neuron/NeuronTest.java b/test/components/neuron/NeuronTest.java new file mode 100644 index 0000000..c486c7b --- /dev/null +++ b/test/components/neuron/NeuronTest.java @@ -0,0 +1,523 @@ +package components.neuron; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +/** + * JUnit test fixture for {@code Neuron}. + * + * @author Grace Metz + * + */ +public abstract class NeuronTest { + + /** + * Test constructor (only one possible constructor). + */ + @Test + public final void testConstructor() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + assertEquals(testNeuron, testNeuronExpected); + } + + /* + * Test kernel implementations + */ + + /** + * Test the weights() method where the weights should be empty. + */ + @Test + public final void testWeightsEmpty() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + assertEquals(testNeuron.weights(), testNeuronExpected.weights()); + } + + /** + * Test the weights() method where the weights have entries. + */ + @Test + public final void testWeightsFilled() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setWeight(0); + testNeuron.setWeight(0.2); + + testNeuronExpected.setWeight(0); + testNeuronExpected.setWeight(0.2); + + assertEquals(testNeuron.weights(), testNeuronExpected.weights()); + assertEquals(testNeuron.weights().length(), 2); + } + + /** + * Test the inputs() method where the inputs should be empty. + */ + @Test + public final void testInputsEmpty() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + assertEquals(testNeuron.inputs().length(), 0); + assertEquals(testNeuron.inputs(), testNeuronExpected.inputs()); + } + + /** + * Test the inputs() method where the inputs have entries. + */ + @Test + public final void testInputsFilled() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setInput("first"); + testNeuron.setInput("second"); + + testNeuronExpected.setInput("first"); + testNeuronExpected.setInput("second"); + + assertEquals(testNeuron.inputs().length(), 2); + assertEquals(testNeuron.inputs(), testNeuronExpected.inputs()); + } + + /** + * Test the setInput() method where the inputs are blank. + */ + @Test + public final void testSetInputsBlank() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setInput(""); + testNeuron.setInput(""); + + testNeuronExpected.setInput(""); + testNeuronExpected.setInput(""); + + assertEquals(testNeuron.inputs().length(), 2); + assertEquals(testNeuron.inputs(), testNeuronExpected.inputs()); + } + + /** + * Test the setInput() method where the comparison should return false. + */ + @Test + public final void testSetInputsFilled() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setInput("hi"); + testNeuron.setInput("Hello"); + + testNeuronExpected.setInput("hi"); + + assertEquals(testNeuron.inputs(), testNeuronExpected.inputs()); + } + + /** + * Test the setInput() method with a mix of blank and empty inputs. + */ + @Test + public final void testSetInputsMixed() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setInput(""); + testNeuron.setInput("Hello"); + + testNeuronExpected.setInput(""); + testNeuronExpected.setInput("Hello"); + + assertEquals(testNeuron.inputs().length(), 2); + assertEquals(testNeuron.inputs(), testNeuronExpected.inputs()); + } + + /* + * Test secondary implementations + */ + + /** + * Test the activate() method where the inputs and weights have entries. + */ + @Test + public final void testActivateFilled() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setInput("first"); + testNeuron.setInput("second"); + testNeuron.setWeight(0); + testNeuron.setWeight(0.2); + + testNeuronExpected.setInput("first"); + testNeuronExpected.setInput("second"); + testNeuronExpected.setWeight(0); + testNeuronExpected.setWeight(0.2); + + assertEquals(testNeuron.activate(), false); + assertEquals(testNeuron.activate(), testNeuronExpected.activate()); + } + + /** + * Test the activate() method where the inputs are full and weights are + * empty. + */ + @Test + public final void testActivateFullAndEmpty() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setInput("first"); + testNeuron.setInput("second"); + + testNeuronExpected.setInput("first"); + testNeuronExpected.setInput("second"); + + assertEquals(testNeuron.activate(), false); + assertEquals(testNeuron.activate(), testNeuronExpected.activate()); + } + + /** + * Test the activate() method where the weights are -1 (minimum value). + */ + @Test + public final void testActivateMin() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setWeight(-1); + testNeuron.setWeight(-1); + + testNeuronExpected.setWeight(-1); + testNeuronExpected.setWeight(-1); + + assertEquals(testNeuron.activate(), false); + assertEquals(testNeuron.activate(), testNeuronExpected.activate()); + } + + /** + * Test the activate() method where the weights are all one (highest value). + */ + @Test + public final void testActivateMax() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setWeight(1); + testNeuron.setWeight(1); + + testNeuronExpected.setWeight(1); + testNeuronExpected.setWeight(1); + + assertEquals(testNeuron.activate(), true); + assertEquals(testNeuron.activate(), testNeuronExpected.activate()); + } + + /** + * Test the setWeight() method where the weights are all negative. + */ + @Test + public final void testSetWeightNeg() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setWeight(-1); + testNeuron.setWeight(-0.5); + + testNeuronExpected.setWeight(-1); + testNeuronExpected.setWeight(-0.5); + + assertEquals(testNeuron.weights(), testNeuronExpected.weights()); + } + + /** + * Test the setWeight() method where the weights are all zero. + */ + @Test + public final void testSetWeightZero() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setWeight(0); + testNeuron.setWeight(0); + + testNeuronExpected.setWeight(0); + testNeuronExpected.setWeight(0); + + assertEquals(testNeuron.weights().length(), 2); + assertEquals(testNeuron.weights(), testNeuronExpected.weights()); + } + + /** + * Test the setWeight() method where the weights are all one (max value). + */ + @Test + public final void testSetWeightMax() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setWeight(1); + testNeuron.setWeight(1); + + testNeuronExpected.setWeight(1); + testNeuronExpected.setWeight(1); + + assertEquals(testNeuron.weights().length(), 2); + assertEquals(testNeuron.weights(), testNeuronExpected.weights()); + } + + /** + * Test the sum() method where the weights are all one (max value). + */ + @Test + public final void testSumMax() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setWeight(1); + testNeuron.setWeight(1); + + testNeuronExpected.setWeight(1); + testNeuronExpected.setWeight(1); + + assertEquals(testNeuron.sum(), 2); + assertEquals(testNeuron.weights(), testNeuronExpected.weights()); + } + + /** + * Test the sum() method where the weights are all zero. + */ + @Test + public final void testSumZero() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setWeight(0); + testNeuron.setWeight(0); + + testNeuronExpected.setWeight(0); + testNeuronExpected.setWeight(0); + + assertEquals(testNeuron.sum(), 0); + assertEquals(testNeuron.weights(), testNeuronExpected.weights()); + } + + /** + * Test the sum() method where the weights are all -1 (minimum value). + */ + @Test + public final void testSumMin() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setWeight(-1); + testNeuron.setWeight(-1); + + testNeuronExpected.setWeight(-1); + testNeuronExpected.setWeight(-1); + + assertEquals(testNeuron.sum(), -2); + assertEquals(testNeuron.weights(), testNeuronExpected.weights()); + } + + /* + * Test Standard and "base" method implementations + */ + + /** + * Test the toString() method where the weights and inputs are empty. + */ + @Test + public final void testToStringEmpty() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + String expectedString = "Neuron [weights=][inputs=]"; + + assertEquals(testNeuron.toString(), expectedString); + assertEquals(testNeuron, testNeuronExpected); + } + + /** + * Test the toString() method where the weights and inputs are filled. + */ + @Test + public final void testToStringFilled() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setInput("hi"); + testNeuron.setInput("hello"); + testNeuron.setWeight(0); + testNeuron.setWeight(1); + + testNeuronExpected.setInput("hi"); + testNeuronExpected.setInput("hello"); + testNeuronExpected.setWeight(0); + testNeuronExpected.setWeight(1); + + String expectedString = "Neuron [weights=0, 1][inputs=hi, hello]"; + + assertEquals(testNeuron.toString(), expectedString); + assertEquals(testNeuron, testNeuronExpected); + } + + /** + * Test the toString() method where the weights are empty and inputs are + * filled. + */ + @Test + public final void testToStringWeightsEmpty() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setInput("hi"); + testNeuron.setInput("hello"); + + testNeuronExpected.setInput("hi"); + testNeuronExpected.setInput("hello"); + + String expectedString = "Neuron [weights=][inputs=hi, hello]"; + + assertEquals(testNeuron.toString(), expectedString); + assertEquals(testNeuron, testNeuronExpected); + } + + /** + * Test the toString() method where the weights are filled and inputs are + * empty. + */ + @Test + public final void testToStringInputsEmpty() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setWeight(0); + testNeuron.setWeight(1); + + testNeuronExpected.setWeight(0); + testNeuronExpected.setWeight(1); + + String expectedString = "Neuron [weights=0, 1][inputs=]"; + + assertEquals(testNeuron.toString(), expectedString); + assertEquals(testNeuron, testNeuronExpected); + } + + /** + * Test the equals() method where it should return true. + */ + @Test + public final void testEqualsTrue() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + assertEquals(testNeuron.equals(testNeuronExpected), true); + assertEquals(testNeuron, testNeuronExpected); + } + + /** + * Test the equals() method where it should return false. + */ + @Test + public final void testEqualsFalse() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuronExpected.setInput("new neuron"); + testNeuronExpected.setWeight(0); + + assertEquals(testNeuron.equals(testNeuronExpected), false); + assertEquals(testNeuron, testNeuronExpected); + } + + /** + * Test the clear() method where both the weights and inputs are empty. + */ + @Test + public final void testClearEmpty() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.clear(); + + assertEquals(testNeuron, testNeuronExpected); + assertEquals(testNeuron.weights().length(), 0); + assertEquals(testNeuron.inputs().length(), 0); + } + + /** + * Test the clear() method where both the weights and inputs are full. + */ + @Test + public final void testClearFull() { + Neuron testNeuron = new Neuron1(); + Neuron testNeuronExpected = new Neuron1(); + + testNeuron.setInput("hi"); + testNeuron.setInput("hello"); + testNeuron.setWeight(0); + testNeuron.setWeight(1); + + testNeuron.clear(); + + assertEquals(testNeuron, testNeuronExpected); + assertEquals(testNeuron.weights().length(), 0); + assertEquals(testNeuron.inputs().length(), 0); + } + + /** + * Test the newInstance() method (only one possible constructor). + */ + @Test + public final void testNewInstance() { + Neuron testNeuronExpected = new Neuron1(); + Neuron testNeuron = testNeuronExpected.newInstance(); + + assertEquals(testNeuron, testNeuronExpected); + } + + /** + * Test the transferFrom() method where both weights and inputs are filled. + */ + @Test + public final void testTransferFromFilled() { + Neuron testNeuronExpected = new Neuron1(); + Neuron testNeuron = new Neuron1(); + + Neuron testNeuronTransfer = new Neuron1(); + testNeuronTransfer.setInput("new neuron"); + testNeuronTransfer.setWeight(0); + testNeuron.transferFrom(testNeuronTransfer); + + testNeuronExpected.setInput("new neuron"); + testNeuronExpected.setWeight(0); + + assertEquals(testNeuron, testNeuronExpected); + assertEquals(testNeuronTransfer.weights().length(), 0); + assertEquals(testNeuronTransfer.inputs().length(), 0); + } + + /** + * Test the transferFrom() method where both weights and inputs are empty. + */ + @Test + public final void testTransferFromEmpty() { + Neuron testNeuronExpected = new Neuron1(); + Neuron testNeuron = new Neuron1(); + + Neuron testNeuronTransfer = new Neuron1(); + testNeuron.transferFrom(testNeuronTransfer); + + assertEquals(testNeuron, testNeuronExpected); + assertEquals(testNeuronTransfer.weights().length(), 0); + assertEquals(testNeuronTransfer.inputs().length(), 0); + } + +} diff --git a/test/components/neuron/NeuronTestA.java b/test/components/neuron/NeuronTestA.java new file mode 100644 index 0000000..4c96a42 --- /dev/null +++ b/test/components/neuron/NeuronTestA.java @@ -0,0 +1,8 @@ +package components.neuron; + +/** + * Customized JUnit test fixture for {@code Neuron}. + */ +public class NeuronTestA extends NeuronTest { + +}