Compare commits
10
Commits
cb8dd97c4a
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ba30640fb | ||
|
|
633e4ab5ed | ||
|
|
3b7e6d7e4f | ||
|
|
ace3b96c67 | ||
|
|
0393893d3d | ||
|
|
5b638407f8 | ||
|
|
104f21cb98 | ||
|
|
ab21b9dfdf | ||
|
|
042333ed4b | ||
|
|
215cb69313 |
@@ -0,0 +1,3 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
||||
@@ -0,0 +1,5 @@
|
||||
[*.{js,jsx,ts,tsx,vue}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
@@ -0,0 +1,35 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true
|
||||
},
|
||||
extends: [
|
||||
'plugin:vue/essential',
|
||||
'@vue/standard',
|
||||
'@vue/typescript/recommended'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 2020
|
||||
},
|
||||
rules: {
|
||||
'space-before-function-paren': 'off',
|
||||
'no-callback-literal': 0,
|
||||
'arrow-parens': 0,
|
||||
// allow async-await
|
||||
'no-unused-vars': 0,
|
||||
'generator-star-spacing': 'off',
|
||||
'spaced-comment': 0,
|
||||
'object-curly-spacing': 0,
|
||||
'@typescript-eslint/no-empty-function': 0,
|
||||
'@typescript-eslint/no-this-alias': 0,
|
||||
'@typescript-eslint/no-var-requires': 0,
|
||||
'prefer-const': 0,
|
||||
'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }],
|
||||
camelcase: 0,
|
||||
// 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
'no-undef-init': 0,
|
||||
'no-useless-call': 0,
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
|
||||
}
|
||||
}
|
||||
+22
-4
@@ -1,5 +1,23 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# edaf
|
||||
|
||||
## Project setup
|
||||
```
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
yarn serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
yarn build
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
yarn lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
+38
-7
@@ -1,15 +1,46 @@
|
||||
{
|
||||
"name": "edaf",
|
||||
"version": "0.0.0",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build"
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.0.4"
|
||||
"@antv/g6": "^4.1.1",
|
||||
"core-js": "^3.6.5",
|
||||
"d3-force": "^2.1.1",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^3.2.0",
|
||||
"vuetify": "^2.4.2",
|
||||
"vuex": "^3.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^1.0.0-rc.13",
|
||||
"@vue/compiler-sfc": "^3.0.4"
|
||||
"@types/d3-force": "^2.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.33.0",
|
||||
"@typescript-eslint/parser": "^2.33.0",
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-plugin-router": "~4.5.0",
|
||||
"@vue/cli-plugin-typescript": "~4.5.0",
|
||||
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/eslint-config-standard": "^5.1.2",
|
||||
"@vue/eslint-config-typescript": "^5.0.2",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"less": "^3.0.4",
|
||||
"less-loader": "^5.0.0",
|
||||
"sass": "^1.19.0",
|
||||
"sass-loader": "^8.0.0",
|
||||
"typescript": "~3.9.3",
|
||||
"vue-cli-plugin-vuetify": "~2.0.9",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"vuetify-loader": "^1.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 6.9 KiB |
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
+263
-8
@@ -1,15 +1,270 @@
|
||||
<style>
|
||||
.info-div {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<img alt="Vue logo" src="./assets/logo.png" />
|
||||
<HelloWorld msg="Hello Vue 3.0 + Vite" />
|
||||
<v-app>
|
||||
<v-app-bar
|
||||
app
|
||||
color="primary"
|
||||
dark
|
||||
dense
|
||||
>
|
||||
<v-app-bar-nav-icon>
|
||||
<v-avatar size="20">
|
||||
<img
|
||||
src="/favicon.ico"
|
||||
alt="veypi"
|
||||
>
|
||||
</v-avatar>
|
||||
</v-app-bar-nav-icon>
|
||||
<v-toolbar-title>
|
||||
{{ $store.state.algorithms[$store.state.algorithm].text }}
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
append-icon="mdi-magnify"
|
||||
label="Search"
|
||||
single-line
|
||||
hide-details
|
||||
></v-text-field>
|
||||
<v-icon class="mr-5" @click="info=!info">mdi-information</v-icon>
|
||||
<v-icon class="mr-5" @click="sync">mdi-autorenew</v-icon>
|
||||
<v-btn color="warning" class="mr-5" v-if="$store.state.algorithm===0" @click="$refs.core.lay2()">计算</v-btn>
|
||||
<v-icon @click="dialog=!dialog">mdi-cog</v-icon>
|
||||
</v-app-bar>
|
||||
<v-main>
|
||||
<v-system-bar>
|
||||
<v-row class="text-center">
|
||||
<v-col>边数: {{ $store.state.edgesNum }}</v-col>
|
||||
<v-col>节点数: {{ $store.state.nodesNum }}</v-col>
|
||||
</v-row>
|
||||
</v-system-bar>
|
||||
<router-view ref="core" style="height: 100%;width: 100%"></router-view>
|
||||
</v-main>
|
||||
<div class="info-div" v-if="info">
|
||||
<v-data-table
|
||||
class="mx-auto"
|
||||
:headers="headers"
|
||||
:items="nodeList"
|
||||
:search="search"
|
||||
disable-sort
|
||||
dense
|
||||
height="300px"
|
||||
style="background: rgba(0,0,0,0.2);"
|
||||
>
|
||||
<template v-slot:item.x="{ item }">
|
||||
{{ item.x.toFixed(2) }}
|
||||
</template>
|
||||
<template v-slot:item.y="{ item }">
|
||||
{{ item.y.toFixed(2) }}
|
||||
</template>
|
||||
<template v-slot:item.act="{ item }">
|
||||
<v-btn v-if="item.color === freeC " color="warning" @click="lock(item)">固定</v-btn>
|
||||
<v-btn v-else color="primary" @click="unlock(item)">解除</v-btn>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</div>
|
||||
<v-dialog
|
||||
v-model="dialog"
|
||||
transition="dialog-bottom-transition"
|
||||
max-width="600"
|
||||
>
|
||||
<v-card>
|
||||
<v-system-bar
|
||||
color="success"
|
||||
dark
|
||||
>
|
||||
设置
|
||||
</v-system-bar>
|
||||
<v-card-text class="mt-10">
|
||||
<v-form>
|
||||
<v-select v-model="$store.state.algorithm" :items="$store.state.algorithms" label="算法"></v-select>
|
||||
<v-slider
|
||||
label="节点数量"
|
||||
class="mt-10"
|
||||
v-model="$store.state.nodesNum"
|
||||
thumb-label="always"
|
||||
:max="$store.state.algorithm ? 100: 10"
|
||||
:min="5"
|
||||
></v-slider>
|
||||
<v-slider
|
||||
:max="$store.state.nodesNum * 5"
|
||||
:min="$store.state.nodesNum * (1 + $store.state.algorithm) - 1" label="边数量" class="mt-10"
|
||||
v-model="$store.state.edgesNum" thumb-label="always"></v-slider>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HelloWorld from './components/HelloWorld.vue'
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
HelloWorld
|
||||
function uniform2NormalDistribution() {
|
||||
let sum = 0.0
|
||||
for (let i = 0; i < 12; i++) {
|
||||
sum = sum + Math.random(1)
|
||||
}
|
||||
return sum - 6.0
|
||||
}
|
||||
|
||||
function getNumberInNormalDistribution(mean, stdDev) {
|
||||
return mean + (uniform2NormalDistribution() * stdDev)
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'App',
|
||||
|
||||
components: {},
|
||||
|
||||
data: () => ({
|
||||
freeC: '#5cf43d',
|
||||
search: '',
|
||||
headers: [
|
||||
{
|
||||
text: '节点id',
|
||||
align: 'start',
|
||||
width: '60px',
|
||||
value: 'id'
|
||||
},
|
||||
{text: 'x', value: 'x', width: 60},
|
||||
{text: 'y', value: 'y', width: 60},
|
||||
{text: 'act', value: 'act'}
|
||||
],
|
||||
dialog: false,
|
||||
info: false
|
||||
//
|
||||
}),
|
||||
computed: {
|
||||
nodeList() {
|
||||
return Object.keys(this.$store.state.nodes).map(v => {
|
||||
return this.$store.state.nodes[v]
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
lock(n) {
|
||||
n.color = 'red'
|
||||
n.fx = n.x
|
||||
n.fy = n.y
|
||||
const graph = this.$refs.core.graph
|
||||
graph.updateItem(n.id, {color: n.color})
|
||||
},
|
||||
unlock(n) {
|
||||
n.color = this.freeC
|
||||
n.fx = null
|
||||
n.fy = null
|
||||
this.$refs.core.graph.updateItem(n.id, {color: n.color})
|
||||
},
|
||||
sync() {
|
||||
const edges = {}
|
||||
const nodes = {}
|
||||
for (let i = 0; i < this.$store.state.nodesNum; i++) {
|
||||
nodes['n' + i] = {
|
||||
label: 'n' + i,
|
||||
id: 'n' + i,
|
||||
// 随机布局
|
||||
color: this.freeC,
|
||||
x: i * Math.random() * 100,
|
||||
y: i * Math.random() * 100,
|
||||
size: Math.floor(Math.random() * 20) + 5
|
||||
}
|
||||
}
|
||||
// nodes.n0.color = 'red'
|
||||
// nodes.n0.fx = 100
|
||||
// nodes.n0.fy = 175
|
||||
// nodes.n0.x = 100
|
||||
// nodes.n0.y = 175
|
||||
// nodes.n1.color = 'red'
|
||||
// nodes.n1.fx = 200
|
||||
// nodes.n1.fy = 225
|
||||
// nodes.n1.x = 200
|
||||
// nodes.n1.y = 225
|
||||
// edges['0-2'] = {
|
||||
// id: '0-2',
|
||||
// source: 'n0',
|
||||
// target: 'n2',
|
||||
// value: 1
|
||||
// }
|
||||
// edges['2-3'] = {
|
||||
// id: '2-3',
|
||||
// source: 'n2',
|
||||
// target: 'n3',
|
||||
// value: 1
|
||||
// }
|
||||
// edges['3-4'] = {
|
||||
// id: '3-4',
|
||||
// source: 'n3',
|
||||
// target: 'n4',
|
||||
// value: 1
|
||||
// }
|
||||
// edges['4-1'] = {
|
||||
// id: '4-1',
|
||||
// source: 'n4',
|
||||
// target: 'n1',
|
||||
// value: 1
|
||||
// }
|
||||
let iter = 1
|
||||
for (let i = 0; i < this.$store.state.nodesNum; i++) {
|
||||
if (Object.keys(edges).length >= this.$store.state.edgesNum) {
|
||||
this.$store.state.edges = edges
|
||||
this.$store.state.nodes = nodes
|
||||
this.$refs.core.loaddata()
|
||||
return
|
||||
}
|
||||
let j = i
|
||||
while (i === j) {
|
||||
j = Math.floor(Math.random() * this.$store.state.nodesNum)
|
||||
}
|
||||
let ni = i
|
||||
if (i > j) {
|
||||
ni = j
|
||||
j = i
|
||||
}
|
||||
const v = Math.abs(Math.floor(getNumberInNormalDistribution(4, 20)))
|
||||
edges[ni + '-' + j] = {
|
||||
id: ni + '-' + j,
|
||||
source: 'n' + ni,
|
||||
target: 'n' + j,
|
||||
value: v
|
||||
}
|
||||
}
|
||||
while (iter < 10) {
|
||||
iter = iter + 1
|
||||
for (let i = 0; i < this.$store.state.nodesNum; i++) {
|
||||
for (let j = i + 1; j < this.$store.state.nodesNum; j++) {
|
||||
// const v = Math.floor(Math.random() * 10)
|
||||
const v = Math.floor(getNumberInNormalDistribution(4, 20))
|
||||
if (v > 0) {
|
||||
const id = i + '-' + j
|
||||
edges[id] = {
|
||||
id: id,
|
||||
source: 'n' + i,
|
||||
target: 'n' + j,
|
||||
value: v
|
||||
// label: v
|
||||
}
|
||||
if (Object.keys(edges).length >= this.$store.state.edgesNum) {
|
||||
this.$store.state.edges = edges
|
||||
this.$store.state.nodes = nodes
|
||||
this.$refs.core.loaddata()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.sync()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 KiB |
@@ -1,19 +1,153 @@
|
||||
<template>
|
||||
<h1>{{ msg }}</h1>
|
||||
<button @click="count++">count is: {{ count }}</button>
|
||||
<p>Edit <code>components/HelloWorld.vue</code> to test hot module replacement.</p>
|
||||
<v-container>
|
||||
<v-row class="text-center">
|
||||
<v-col cols="12">
|
||||
<v-img
|
||||
:src="require('../assets/logo.svg')"
|
||||
class="my-3"
|
||||
contain
|
||||
height="200"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col class="mb-4">
|
||||
<h1 class="display-2 font-weight-bold mb-3">
|
||||
Welcome to Vuetify
|
||||
</h1>
|
||||
|
||||
<p class="subheading font-weight-regular">
|
||||
For help and collaboration with other Vuetify developers,
|
||||
<br>please join our online
|
||||
<a
|
||||
href="https://community.vuetifyjs.com"
|
||||
target="_blank"
|
||||
>Discord Community</a>
|
||||
</p>
|
||||
</v-col>
|
||||
|
||||
<v-col
|
||||
class="mb-5"
|
||||
cols="12"
|
||||
>
|
||||
<h2 class="headline font-weight-bold mb-3">
|
||||
What's next?
|
||||
</h2>
|
||||
|
||||
<v-row justify="center">
|
||||
<a
|
||||
v-for="(next, i) in whatsNext"
|
||||
:key="i"
|
||||
:href="next.href"
|
||||
class="subheading mx-3"
|
||||
target="_blank"
|
||||
>
|
||||
{{ next.text }}
|
||||
</a>
|
||||
</v-row>
|
||||
</v-col>
|
||||
|
||||
<v-col
|
||||
class="mb-5"
|
||||
cols="12"
|
||||
>
|
||||
<h2 class="headline font-weight-bold mb-3">
|
||||
Important Links
|
||||
</h2>
|
||||
|
||||
<v-row justify="center">
|
||||
<a
|
||||
v-for="(link, i) in importantLinks"
|
||||
:key="i"
|
||||
:href="link.href"
|
||||
class="subheading mx-3"
|
||||
target="_blank"
|
||||
>
|
||||
{{ link.text }}
|
||||
</a>
|
||||
</v-row>
|
||||
</v-col>
|
||||
|
||||
<v-col
|
||||
class="mb-5"
|
||||
cols="12"
|
||||
>
|
||||
<h2 class="headline font-weight-bold mb-3">
|
||||
Ecosystem
|
||||
</h2>
|
||||
|
||||
<v-row justify="center">
|
||||
<a
|
||||
v-for="(eco, i) in ecosystem"
|
||||
:key="i"
|
||||
:href="eco.href"
|
||||
class="subheading mx-3"
|
||||
target="_blank"
|
||||
>
|
||||
{{ eco.text }}
|
||||
</a>
|
||||
</v-row>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'HelloWorld',
|
||||
props: {
|
||||
msg: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
count: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data: () => ({
|
||||
ecosystem: [
|
||||
{
|
||||
text: 'vuetify-loader',
|
||||
href: 'https://github.com/vuetifyjs/vuetify-loader'
|
||||
},
|
||||
{
|
||||
text: 'github',
|
||||
href: 'https://github.com/vuetifyjs/vuetify'
|
||||
},
|
||||
{
|
||||
text: 'awesome-vuetify',
|
||||
href: 'https://github.com/vuetifyjs/awesome-vuetify'
|
||||
}
|
||||
],
|
||||
importantLinks: [
|
||||
{
|
||||
text: 'Documentation',
|
||||
href: 'https://vuetifyjs.com'
|
||||
},
|
||||
{
|
||||
text: 'Chat',
|
||||
href: 'https://community.vuetifyjs.com'
|
||||
},
|
||||
{
|
||||
text: 'Made with Vuetify',
|
||||
href: 'https://madewithvuejs.com/vuetify'
|
||||
},
|
||||
{
|
||||
text: 'Twitter',
|
||||
href: 'https://twitter.com/vuetifyjs'
|
||||
},
|
||||
{
|
||||
text: 'Articles',
|
||||
href: 'https://medium.com/vuetify'
|
||||
}
|
||||
],
|
||||
whatsNext: [
|
||||
{
|
||||
text: 'Explore components',
|
||||
href: 'https://vuetifyjs.com/components/api-explorer'
|
||||
},
|
||||
{
|
||||
text: 'Select a layout',
|
||||
href: 'https://vuetifyjs.com/getting-started/pre-made-layouts'
|
||||
},
|
||||
{
|
||||
text: 'Frequently Asked Questions',
|
||||
href: 'https://vuetifyjs.com/getting-started/frequently-asked-questions'
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
const d3Force = require('d3-force')
|
||||
|
||||
const forceLayout = {
|
||||
tick: () => {
|
||||
},
|
||||
center: [0, 0],
|
||||
nodeStrength: null,
|
||||
edgeStrength: null,
|
||||
preventOverlap: false,
|
||||
nodeSize: undefined,
|
||||
nodeSpacing: undefined,
|
||||
linkDistance: 50,
|
||||
forceSimulation: null,
|
||||
alphaDecay: 0.028,
|
||||
alphaMin: 0.001,
|
||||
alpha: 0.3,
|
||||
collideStrength: 1,
|
||||
onLayoutEnd: function () {
|
||||
},
|
||||
getDefaultCfg() {
|
||||
return {
|
||||
center: [0, 0],
|
||||
nodeStrength: null,
|
||||
edgeStrength: null,
|
||||
preventOverlap: false,
|
||||
nodeSize: undefined,
|
||||
nodeSpacing: undefined,
|
||||
linkDistance: 50,
|
||||
forceSimulation: null,
|
||||
alphaDecay: 0.028,
|
||||
alphaMin: 0.001,
|
||||
alpha: 0.3,
|
||||
collideStrength: 1,
|
||||
onLayoutEnd: function () {
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 初始化
|
||||
* @param {Object} data 数据
|
||||
*/
|
||||
init(data) {
|
||||
console.log('init')
|
||||
const self = this
|
||||
self.nodes = data.nodes || []
|
||||
const edges = data.edges || []
|
||||
self.edges = edges.map(function (edge) {
|
||||
const res = {}
|
||||
const expectKeys = ['targetNode', 'sourceNode', 'startPoint', 'endPoint']
|
||||
Object.keys(edge).forEach(function (key) {
|
||||
if (!(expectKeys.indexOf(key) > -1)) {
|
||||
res[key] = edge[key]
|
||||
}
|
||||
})
|
||||
return res
|
||||
})
|
||||
self.ticking = false
|
||||
},
|
||||
/**
|
||||
* 执行布局
|
||||
*/
|
||||
execute(reloadData: any) {
|
||||
console.log('execute')
|
||||
const self = this
|
||||
const nodes = self.nodes
|
||||
const edges = self.edges
|
||||
// 如果正在布局,忽略布局请求
|
||||
if (self.ticking) {
|
||||
return
|
||||
}
|
||||
let simulation = self.forceSimulation
|
||||
const alphaMin = self.alphaMin
|
||||
const alphaDecay = self.alphaDecay
|
||||
const alpha = self.alpha
|
||||
if (!simulation) {
|
||||
try {
|
||||
// 定义节点的力
|
||||
const nodeForce = d3Force.forceManyBody()
|
||||
if (self.nodeStrength) {
|
||||
nodeForce.strength(self.nodeStrength)
|
||||
}
|
||||
simulation = d3Force.forceSimulation().nodes(nodes)
|
||||
simulation
|
||||
.force('center', d3Force.forceCenter(self.center[0], self.center[1]))
|
||||
.force('charge', nodeForce)
|
||||
.alpha(alpha)
|
||||
.alphaDecay(alphaDecay)
|
||||
.alphaMin(alphaMin)
|
||||
if (self.preventOverlap) {
|
||||
self.overlapProcess(simulation)
|
||||
}
|
||||
// 如果有边,定义边的力
|
||||
if (edges) {
|
||||
// d3 的 forceLayout 会重新生成边的数据模型,为了避免污染源数据
|
||||
const edgeForce = d3Force
|
||||
.forceLink()
|
||||
.id(function (d) {
|
||||
return d.id
|
||||
})
|
||||
.links(edges)
|
||||
if (self.edgeStrength) {
|
||||
edgeForce.strength(self.edgeStrength)
|
||||
}
|
||||
if (self.linkDistance) {
|
||||
edgeForce.distance(self.linkDistance)
|
||||
}
|
||||
self.edgeForce = edgeForce
|
||||
simulation.force('link', edgeForce)
|
||||
}
|
||||
simulation
|
||||
.on('tick', function () {
|
||||
self.tick()
|
||||
})
|
||||
.on('end', function () {
|
||||
self.ticking = false
|
||||
if (self.onLayoutEnd) {
|
||||
self.onLayoutEnd()
|
||||
}
|
||||
})
|
||||
self.ticking = true
|
||||
self.forceSimulation = simulation
|
||||
self.ticking = true
|
||||
} catch (e) {
|
||||
self.ticking = false
|
||||
console.warn(e)
|
||||
}
|
||||
} else {
|
||||
if (reloadData) {
|
||||
simulation.nodes(nodes)
|
||||
if (edges && self.edgeForce) {
|
||||
self.edgeForce.links(edges)
|
||||
} else if (edges && !self.edgeForce) {
|
||||
// d3 的 forceLayout 会重新生成边的数据模型,为了避免污染源数据
|
||||
const edgeForce = d3Force
|
||||
.forceLink()
|
||||
.id(function (d) {
|
||||
return d.id
|
||||
})
|
||||
.links(edges)
|
||||
if (self.edgeStrength) {
|
||||
edgeForce.strength(self.edgeStrength)
|
||||
}
|
||||
if (self.linkDistance) {
|
||||
edgeForce.distance(self.linkDistance)
|
||||
}
|
||||
self.edgeForce = edgeForce
|
||||
simulation.force('link', edgeForce)
|
||||
}
|
||||
}
|
||||
if (self.preventOverlap) {
|
||||
self.overlapProcess(simulation)
|
||||
}
|
||||
simulation.alpha(alpha).restart()
|
||||
this.ticking = true
|
||||
}
|
||||
// TODO
|
||||
},
|
||||
/**
|
||||
* 根据传入的数据进行布局
|
||||
* @param {Object} data 数据
|
||||
*/
|
||||
layout(data) {
|
||||
console.log('layout')
|
||||
this.init(data)
|
||||
this.execute()
|
||||
},
|
||||
/**
|
||||
* 更新布局配置,但不执行布局
|
||||
* @param {Object} cfg 需要更新的配置项
|
||||
*/
|
||||
updateCfg(cfg) {
|
||||
console.log('update cfg')
|
||||
const self = this
|
||||
if (self.ticking) {
|
||||
self.forceSimulation.stop()
|
||||
self.ticking = false
|
||||
}
|
||||
self.forceSimulation = null
|
||||
Object.assign(self, cfg)
|
||||
},
|
||||
/**
|
||||
* 销毁
|
||||
*/
|
||||
destroy() {
|
||||
console.log('destroy')
|
||||
}
|
||||
}
|
||||
|
||||
export default forceLayout
|
||||
@@ -0,0 +1,6 @@
|
||||
import G6 from '@antv/g6'
|
||||
import forceLayout from '@/g6/force'
|
||||
|
||||
G6.registerLayout('forceLayout', forceLayout)
|
||||
|
||||
export default G6
|
||||
@@ -1,8 +0,0 @@
|
||||
#app {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
function multiply(a, b) {
|
||||
// 相乘约束
|
||||
if (a[0].length !== b.length) {
|
||||
throw new Error()
|
||||
}
|
||||
let m = a.length
|
||||
let p = a[0].length
|
||||
let n = b[0].length
|
||||
|
||||
// 初始化 m*n 全 0 二维数组
|
||||
let c = new Array(m).fill(0).map(arr => new Array(n).fill(0))
|
||||
|
||||
for (let i = 0; i < m; i++) {
|
||||
for (let j = 0; j < n; j++) {
|
||||
for (let k = 0; k < p; k++) {
|
||||
c[i][j] += a[i][k] * b[k][j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
function det(square) {
|
||||
// 方阵约束
|
||||
if (square.length !== square[0].length) {
|
||||
throw new Error()
|
||||
}
|
||||
// 方阵阶数
|
||||
let n = square.length
|
||||
|
||||
let result = 0
|
||||
if (n > 3) {
|
||||
// n 阶
|
||||
for (let column = 0; column < n; column++) {
|
||||
// 去掉第 0 行第 column 列的矩阵
|
||||
let matrix = new Array(n - 1).fill(0).map(arr => new Array(n - 1).fill(0))
|
||||
for (let i = 0; i < n - 1; i++) {
|
||||
for (let j = 0; j < n - 1; j++) {
|
||||
if (j < column) {
|
||||
matrix[i][j] = square[i + 1][j]
|
||||
} else {
|
||||
matrix[i][j] = square[i + 1][j + 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
result += square[0][column] * Math.pow(-1, 0 + column) * det(matrix)
|
||||
}
|
||||
} else if (n === 3) {
|
||||
// 3 阶
|
||||
result = square[0][0] * square[1][1] * square[2][2] +
|
||||
square[0][1] * square[1][2] * square[2][0] +
|
||||
square[0][2] * square[1][0] * square[2][1] -
|
||||
square[0][2] * square[1][1] * square[2][0] -
|
||||
square[0][1] * square[1][0] * square[2][2] -
|
||||
square[0][0] * square[1][2] * square[2][1]
|
||||
} else if (n === 2) {
|
||||
// 2 阶
|
||||
result = square[0][0] * square[1][1] - square[0][1] * square[1][0]
|
||||
} else if (n === 1) {
|
||||
// 1 阶
|
||||
result = square[0][0]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function transpose(matrix) {
|
||||
let result = new Array(matrix.length).fill(0).map(arr => new Array(matrix[0].length).fill(0))
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
for (let j = 0; j < result[0].length; j++) {
|
||||
result[i][j] = matrix[j][i]
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function adjoint(square) {
|
||||
// 方阵约束
|
||||
if (square[0].length !== square.length) {
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
let n = square.length
|
||||
|
||||
let result = new Array(n).fill(0).map(arr => new Array(n).fill(0))
|
||||
for (let row = 0; row < n; row++) {
|
||||
for (let column = 0; column < n; column++) {
|
||||
// 去掉第 row 行第 column 列的矩阵
|
||||
let matrix = []
|
||||
for (let i = 0; i < square.length; i++) {
|
||||
if (i !== row) {
|
||||
let arr = []
|
||||
for (let j = 0; j < square.length; j++) {
|
||||
if (j !== column) {
|
||||
arr.push(square[i][j])
|
||||
}
|
||||
}
|
||||
matrix.push(arr)
|
||||
}
|
||||
}
|
||||
result[row][column] = Math.pow(-1, row + column) * det(matrix)
|
||||
}
|
||||
}
|
||||
return transpose(result)
|
||||
}
|
||||
|
||||
function inv(square) {
|
||||
if (square[0].length !== square.length) {
|
||||
throw new Error()
|
||||
}
|
||||
let detValue = det(square)
|
||||
let result = adjoint(square)
|
||||
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
for (let j = 0; j < result.length; j++) {
|
||||
result[i][j] /= detValue
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function copyM(m, xs, xe, ys, ye) {
|
||||
let n = []
|
||||
for (let i = xs; i < xe; i++) {
|
||||
n.push([])
|
||||
for (let j = ys; j < ye; j++) {
|
||||
n[i - xs].push(m[i][j])
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
export { inv, multiply, copyM }
|
||||
@@ -1,5 +0,0 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import './index.css'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
@@ -0,0 +1,14 @@
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import vuetify from './plugins/vuetify'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
vuetify,
|
||||
render: h => h(App)
|
||||
}).$mount('#app')
|
||||
@@ -0,0 +1,7 @@
|
||||
import Vue from 'vue'
|
||||
import Vuetify from 'vuetify/lib/framework'
|
||||
|
||||
Vue.use(Vuetify)
|
||||
|
||||
export default new Vuetify({
|
||||
})
|
||||
@@ -0,0 +1,27 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter, { RouteConfig } from 'vue-router'
|
||||
import Home from '../views/Home.vue'
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
const routes: Array<RouteConfig> = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: Home
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
name: 'About',
|
||||
// route level code-splitting
|
||||
// this generates a separate chunk (about.[hash].js) for this route
|
||||
// which is lazy-loaded when the route is visited.
|
||||
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
|
||||
}
|
||||
]
|
||||
|
||||
const router = new VueRouter({
|
||||
routes
|
||||
})
|
||||
|
||||
export default router
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
import Vue, { VNode } from 'vue'
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
// tslint:disable no-empty-interface
|
||||
interface Element extends VNode {}
|
||||
// tslint:disable no-empty-interface
|
||||
interface ElementClass extends Vue {}
|
||||
interface IntrinsicElements {
|
||||
[elem: string]: any;
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
declare module '*.vue' {
|
||||
import Vue from 'vue'
|
||||
export default Vue
|
||||
}
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
declare module 'vuetify/lib/framework' {
|
||||
import Vuetify from 'vuetify'
|
||||
export default Vuetify
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
state: {
|
||||
algorithm: 1,
|
||||
algorithms: [
|
||||
{value: 0, text: '二次线长布局'},
|
||||
{value: 1, text: '力矢量布局'}
|
||||
],
|
||||
nodes: [],
|
||||
edges: {},
|
||||
nodesNum: 5,
|
||||
edgesNum: 4
|
||||
},
|
||||
mutations: {},
|
||||
actions: {},
|
||||
modules: {}
|
||||
})
|
||||
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div class="about">
|
||||
<h1>This is an about page</h1>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<div class="home" id="container">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import G6 from './../g6'
|
||||
import {multiply, inv, copyM} from '@/libs'
|
||||
|
||||
const modes = {
|
||||
default: ['drag-canvas', 'zoom-canvas', 'brush-select']
|
||||
}
|
||||
|
||||
function refreshDragedNodePosition(e: any) {
|
||||
const model = e.item.get('model')
|
||||
model.x = e.x
|
||||
model.y = e.y
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'Home',
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
graph: G6.Graph,
|
||||
cfg: {
|
||||
container: 'container',
|
||||
modes: modes,
|
||||
defaultNode: {
|
||||
size: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
mode() {
|
||||
return this.$store.state.algorithm
|
||||
},
|
||||
nodes() {
|
||||
return Object.keys(this.$store.state.nodes).map(v => {
|
||||
return this.$store.state.nodes[v]
|
||||
})
|
||||
},
|
||||
edges() {
|
||||
return Object.keys(this.$store.state.edges).map(v => this.$store.state.edges[v])
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
mode() {
|
||||
this.graph.destroy()
|
||||
this.init()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
lay2() {
|
||||
const p = []
|
||||
const l = []
|
||||
let fnum = 0
|
||||
this.nodes.forEach(v => {
|
||||
l.push([])
|
||||
this.nodes.forEach(() => {
|
||||
l[l.length - 1].push(0)
|
||||
})
|
||||
if (v.color === 'red') {
|
||||
fnum = fnum + 1
|
||||
p.push([v.x, v.y])
|
||||
}
|
||||
})
|
||||
if (fnum === 0) {
|
||||
alert('请固定至少一个点')
|
||||
return
|
||||
}
|
||||
this.nodes.forEach(v => {
|
||||
if (v.color !== 'red') {
|
||||
p.push([0, 0])
|
||||
}
|
||||
})
|
||||
this.edges.forEach(v => {
|
||||
const s = Number(v.source.slice(1))
|
||||
const e = Number(v.target.slice(1))
|
||||
l[s][e] = 1
|
||||
l[e][s] = 1
|
||||
})
|
||||
const ones = [l.map(e => 1)]
|
||||
const onesL = multiply(ones, l)
|
||||
const B = multiply(l, p)
|
||||
const A = []
|
||||
for (let i = 0; i < p.length; i++) {
|
||||
A.push([])
|
||||
for (let j = 0; j < p.length; j++) {
|
||||
A[i].push(0)
|
||||
if (i === j) {
|
||||
A[i][j] = onesL[0][i]
|
||||
}
|
||||
A[i][j] = A[i][j] - l[i][j]
|
||||
}
|
||||
}
|
||||
const nA = copyM(A, fnum, A.length, fnum, A.length)
|
||||
const nB = copyM(B, fnum, A.length, 0, 2)
|
||||
const res = multiply(inv(nA), nB)
|
||||
let index = 0
|
||||
console.log(res)
|
||||
this.nodes.forEach(v => {
|
||||
if (v.color !== 'red') {
|
||||
v.x = res[index][0]
|
||||
v.y = res[index][1]
|
||||
this.graph.updateItem(v.id, {x: v.x, y: v.y})
|
||||
index = index + 1
|
||||
}
|
||||
})
|
||||
},
|
||||
init() {
|
||||
const container = document.getElementById('container')
|
||||
this.cfg.width = container.scrollWidth
|
||||
this.cfg.height = container.scrollHeight || 500
|
||||
this.cfg.layout = this.mode === 1 ? {
|
||||
type: 'force',
|
||||
center: [this.cfg.width / 2, this.cfg.height / 2],
|
||||
preventOverlap: true,
|
||||
onTick: (e) => {
|
||||
},
|
||||
onLayoutEnd: () => {
|
||||
},
|
||||
workerEnabled: false
|
||||
} : undefined
|
||||
const graph = new G6.Graph(this.cfg)
|
||||
this.graph = graph
|
||||
this.loaddata()
|
||||
if (this.mode !== 1) {
|
||||
graph.on('node:drag', e => {
|
||||
if (e.item?.getModel().color === 'red') {
|
||||
return
|
||||
}
|
||||
refreshDragedNodePosition(e)
|
||||
graph.refresh()
|
||||
})
|
||||
return
|
||||
}
|
||||
const forceLayout = graph.get('layoutController').layoutMethod
|
||||
const start = (e) => {
|
||||
graph.layout()
|
||||
refreshDragedNodePosition(e)
|
||||
}
|
||||
const move = (e) => {
|
||||
forceLayout.execute()
|
||||
refreshDragedNodePosition(e)
|
||||
}
|
||||
const end = (e) => {
|
||||
// e.item.get('model').fx = null
|
||||
// e.item.get('model').fy = null
|
||||
}
|
||||
graph.on('node:dragstart', start)
|
||||
graph.on('node:drag', move)
|
||||
graph.on('node:dragend', end)
|
||||
graph.on('node:touchstart', start)
|
||||
graph.on('node:touchmove', move)
|
||||
graph.on('node:touchend', end)
|
||||
},
|
||||
loaddata() {
|
||||
this.graph.data({
|
||||
nodes: this.nodes,
|
||||
edges: this.edges
|
||||
})
|
||||
this.graph.render()
|
||||
// this.graph.fitView(20)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"importHelpers": true,
|
||||
"moduleResolution": "node",
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"types": [
|
||||
"webpack-env"
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"tests/**/*.ts",
|
||||
"tests/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
transpileDependencies: [
|
||||
'vuetify'
|
||||
]
|
||||
}
|
||||
+8685
-1163
File diff suppressed because it is too large
Load Diff
@@ -56,5 +56,8 @@ end
|
||||
作业提交有效时间是今天到10月23日(两周后)之前的任意时间。提交作业请将代码和报告打包,以“课后作业1-名字-学号”命名提交。
|
||||
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
@@ -0,0 +1,184 @@
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import time
|
||||
|
||||
|
||||
def LU_decomposition(A):
|
||||
n = len(A[0])
|
||||
L = np.zeros([n, n])
|
||||
U = np.zeros([n, n])
|
||||
for i in range(n):
|
||||
L[i][i] = 1
|
||||
if i == 0:
|
||||
U[0][0] = A[0][0]
|
||||
for j in range(1, n):
|
||||
U[0][j] = A[0][j]
|
||||
L[j][0] = A[j][0] / U[0][0]
|
||||
else:
|
||||
for j in range(i, n): # U
|
||||
temp = 0
|
||||
for k in range(0, i):
|
||||
temp = temp + L[i][k] * U[k][j]
|
||||
U[i][j] = A[i][j] - temp
|
||||
for j in range(i + 1, n): # L
|
||||
temp = 0
|
||||
for k in range(0, i):
|
||||
temp = temp + L[j][k] * U[k][i]
|
||||
L[j][i] = (A[j][i] - temp) / U[i][i]
|
||||
return L, U
|
||||
|
||||
|
||||
# 生成随机矩阵 A, b, 范围[-10, 10]
|
||||
def randomAb(m):
|
||||
A = np.random.random([m, m]) * 20 - 10
|
||||
dia = np.random.random(m) * 10
|
||||
for i in range(len(dia)):
|
||||
A[i, i] = dia[i]
|
||||
return A, np.random.randint(0, 10, [m, 1])
|
||||
|
||||
|
||||
# 生成稀疏矩阵A, b
|
||||
def sparseMatrix(m):
|
||||
A, b = randomAb(m)
|
||||
for i in range(m):
|
||||
for j in range(m):
|
||||
if i != j:
|
||||
a = A[i][j]
|
||||
if abs(a) < 9:
|
||||
A[i][j] = 0
|
||||
elif a > 0:
|
||||
A[i][j] = 10 * (a - 9)
|
||||
else:
|
||||
A[i][j] = 10 * (9 + a)
|
||||
|
||||
return A, b
|
||||
|
||||
|
||||
# 生成病态矩阵A, b
|
||||
def illMatrix(m):
|
||||
A, b = randomAb(m)
|
||||
return A, b
|
||||
|
||||
|
||||
class Question1:
|
||||
"""
|
||||
求解 Ax=b
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def solver1(self, A, b):
|
||||
"""
|
||||
LU 分解 求解器
|
||||
"""
|
||||
L, U = LU_decomposition(A)
|
||||
# LY=b
|
||||
n = len(A)
|
||||
y = np.zeros((n, 1))
|
||||
for i in range(len(A)):
|
||||
t = 0
|
||||
for j in range(i):
|
||||
t += L[i][j] * y[j][0]
|
||||
y[i][0] = b[i][0] - t
|
||||
X = np.zeros((n, 1))
|
||||
for i in range(len(A) - 1, -1, -1):
|
||||
t = 0
|
||||
for j in range(i + 1, len(A)):
|
||||
t += U[i][j] * X[j][0]
|
||||
t = y[i][0] - t
|
||||
if t != 0 and U[i][i] == 0:
|
||||
return 0
|
||||
X[i] = t / U[i][i]
|
||||
return X
|
||||
|
||||
def solver2(self, A, b):
|
||||
"""
|
||||
Jacobi 求解器
|
||||
"""
|
||||
x = np.zeros(b.shape)
|
||||
Dv = np.diag(A)
|
||||
D = np.zeros(A.shape)
|
||||
for i in range(len(Dv)):
|
||||
D[i, i] = Dv[i]
|
||||
R = A - np.diagflat(Dv)
|
||||
|
||||
# Iterate for N times
|
||||
print(D)
|
||||
D = np.linalg.inv(D)
|
||||
print(D)
|
||||
while 1:
|
||||
x1 = D @ (b - R @ x)
|
||||
if np.max(x1 - x) < 1e-6:
|
||||
break
|
||||
x = x1
|
||||
return x
|
||||
# return Jacobi(np.zeros(b.shape), A, b)
|
||||
|
||||
def solver3(self, A, b):
|
||||
"""
|
||||
inv(A) * b
|
||||
"""
|
||||
return np.dot(np.linalg.inv(A), b)
|
||||
|
||||
def solver4(self, A, b):
|
||||
"""
|
||||
默认求解器
|
||||
"""
|
||||
return np.linalg.solve(A, b)
|
||||
|
||||
def RMSE(self, solver, n=8, randFunc=randomAb):
|
||||
## 计算方差
|
||||
s = time.time()
|
||||
A, b = randFunc(n)
|
||||
X = (A.dot(solver(A, b)) - b) ** 2
|
||||
for i in range(1000):
|
||||
A, b = randFunc(n)
|
||||
X = X + (A.dot(solver(A, b)) - b) ** 2
|
||||
return np.max(X), time.time() - s
|
||||
|
||||
def show(self):
|
||||
n = 12
|
||||
N = [2 ** i for i in range(n)]
|
||||
Y = [[0 for i in range(n)] for _ in range(4)]
|
||||
Z = [[0 for i in range(n)] for _ in range(4)]
|
||||
|
||||
randomFuns = [randomAb, sparseMatrix, illMatrix]
|
||||
for r in range(3):
|
||||
plt.subplot(3, 2, 2*r + 1)
|
||||
for i in range(n):
|
||||
print("size: %s" % N[i])
|
||||
print("LU")
|
||||
Y[0][i], Z[0][i] = self.RMSE(self.solver1, N[i])
|
||||
print("jacobi")
|
||||
Y[1][i], Z[1][i] = self.RMSE(self.solver3, N[i])
|
||||
print("inverse")
|
||||
Y[2][i], Z[2][i] = self.RMSE(self.solver3, N[i])
|
||||
print("default\n")
|
||||
Y[3][i], Z[3][i] = self.RMSE(self.solver4, N[i])
|
||||
|
||||
# N = range(12)
|
||||
plt.plot(N, Y[0], label="LU")
|
||||
plt.plot(N, Y[1], label="Jacobi")
|
||||
plt.plot(N, Y[2], label="inverse")
|
||||
plt.plot(N, Y[3], label="default solver")
|
||||
# plt.xticks([0, 10, 100, 1000], [0, 10, 100, 1000])
|
||||
plt.title('Accuracy')
|
||||
plt.yscale('symlog')
|
||||
plt.xscale('symlog')
|
||||
# plt.legend(loc='lower right')
|
||||
plt.subplot(3, 2, 2 * r + 2)
|
||||
plt.plot(N, Z[0], label="LU")
|
||||
plt.plot(N, Z[1], label="Jacobi")
|
||||
plt.plot(N, Z[2], label="inverse")
|
||||
plt.plot(N, Z[3], label="default solver")
|
||||
plt.xscale('symlog')
|
||||
plt.yscale('symlog')
|
||||
plt.title('time cost')
|
||||
# plt.legend(loc='lower right')
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
q = Question1()
|
||||
q.show()
|
||||
@@ -0,0 +1,17 @@
|
||||
# 结论
|
||||
|
||||
图例
|
||||
|
||||
0 - 标准函数
|
||||
1 - 复化梯形公式
|
||||
2 - 复化Simpson 1/3
|
||||
3 - 复化Simpson 3/8
|
||||
|
||||
随积分区间变化图
|
||||
|
||||

|
||||
|
||||
|
||||
随N变化图
|
||||
|
||||

|
||||
@@ -0,0 +1,90 @@
|
||||
import math
|
||||
from scipy import integrate
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
def erf_inner(x):
|
||||
return math.e ** (- x ** 2)
|
||||
|
||||
|
||||
def solve0(a, b, N):
|
||||
"""
|
||||
标准函数求积分
|
||||
"""
|
||||
return integrate.quad(erf_inner, a, b)[0]
|
||||
|
||||
|
||||
def solve1(a, b, N):
|
||||
"""
|
||||
复化梯形积分公式
|
||||
"""
|
||||
h = (b - a) / N
|
||||
s = erf_inner(a)
|
||||
for i in range(1, N):
|
||||
s += 2 * erf_inner(a + h * i)
|
||||
s += erf_inner(b)
|
||||
return s * h / 2
|
||||
|
||||
|
||||
def solve2(a, b, N):
|
||||
"""
|
||||
复化Simpson 1/3
|
||||
"""
|
||||
h = (b - a) / N
|
||||
s = 0
|
||||
s = erf_inner(a)
|
||||
for i in range(1, N):
|
||||
s += 2 * erf_inner(a + h * i)
|
||||
for i in range(0, N):
|
||||
s += 4 * erf_inner(a + h * (i + 0.5))
|
||||
s += erf_inner(b)
|
||||
return s * h / 6
|
||||
|
||||
|
||||
def solve3(a, b, N):
|
||||
"""
|
||||
复化Simpson 3/8
|
||||
"""
|
||||
h = (b - a) / N
|
||||
s = 0
|
||||
s = 7 * erf_inner(a)
|
||||
for i in range(1, N):
|
||||
s += 32 * erf_inner(a + h * (i - 0.75)) + 12 * erf_inner(a + h * (i - 0.5)) + 32 * erf_inner(
|
||||
a + h * (i - 0.25)) + 14 * erf_inner(a + h * i)
|
||||
s += 7 * erf_inner(b)
|
||||
return s * h / 90
|
||||
|
||||
|
||||
def show():
|
||||
x = [i for i in range(60)]
|
||||
y = [[0 for j in range(60)] for _ in range(4)]
|
||||
solves = [solve0, solve1, solve2, solve3]
|
||||
for s in range(4):
|
||||
for i in x:
|
||||
y[s][i] = solves[s](0, i, 10)
|
||||
plt.plot(x, y[s], label=str(s))
|
||||
plt.legend(loc="lower right")
|
||||
plt.show()
|
||||
|
||||
|
||||
def showN():
|
||||
x = [i for i in range(1, 30)]
|
||||
y = [[0 for j in range(30)] for _ in range(4)]
|
||||
solves = [solve0, solve1, solve2, solve3]
|
||||
for s in range(4):
|
||||
for i in x:
|
||||
y[s][i] = solves[s](0, 10, i)
|
||||
plt.plot(x, y[s][1:], label=str(s))
|
||||
plt.legend(loc="lower right")
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# a = 0
|
||||
# b = 20
|
||||
# n = 90
|
||||
# print(solve1(a, b, n))
|
||||
# print(solve2(a, b, n))
|
||||
# print(solve3(a, b, n))
|
||||
# print(solve0(a, b, n))
|
||||
showN()
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
# 问题1
|
||||
|
||||
1:
|
||||
f = 1 / (e^(-x) + e^x)
|
||||
|
||||
2
|
||||
|
||||
标签
|
||||
|
||||
0: 默认求解器
|
||||
1: 向前差分
|
||||
2: 向后差分
|
||||
3: rk45
|
||||
|
||||

|
||||
|
||||

|
||||
@@ -0,0 +1,153 @@
|
||||
import math
|
||||
from math import e
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from scipy.integrate import odeint, solve_bvp, solve_ivp
|
||||
|
||||
|
||||
def runge_kutta(y, x, dx, f):
|
||||
""" y is the initial value for y
|
||||
x is the initial value for x
|
||||
dx is the time step in x
|
||||
f is derivative of function y(t)
|
||||
"""
|
||||
k1 = dx * f(y, x)
|
||||
k2 = dx * f(y + 0.5 * k1, x + 0.5 * dx)
|
||||
k3 = dx * f(y + 0.5 * k2, x + 0.5 * dx)
|
||||
k4 = dx * f(y + k3, x + dx)
|
||||
return y + (k1 + 2 * k2 + 2 * k3 + k4) / 6.
|
||||
|
||||
|
||||
'''
|
||||
为了兼容solve_ivp的参数形式,微分方程函数定义的参数顺序为(t,y),因此使用odeint函数时需要使参数tfirst=True
|
||||
二阶甚至高阶微分方程组都可以变量替换成一阶方程组的形式,再调用相关函数进行求解,因此编写函数的时候,不同于一阶微分方程,二阶或者高阶微分方程返回的是低阶到高阶组成的方程组,
|
||||
|
||||
'''
|
||||
|
||||
y0 = [1 / (e + 1 / e), (e - 1 / e) / ((e + 1 / e) ** 2)] # 初值条件
|
||||
|
||||
|
||||
# 初值[2,0]表示y(0)=2,y'(0)=0
|
||||
|
||||
|
||||
def fvdp1(t, y):
|
||||
'''
|
||||
要把y看出一个向量,y = [dy0,dy1,dy2,...]分别表示y的n阶导,那么
|
||||
y[0]就是需要求解的函数,y[1]表示一阶导,y[2]表示二阶导,以此类推
|
||||
对于二阶微分方程,肯定是由0阶和1阶函数组合而成的,所以下面把y看成向量的话,y0表示最初始的函数,也就是我们要求解的函数,y1表示一阶导,对于高阶微分方程也可以以此类推
|
||||
'''
|
||||
dy1 = y[1] # y[1]=dy/dt,一阶导
|
||||
# dy2 = -3 * y[1] - 2 * y[0] + np.exp(-1 * t)
|
||||
dy2 = 2 * y[1] ** 2 / y[0] - y[0]
|
||||
# y[0]是最初始,也就是需要求解的函数
|
||||
# 注意返回的顺序是[一阶导, 二阶导],这就形成了一阶微分方程组
|
||||
return [dy1, dy2]
|
||||
|
||||
|
||||
def solve0():
|
||||
'''
|
||||
内置求解器1
|
||||
'''
|
||||
t2 = np.linspace(-1, 1, 1000)
|
||||
return odeint(fvdp1, y0, t2, tfirst=True)[:, 0]
|
||||
|
||||
|
||||
def solve01(seq):
|
||||
f0 = [y0[0]]
|
||||
f1 = [y0[1]]
|
||||
f2 = [fvdp1(-1, [f0[0], f1[0]])[1]]
|
||||
for i in range(1, len(seq)):
|
||||
h = seq[i] - seq[i - 1]
|
||||
k21 = f2[i - 1]
|
||||
k22 = fvdp1(seq[i - 1] + h / 2, [f0[i - 1] + h * k21 / 2, f1[i - 1] + h * k21 / 2])[1]
|
||||
k23 = fvdp1(seq[i - 1] + h / 2, [f0[i - 1] + h * k22 / 2, f1[i - 1] + h * k22 / 2])[1]
|
||||
k24 = fvdp1(seq[i - 1] + h / 2, [f0[i - 1] + h * k23, f1[i - 1] + h * k23])[1]
|
||||
f1.append(f1[i - 1] + h * (k21 + k22 + k23 + k24) / 6)
|
||||
f0.append(f0[i - 1] + h * f1[i - 1])
|
||||
f2.append(fvdp1(seq[i], [f0[i], f1[i]])[1])
|
||||
return f0
|
||||
|
||||
|
||||
def solve1(seq):
|
||||
'''
|
||||
向前差分
|
||||
'''
|
||||
f0 = [y0[0]]
|
||||
f1 = [y0[1]]
|
||||
f2 = [fvdp1(-1, [f0[0], f1[0]])[1]]
|
||||
for i in range(1, len(seq)):
|
||||
h = seq[i] - seq[i - 1]
|
||||
f0.append(f0[i - 1] + h * f1[i - 1])
|
||||
f1.append(f1[i - 1] + h * f2[i - 1])
|
||||
f2.append(fvdp1(seq[i], [f0[i], f1[i]])[1])
|
||||
return f0
|
||||
|
||||
|
||||
def solve2(seq):
|
||||
'''
|
||||
向后差分
|
||||
'''
|
||||
f0 = [y0[0]]
|
||||
f1 = [y0[1]]
|
||||
f2 = [fvdp1(-1, [f0[0], f1[0]])[1]]
|
||||
for i in range(1, len(seq)):
|
||||
h = seq[i] - seq[i - 1]
|
||||
f2.append(fvdp1(seq[i], [f0[i - 1], f1[i - 1]])[1])
|
||||
f1.append(f1[i - 1] + h * f2[i])
|
||||
f0.append(f0[i - 1] + h * f1[i])
|
||||
return f0
|
||||
|
||||
|
||||
def runge_kutta(y, x, dx, f):
|
||||
""" y is the initial value for y
|
||||
x is the initial value for x
|
||||
dx is the time step in x
|
||||
f is derivative of function y(t)
|
||||
"""
|
||||
k1 = dx * f(y, x)
|
||||
k2 = dx * f(y + 0.5 * k1, x + 0.5 * dx)
|
||||
k3 = dx * f(y + 0.5 * k2, x + 0.5 * dx)
|
||||
k4 = dx * f(y + k3, x + dx)
|
||||
return y + (k1 + 2 * k2 + 2 * k3 + k4) / 6.
|
||||
|
||||
|
||||
def solve3(seq):
|
||||
'''
|
||||
rk4
|
||||
'''
|
||||
return solve_ivp(fvdp1, t_span=(-1, 1.0), y0=y0, t_eval=seq).y.T[:, 0]
|
||||
|
||||
|
||||
def show():
|
||||
t0 = np.linspace(-1, 1, 1000)
|
||||
r0 = solve0()
|
||||
t1 = np.linspace(-1, 1, 6)
|
||||
r1 = solve1(t1)
|
||||
t2 = np.linspace(-1, 1, 6)
|
||||
r2 = solve2(t2)
|
||||
t3 = np.linspace(-1, 1, 6)
|
||||
r3 = solve3(t3)
|
||||
plt.plot(t0, r0, label='0')
|
||||
plt.plot(t1, r1, label='1')
|
||||
plt.plot(t2, r2, label='2')
|
||||
plt.plot(t3, r3, label='3')
|
||||
plt.legend()
|
||||
plt.show()
|
||||
|
||||
|
||||
def showN():
|
||||
t0 = np.linspace(-1, 1, 1000)
|
||||
r0 = solve0()
|
||||
plt.plot(t0, r0, label='0: N = 1000')
|
||||
solves = [solve1, solve2, solve3]
|
||||
for j in range(3):
|
||||
for i in range(1, 5):
|
||||
n = 2 ** i
|
||||
t = np.linspace(-1, 1, n + 1)
|
||||
plt.plot(t, solves[j](t), label='%s:N=%s' % (j, n))
|
||||
plt.legend()
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
showN()
|
||||
@@ -0,0 +1,5 @@
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import math
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from matplotlib.ticker import LinearLocator
|
||||
|
||||
|
||||
def f1(x):
|
||||
return 2 * math.sin(x) - x ** 2 / 10
|
||||
|
||||
|
||||
def showf1():
|
||||
t = np.linspace(0, 4, 1000)
|
||||
plt.plot(t, [f1(x) for x in t])
|
||||
plt.show()
|
||||
|
||||
|
||||
def f2(x, y):
|
||||
return (1 - x) ** 2 + 100 * (y - x ** 2) ** 2
|
||||
|
||||
|
||||
def f3(x, y):
|
||||
return (1.5 - x + x * y) ** 2 + (2.25 - x + x * y ** 2) ** 2 + (2.625 - x + x * y ** 3) ** 2
|
||||
|
||||
|
||||
def showf2():
|
||||
fig = plt.figure(figsize=plt.figaspect(1.))
|
||||
ax = fig.add_subplot(1, 1, 1, projection='3d')
|
||||
X = np.arange(-1, 1, 0.05)
|
||||
Y = np.arange(-1, 1, 0.05)
|
||||
X, Y = np.meshgrid(X, Y)
|
||||
# R = np.sqrt(X ** 2 + Y ** 2)
|
||||
Z = f2(X, Y)
|
||||
# Z = np.sin(R)
|
||||
|
||||
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
|
||||
cmap=plt.cm.YlGnBu_r,
|
||||
linewidth=0, antialiased=False)
|
||||
fig.colorbar(surf, shrink=0.5, aspect=5)
|
||||
plt.show()
|
||||
|
||||
|
||||
def showf3():
|
||||
fig = plt.figure(figsize=plt.figaspect(1.))
|
||||
ax = fig.add_subplot(1, 1, 1, projection='3d')
|
||||
X = np.arange(-5, 5, 0.25)
|
||||
Y = np.arange(-5, 5, 0.25)
|
||||
X, Y = np.meshgrid(X, Y)
|
||||
# R = np.sqrt(X ** 2 + Y ** 2)
|
||||
Z = f3(X, Y)
|
||||
# Z = np.sin(R)
|
||||
|
||||
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
|
||||
cmap=plt.cm.YlGnBu_r,
|
||||
linewidth=0, antialiased=False)
|
||||
fig.colorbar(surf, shrink=0.5, aspect=5)
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
showf3()
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||

|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import math
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import random
|
||||
from sklearn.linear_model import LinearRegression, Ridge, RidgeCV
|
||||
from sklearn.preprocessing import PolynomialFeatures
|
||||
|
||||
|
||||
def f1(x, e):
|
||||
return math.exp(-x) * math.sin(x) \
|
||||
+ random.normalvariate(0, e)
|
||||
|
||||
|
||||
def f2(x, y, e):
|
||||
return math.exp(-x ** 2 - y ** 2) * math.sin(x * y) + random.normalvariate(0, e)
|
||||
|
||||
|
||||
def solve1(x, y):
|
||||
return LinearRegression().fit(x, y)
|
||||
|
||||
|
||||
def solve2(x, y):
|
||||
poly = PolynomialFeatures(degree=4)
|
||||
X_poly = poly.fit_transform(x)
|
||||
poly.fit(X_poly, y)
|
||||
return poly
|
||||
|
||||
|
||||
def solve3(x, y):
|
||||
model = RidgeCV(alphas=[0.1, 1.0, 10.0]) # 通过RidgeCV可以设置多个参数值,算法使用交叉验证获取最佳参数值
|
||||
model.fit(x, y)
|
||||
return model
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
x = np.linspace(0, 10, 100)
|
||||
data = [f1(i, 1) for i in x]
|
||||
y1 = []
|
||||
model = solve3(x.reshape((-1, 1)), data)
|
||||
for i in x:
|
||||
y1.append(model.predict([[i]])[0])
|
||||
print(model.predict([[1]]))
|
||||
plt.plot(x, data, label='0')
|
||||
plt.plot(x, y1, label='1')
|
||||
plt.legend()
|
||||
plt.show()
|
||||
@@ -108,6 +108,6 @@ class WinePredict:
|
||||
if __name__ == '__main__':
|
||||
wp = WinePredict()
|
||||
wp.gs_rfc()
|
||||
for i in [wp.rfc, wp.lr, wp.svc, wp.sgd, wp.mlp][:1]:
|
||||
for i in [wp.rfc, wp.lr, wp.svc, wp.sgd, wp.mlp]:
|
||||
wp.report(i)
|
||||
# wp.showXY()
|
||||
|
||||
Reference in New Issue
Block a user