Skip to content

Commit

Permalink
Merge pull request #134 from sandboxnu/add-back-perceptron-weights
Browse files Browse the repository at this point in the history
Add back perceptron weights
  • Loading branch information
jakeisnt authored Mar 8, 2021
2 parents 060b36b + 844b73b commit 38dd5d1
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 75 deletions.
132 changes: 58 additions & 74 deletions src/modules/perceptrons/mpNeuron/MPNeuron.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,19 @@
import React, { useEffect, useState } from 'react';
import {AddCircle, RemoveCircle} from '@material-ui/icons';
import {RblattConfig, INIT_CONFIG} from '../rosenblatt/constants';

import { AddCircle, RemoveCircle } from '@material-ui/icons';
import { INIT_CONFIG } from '../rosenblatt/constants';

export type NeuronInput = {
val: number | null,
weight: number | null
}

// todo: pass in color for things that might not go well against bg
// what labels should i do for each bubble?
// how to make function piece obviously interactable
// this can take a number => number func, use its tostring to render
const MPNeuron = (props: {labelColor: string}) => {
// react draggable?
const MPNeuron = (props: { labelColor: string }) => {
const [inputs, setInputs] = useState<NeuronInput[]>(
[{ val: 1, weight: -.5 },
{ val: 1, weight: 1 }]
// this is becoming a bias, leaving it just in case as breadcrumbs
// { val: 1, weight: .2 }]

);
const [func, setFunc] = useState(() => ((n: number) => 0));
// need to recalc output when inputs change!

const flipInput = (idx: number) => {
const newVal = inputs[idx].val === 1 ? 0 : 1;
const newInputs = [...inputs];
newInputs[idx].val = newVal;
setInputs(newInputs);
}
const changeWeight = (e: React.ChangeEvent<HTMLInputElement>, idx: number) => {
const val = parseFloat(e.target.value);
const newInputs = [...inputs];
Expand All @@ -41,6 +25,19 @@ const MPNeuron = (props: {labelColor: string}) => {
setInputs(newInputs);
}
}

const changeVal = (e: React.ChangeEvent<HTMLInputElement>, idx: number) => {
const val = parseFloat(e.target.value);
const newInputs = [...inputs];
if (!isNaN(val)) {
newInputs[idx].val = val;
setInputs(newInputs);
} else if (e.target.value === '') {
newInputs[idx].val = null;
setInputs(newInputs);
}
}

const onFuncChange = (func: (n: number) => number) => {
setFunc(() => ((n: number) => func(n)));
}
Expand All @@ -56,30 +53,21 @@ const MPNeuron = (props: {labelColor: string}) => {
}

const inputSum = inputs.reduce((prev, acc) => {
return (acc.val && acc.weight ? acc.val * acc.weight : 0) + INIT_CONFIG.bias + prev
return (acc.val && acc.weight ? acc.val * acc.weight : 0) + INIT_CONFIG.bias + prev
}, 0);
const output = func(inputSum);

const makeInput = (inpt: NeuronInput, idx: number) => {
const isOne = inpt.val === 1;
return (
<div className="flex items-center cursor-pointer">
{/* This following div is commented out since it makes the demo too complex to understand,
leaving this in as breadcrumbs.
*/}
{/* <div
className="font-bold rounded-full w-12 h-12 bg-navy m-1
flex items-center justify-center "
style={{
backgroundColor: isOne ? INPT_CLR : 'white',
border: isOne ? 'none' : `2px solid ${INPT_CLR}`,
color: isOne ? 'white' : 'black'
}}
onClick={() => flipInput(idx)}
>
{inpt.val}
</div> */}
{/* <div className="w-2 h-1 bg-navy" /> */}
<div className="m-1">
<input className="number-input w-20 h-10 border-2 border-pink-700"
type="number"
value={inpt.val !== null ? inpt.val : ''}
onChange={(e) => changeVal(e, idx)}
/>
</div>
<div className="w-10 h-1 bg-navy" />
<div className="m-1">
<input className="number-input w-20 h-10 border-2 border-pink-700"
type="number"
Expand All @@ -93,46 +81,42 @@ const MPNeuron = (props: {labelColor: string}) => {

return (
<div className="m-2 flex flex-col items-center justify-center">
<div className="flex items-center">
<div className="flex flex-col">
{inputs.map((val, idx) => makeInput(val, idx))}

<div className="flex items-center self-end">
<p className={props.labelColor}>bias</p>
<div
className="font-bold rounded-full w-12 h-12 bg-pink-700 m-1
flex items-center justify-center text-white"
>

{INIT_CONFIG.bias.toFixed(1)}
<div className="flex items-center">
<div className="flex flex-col">
{inputs.map((val, idx) => makeInput(val, idx))}
<div className="flex items-center self-end">
<p className={props.labelColor}>bias</p>
<div
className="font-bold rounded-full w-12 h-12 bg-pink-700 m-1
flex items-center justify-center text-white"
>
{INIT_CONFIG.bias.toFixed(1)}
</div>
</div>
</div>
</div>
{/* +1 to account for the bias term */}
<InputLines numInpts={inputs.length + 1} />
<div className="rounded-full w-20 h-20 bg-brightOrange
</div>
<InputLines numInpts={inputs.length + 1} />
<div className="rounded-full w-20 h-20 bg-brightOrange
flex items-center justify-center">
{inputSum}
</div>
<div className="w-2 h-1 bg-navy" />
<ThresholdFunc onFuncChange={onFuncChange} />
<div className="w-16 h-1 bg-navy" />
<div
className="rounded-full w-12 h-12 font-bold bg-moduleTeal flex items-center justify-center"
style={{
backgroundColor: output === 1 ? OUTPT_CLR : 'white',
border: output === 1 ? 'none' : `2px solid ${OUTPT_CLR}`
}}
>
{output}
{inputSum}
</div>
<div className="w-2 h-1 bg-navy" />
<ThresholdFunc onFuncChange={onFuncChange} />
<div className="w-16 h-1 bg-navy" />
<div
className="rounded-full w-12 h-12 font-bold bg-moduleTeal flex items-center justify-center"
style={{
backgroundColor: output === 1 ? OUTPT_CLR : 'white',
border: output === 1 ? 'none' : `2px solid ${OUTPT_CLR}`
}}
>
{output}
</div>
</div>
</div>
{/* Removed for now since it makes the example too complex */}
{/* <div>
<div>
<RemoveCircle className="icon-button" fontSize="large" onClick={removeInput}/>
<p className="inline m-2 text-white">{inputs.length} inputs</p>
<AddCircle className="icon-button" fontSize="large" onClick={addInput}/>
</div> */}
</div>
</div>
);
}
Expand Down Expand Up @@ -175,12 +159,12 @@ const ThresholdFunc = (props: { onFuncChange: ((func: (n: number) => number) =>
}, [isGreater, threshold])

return (
<div className="font-bold w-20 h-10 rounded-md border-2 border-orange-500
<div className="font-bold w-20 h-10 rounded-md border-2 border-orange-500
flex items-center justify-center px-2 text-white">
<div className="cursor-pointer"
onClick={() => setIsGreater(!isGreater)}
>
{isGreater ? '>' : '<'}
{isGreater ? '>' : '<'}
</div>
<input className="number-input w-10 border-0 bg-transparent"
type="number"
Expand All @@ -198,4 +182,4 @@ const ThresholdFunc = (props: { onFuncChange: ((func: (n: number) => number) =>
const INPT_CLR = '#b92079';
const OUTPT_CLR = '#0FD4C0';

export default MPNeuron;
export default MPNeuron;
2 changes: 1 addition & 1 deletion src/modules/perceptrons/rosenblatt/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

const INIT_CONFIG = { weightX: .7, weightY: -1, bias: 0 , learningRate: .1 };
const INIT_CONFIG = { weightX: .7, weightY: -1, bias: 10, learningRate: .1 };
const INIT_INPUTS: RblattInput[] = [
{ x: 2.101231155778894, y: 4.947319932998326, z: 0 },
{ x: 8.27, y: -3.94, z: 0 },
Expand Down

0 comments on commit 38dd5d1

Please sign in to comment.